diff options
Diffstat (limited to 'src/gui/widgets/qtextbrowser.cpp')
-rw-r--r-- | src/gui/widgets/qtextbrowser.cpp | 1275 |
1 files changed, 0 insertions, 1275 deletions
diff --git a/src/gui/widgets/qtextbrowser.cpp b/src/gui/widgets/qtextbrowser.cpp deleted file mode 100644 index 2c1fb285c4..0000000000 --- a/src/gui/widgets/qtextbrowser.cpp +++ /dev/null @@ -1,1275 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtextbrowser.h" -#include "qtextedit_p.h" - -#ifndef QT_NO_TEXTBROWSER - -#include <qstack.h> -#include <qapplication.h> -#include <qevent.h> -#include <qdesktopwidget.h> -#include <qdebug.h> -#include <qabstracttextdocumentlayout.h> -#include "private/qtextdocumentlayout_p.h" -#include <qtextcodec.h> -#include <qpainter.h> -#include <qdir.h> -#include <qwhatsthis.h> -#include <qtextobject.h> -#include <qdesktopservices.h> - -QT_BEGIN_NAMESPACE - -class QTextBrowserPrivate : public QTextEditPrivate -{ - Q_DECLARE_PUBLIC(QTextBrowser) -public: - inline QTextBrowserPrivate() - : textOrSourceChanged(false), forceLoadOnSourceChange(false), openExternalLinks(false), - openLinks(true) -#ifdef QT_KEYPAD_NAVIGATION - , lastKeypadScrollValue(-1) -#endif - {} - - void init(); - - struct HistoryEntry { - inline HistoryEntry() - : hpos(0), vpos(0), focusIndicatorPosition(-1), - focusIndicatorAnchor(-1) {} - QUrl url; - QString title; - int hpos; - int vpos; - int focusIndicatorPosition, focusIndicatorAnchor; - }; - - HistoryEntry history(int i) const - { - if (i <= 0) - if (-i < stack.count()) - return stack[stack.count()+i-1]; - else - return HistoryEntry(); - else - if (i <= forwardStack.count()) - return forwardStack[forwardStack.count()-i]; - else - return HistoryEntry(); - } - - - HistoryEntry createHistoryEntry() const; - void restoreHistoryEntry(const HistoryEntry entry); - - QStack<HistoryEntry> stack; - QStack<HistoryEntry> forwardStack; - QUrl home; - QUrl currentURL; - - QStringList searchPaths; - - /*flag necessary to give the linkClicked() signal some meaningful - semantics when somebody connected to it calls setText() or - setSource() */ - bool textOrSourceChanged; - bool forceLoadOnSourceChange; - - bool openExternalLinks; - bool openLinks; - -#ifndef QT_NO_CURSOR - QCursor oldCursor; -#endif - - QString findFile(const QUrl &name) const; - - inline void _q_documentModified() - { - textOrSourceChanged = true; - forceLoadOnSourceChange = !currentURL.path().isEmpty(); - } - - void _q_activateAnchor(const QString &href); - void _q_highlightLink(const QString &href); - - void setSource(const QUrl &url); - - // re-imlemented from QTextEditPrivate - virtual QUrl resolveUrl(const QUrl &url) const; - inline QUrl resolveUrl(const QString &url) const - { return resolveUrl(QUrl::fromEncoded(url.toUtf8())); } - -#ifdef QT_KEYPAD_NAVIGATION - void keypadMove(bool next); - QTextCursor prevFocus; - int lastKeypadScrollValue; -#endif -}; - -QString QTextBrowserPrivate::findFile(const QUrl &name) const -{ - QString fileName; - if (name.scheme() == QLatin1String("qrc")) - fileName = QLatin1String(":/") + name.path(); - else - fileName = name.toLocalFile(); - - if (QFileInfo(fileName).isAbsolute()) - return fileName; - - foreach (QString path, searchPaths) { - if (!path.endsWith(QLatin1Char('/'))) - path.append(QLatin1Char('/')); - path.append(fileName); - if (QFileInfo(path).isReadable()) - return path; - } - - return fileName; -} - -QUrl QTextBrowserPrivate::resolveUrl(const QUrl &url) const -{ - if (!url.isRelative()) - return url; - - // For the second case QUrl can merge "#someanchor" with "foo.html" - // correctly to "foo.html#someanchor" - if (!(currentURL.isRelative() - || (currentURL.scheme() == QLatin1String("file") - && !QFileInfo(currentURL.toLocalFile()).isAbsolute())) - || (url.hasFragment() && url.path().isEmpty())) { - return currentURL.resolved(url); - } - - // this is our last resort when current url and new url are both relative - // we try to resolve against the current working directory in the local - // file system. - QFileInfo fi(currentURL.toLocalFile()); - if (fi.exists()) { - return QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(url); - } - - return url; -} - -void QTextBrowserPrivate::_q_activateAnchor(const QString &href) -{ - if (href.isEmpty()) - return; - Q_Q(QTextBrowser); - -#ifndef QT_NO_CURSOR - viewport->setCursor(oldCursor); -#endif - - const QUrl url = resolveUrl(href); - - if (!openLinks) { - emit q->anchorClicked(url); - return; - } - - textOrSourceChanged = false; - -#ifndef QT_NO_DESKTOPSERVICES - if ((openExternalLinks - && url.scheme() != QLatin1String("file") - && url.scheme() != QLatin1String("qrc") - && !url.isRelative()) - || (url.isRelative() && !currentURL.isRelative() - && currentURL.scheme() != QLatin1String("file") - && currentURL.scheme() != QLatin1String("qrc"))) { - QDesktopServices::openUrl(url); - return; - } -#endif - - emit q->anchorClicked(url); - - if (textOrSourceChanged) - return; - - q->setSource(url); -} - -void QTextBrowserPrivate::_q_highlightLink(const QString &anchor) -{ - Q_Q(QTextBrowser); - if (anchor.isEmpty()) { -#ifndef QT_NO_CURSOR - if (viewport->cursor().shape() != Qt::PointingHandCursor) - oldCursor = viewport->cursor(); - viewport->setCursor(oldCursor); -#endif - emit q->highlighted(QUrl()); - emit q->highlighted(QString()); - } else { -#ifndef QT_NO_CURSOR - viewport->setCursor(Qt::PointingHandCursor); -#endif - - const QUrl url = resolveUrl(anchor); - emit q->highlighted(url); - // convenience to ease connecting to QStatusBar::showMessage(const QString &) - emit q->highlighted(url.toString()); - } -} - -void QTextBrowserPrivate::setSource(const QUrl &url) -{ - Q_Q(QTextBrowser); -#ifndef QT_NO_CURSOR - if (q->isVisible()) - QApplication::setOverrideCursor(Qt::WaitCursor); -#endif - textOrSourceChanged = true; - - QString txt; - - bool doSetText = false; - - QUrl currentUrlWithoutFragment = currentURL; - currentUrlWithoutFragment.setFragment(QString()); - QUrl newUrlWithoutFragment = currentURL.resolved(url); - newUrlWithoutFragment.setFragment(QString()); - - if (url.isValid() - && (newUrlWithoutFragment != currentUrlWithoutFragment || forceLoadOnSourceChange)) { - QVariant data = q->loadResource(QTextDocument::HtmlResource, resolveUrl(url)); - if (data.type() == QVariant::String) { - txt = data.toString(); - } else if (data.type() == QVariant::ByteArray) { -#ifndef QT_NO_TEXTCODEC - QByteArray ba = data.toByteArray(); - QTextCodec *codec = Qt::codecForHtml(ba); - txt = codec->toUnicode(ba); -#else - txt = data.toString(); -#endif - } - if (txt.isEmpty()) - qWarning("QTextBrowser: No document for %s", url.toString().toLatin1().constData()); - - if (q->isVisible()) { - QString firstTag = txt.left(txt.indexOf(QLatin1Char('>')) + 1); - if (firstTag.startsWith(QLatin1String("<qt")) && firstTag.contains(QLatin1String("type")) && firstTag.contains(QLatin1String("detail"))) { -#ifndef QT_NO_CURSOR - QApplication::restoreOverrideCursor(); -#endif -#ifndef QT_NO_WHATSTHIS - QWhatsThis::showText(QCursor::pos(), txt, q); -#endif - return; - } - } - - currentURL = resolveUrl(url); - doSetText = true; - } - - if (!home.isValid()) - home = url; - - if (doSetText) { -#ifndef QT_NO_TEXTHTMLPARSER - q->QTextEdit::setHtml(txt); - q->document()->setMetaInformation(QTextDocument::DocumentUrl, currentURL.toString()); -#else - q->QTextEdit::setPlainText(txt); -#endif - -#ifdef QT_KEYPAD_NAVIGATION - prevFocus.movePosition(QTextCursor::Start); -#endif - } - - forceLoadOnSourceChange = false; - - if (!url.fragment().isEmpty()) { - q->scrollToAnchor(url.fragment()); - } else { - hbar->setValue(0); - vbar->setValue(0); - } -#ifdef QT_KEYPAD_NAVIGATION - lastKeypadScrollValue = vbar->value(); - emit q->highlighted(QUrl()); - emit q->highlighted(QString()); -#endif - -#ifndef QT_NO_CURSOR - if (q->isVisible()) - QApplication::restoreOverrideCursor(); -#endif - emit q->sourceChanged(url); -} - -#ifdef QT_KEYPAD_NAVIGATION -void QTextBrowserPrivate::keypadMove(bool next) -{ - Q_Q(QTextBrowser); - - const int height = viewport->height(); - const int overlap = qBound(20, height / 5, 40); // XXX arbitrary, but a good balance - const int visibleLinkAmount = overlap; // consistent, but maybe not the best choice (?) - int yOffset = vbar->value(); - int scrollYOffset = qBound(0, next ? yOffset + height - overlap : yOffset - height + overlap, vbar->maximum()); - - bool foundNextAnchor = false; - bool focusIt = false; - int focusedPos = -1; - - QTextCursor anchorToFocus; - - QRectF viewRect = QRectF(0, yOffset, control->size().width(), height); - QRectF newViewRect = QRectF(0, scrollYOffset, control->size().width(), height); - QRectF bothViewRects = viewRect.united(newViewRect); - - // If we don't have a previous anchor, pretend that we had the first/last character - // on the screen selected. - if (prevFocus.isNull()) { - if (next) - prevFocus = control->cursorForPosition(QPointF(0, yOffset)); - else - prevFocus = control->cursorForPosition(QPointF(control->size().width(), yOffset + height)); - } - - // First, check to see if someone has moved the scroll bars independently - if (lastKeypadScrollValue != yOffset) { - // Someone (user or programmatically) has moved us, so we might - // need to start looking from the current position instead of prevFocus - - bool findOnScreen = true; - - // If prevFocus is on screen at all, we just use it. - if (prevFocus.hasSelection()) { - QRectF prevRect = control->selectionRect(prevFocus); - if (viewRect.intersects(prevRect)) - findOnScreen = false; - } - - // Otherwise, we find a new anchor that's on screen. - // Basically, create a cursor with the last/first character - // on screen - if (findOnScreen) { - if (next) - prevFocus = control->cursorForPosition(QPointF(0, yOffset)); - else - prevFocus = control->cursorForPosition(QPointF(control->size().width(), yOffset + height)); - } - foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus); - } else if (prevFocus.hasSelection()) { - // Check the pathological case that the current anchor is higher - // than the screen, and just scroll through it in that case - QRectF prevRect = control->selectionRect(prevFocus); - if ((next && prevRect.bottom() > (yOffset + height)) || - (!next && prevRect.top() < yOffset)) { - anchorToFocus = prevFocus; - focusedPos = scrollYOffset; - focusIt = true; - } else { - // This is the "normal" case - no scroll bar adjustments, no large anchors, - // and no wrapping. - foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus); - } - } - - // If not found yet, see if we need to wrap - if (!focusIt && !foundNextAnchor) { - if (next) { - if (yOffset == vbar->maximum()) { - prevFocus.movePosition(QTextCursor::Start); - yOffset = scrollYOffset = 0; - - // Refresh the rectangles - viewRect = QRectF(0, yOffset, control->size().width(), height); - newViewRect = QRectF(0, scrollYOffset, control->size().width(), height); - bothViewRects = viewRect.united(newViewRect); - } - } else { - if (yOffset == 0) { - prevFocus.movePosition(QTextCursor::End); - yOffset = scrollYOffset = vbar->maximum(); - - // Refresh the rectangles - viewRect = QRectF(0, yOffset, control->size().width(), height); - newViewRect = QRectF(0, scrollYOffset, control->size().width(), height); - bothViewRects = viewRect.united(newViewRect); - } - } - - // Try looking now - foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus); - } - - // If we did actually find an anchor to use... - if (foundNextAnchor) { - QRectF desiredRect = control->selectionRect(anchorToFocus); - - // XXX This is an arbitrary heuristic - // Decide to focus an anchor if it will be at least be - // in the middle region of the screen after a scroll. - // This can result in partial anchors with focus, but - // insisting on links being completely visible before - // selecting them causes disparities between links that - // take up 90% of the screen height and those that take - // up e.g. 110% - // Obviously if a link is entirely visible, we still - // focus it. - if(bothViewRects.contains(desiredRect) - || bothViewRects.adjusted(0, visibleLinkAmount, 0, -visibleLinkAmount).intersects(desiredRect)) { - focusIt = true; - - // We aim to put the new link in the middle of the screen, - // unless the link is larger than the screen (we just move to - // display the first page of the link) - if (desiredRect.height() > height) { - if (next) - focusedPos = (int) desiredRect.top(); - else - focusedPos = (int) desiredRect.bottom() - height; - } else - focusedPos = (int) ((desiredRect.top() + desiredRect.bottom()) / 2 - (height / 2)); - - // and clamp it to make sure we don't skip content. - if (next) - focusedPos = qBound(yOffset, focusedPos, scrollYOffset); - else - focusedPos = qBound(scrollYOffset, focusedPos, yOffset); - } - } - - // If we didn't get a new anchor, check if the old one is still on screen when we scroll - // Note that big (larger than screen height) anchors also have some handling at the - // start of this function. - if (!focusIt && prevFocus.hasSelection()) { - QRectF desiredRect = control->selectionRect(prevFocus); - // XXX this may be better off also using the visibleLinkAmount value - if(newViewRect.intersects(desiredRect)) { - focusedPos = scrollYOffset; - focusIt = true; - anchorToFocus = prevFocus; - } - } - - // setTextCursor ensures that the cursor is visible. save & restore - // the scroll bar values therefore - const int savedXOffset = hbar->value(); - - // Now actually process our decision - if (focusIt && control->setFocusToAnchor(anchorToFocus)) { - // Save the focus for next time - prevFocus = control->textCursor(); - - // Scroll - vbar->setValue(focusedPos); - lastKeypadScrollValue = focusedPos; - hbar->setValue(savedXOffset); - - // Ensure that the new selection is highlighted. - const QString href = control->anchorAtCursor(); - QUrl url = resolveUrl(href); - emit q->highlighted(url); - emit q->highlighted(url.toString()); - } else { - // Scroll - vbar->setValue(scrollYOffset); - lastKeypadScrollValue = scrollYOffset; - - // now make sure we don't have a focused anchor - QTextCursor cursor = control->textCursor(); - cursor.clearSelection(); - - control->setTextCursor(cursor); - - hbar->setValue(savedXOffset); - vbar->setValue(scrollYOffset); - - emit q->highlighted(QUrl()); - emit q->highlighted(QString()); - } -} -#endif - -QTextBrowserPrivate::HistoryEntry QTextBrowserPrivate::createHistoryEntry() const -{ - HistoryEntry entry; - entry.url = q_func()->source(); - entry.title = q_func()->documentTitle(); - entry.hpos = hbar->value(); - entry.vpos = vbar->value(); - - const QTextCursor cursor = control->textCursor(); - if (control->cursorIsFocusIndicator() - && cursor.hasSelection()) { - - entry.focusIndicatorPosition = cursor.position(); - entry.focusIndicatorAnchor = cursor.anchor(); - } - return entry; -} - -void QTextBrowserPrivate::restoreHistoryEntry(const HistoryEntry entry) -{ - setSource(entry.url); - hbar->setValue(entry.hpos); - vbar->setValue(entry.vpos); - if (entry.focusIndicatorAnchor != -1 && entry.focusIndicatorPosition != -1) { - QTextCursor cursor(control->document()); - cursor.setPosition(entry.focusIndicatorAnchor); - cursor.setPosition(entry.focusIndicatorPosition, QTextCursor::KeepAnchor); - control->setTextCursor(cursor); - control->setCursorIsFocusIndicator(true); - } -#ifdef QT_KEYPAD_NAVIGATION - lastKeypadScrollValue = vbar->value(); - prevFocus = control->textCursor(); - - Q_Q(QTextBrowser); - const QString href = prevFocus.charFormat().anchorHref(); - QUrl url = resolveUrl(href); - emit q->highlighted(url); - emit q->highlighted(url.toString()); -#endif -} - -/*! - \class QTextBrowser - \brief The QTextBrowser class provides a rich text browser with hypertext navigation. - - \ingroup richtext-processing - - This class extends QTextEdit (in read-only mode), adding some navigation - functionality so that users can follow links in hypertext documents. - - If you want to provide your users with an editable rich text editor, - use QTextEdit. If you want a text browser without hypertext navigation - use QTextEdit, and use QTextEdit::setReadOnly() to disable - editing. If you just need to display a small piece of rich text - use QLabel. - - \section1 Document Source and Contents - - The contents of QTextEdit are set with setHtml() or setPlainText(), - but QTextBrowser also implements the setSource() function, making it - possible to use a named document as the source text. The name is looked - up in a list of search paths and in the directory of the current document - factory. - - If a document name ends with - an anchor (for example, "\c #anchor"), the text browser automatically - scrolls to that position (using scrollToAnchor()). When the user clicks - on a hyperlink, the browser will call setSource() itself with the link's - \c href value as argument. You can track the current source by connecting - to the sourceChanged() signal. - - \section1 Navigation - - QTextBrowser provides backward() and forward() slots which you can - use to implement Back and Forward buttons. The home() slot sets - the text to the very first document displayed. The anchorClicked() - signal is emitted when the user clicks an anchor. To override the - default navigation behavior of the browser, call the setSource() - function to supply new document text in a slot connected to this - signal. - - If you want to load documents stored in the Qt resource system use - \c{qrc} as the scheme in the URL to load. For example, for the document - resource path \c{:/docs/index.html} use \c{qrc:/docs/index.html} as - the URL with setSource(). - - \sa QTextEdit, QTextDocument -*/ - -/*! - \property QTextBrowser::modified - \brief whether the contents of the text browser have been modified -*/ - -/*! - \property QTextBrowser::readOnly - \brief whether the text browser is read-only - - By default, this property is true. -*/ - -/*! - \property QTextBrowser::undoRedoEnabled - \brief whether the text browser supports undo/redo operations - - By default, this property is false. -*/ - -void QTextBrowserPrivate::init() -{ - Q_Q(QTextBrowser); - control->setTextInteractionFlags(Qt::TextBrowserInteraction); -#ifndef QT_NO_CURSOR - viewport->setCursor(oldCursor); -#endif - q->setUndoRedoEnabled(false); - viewport->setMouseTracking(true); - QObject::connect(q->document(), SIGNAL(contentsChanged()), q, SLOT(_q_documentModified())); - QObject::connect(control, SIGNAL(linkActivated(QString)), - q, SLOT(_q_activateAnchor(QString))); - QObject::connect(control, SIGNAL(linkHovered(QString)), - q, SLOT(_q_highlightLink(QString))); -} - -/*! - Constructs an empty QTextBrowser with parent \a parent. -*/ -QTextBrowser::QTextBrowser(QWidget *parent) - : QTextEdit(*new QTextBrowserPrivate, parent) -{ - Q_D(QTextBrowser); - d->init(); -} - -#ifdef QT3_SUPPORT -/*! - Use one of the constructors that doesn't take the \a name - argument and then use setObjectName() instead. -*/ -QTextBrowser::QTextBrowser(QWidget *parent, const char *name) - : QTextEdit(*new QTextBrowserPrivate, parent) -{ - setObjectName(QString::fromAscii(name)); - Q_D(QTextBrowser); - d->init(); -} -#endif - -/*! - \internal -*/ -QTextBrowser::~QTextBrowser() -{ -} - -/*! - \property QTextBrowser::source - \brief the name of the displayed document. - - This is a an invalid url if no document is displayed or if the - source is unknown. - - When setting this property QTextBrowser tries to find a document - with the specified name in the paths of the searchPaths property - and directory of the current source, unless the value is an absolute - file path. It also checks for optional anchors and scrolls the document - accordingly - - If the first tag in the document is \c{<qt type=detail>}, the - document is displayed as a popup rather than as new document in - the browser window itself. Otherwise, the document is displayed - normally in the text browser with the text set to the contents of - the named document with setHtml(). - - By default, this property contains an empty URL. -*/ -QUrl QTextBrowser::source() const -{ - Q_D(const QTextBrowser); - if (d->stack.isEmpty()) - return QUrl(); - else - return d->stack.top().url; -} - -/*! - \property QTextBrowser::searchPaths - \brief the search paths used by the text browser to find supporting - content - - QTextBrowser uses this list to locate images and documents. - - By default, this property contains an empty string list. -*/ - -QStringList QTextBrowser::searchPaths() const -{ - Q_D(const QTextBrowser); - return d->searchPaths; -} - -void QTextBrowser::setSearchPaths(const QStringList &paths) -{ - Q_D(QTextBrowser); - d->searchPaths = paths; -} - -/*! - Reloads the current set source. -*/ -void QTextBrowser::reload() -{ - Q_D(QTextBrowser); - QUrl s = d->currentURL; - d->currentURL = QUrl(); - setSource(s); -} - -void QTextBrowser::setSource(const QUrl &url) -{ - Q_D(QTextBrowser); - - const QTextBrowserPrivate::HistoryEntry historyEntry = d->createHistoryEntry(); - - d->setSource(url); - - if (!url.isValid()) - return; - - // the same url you are already watching? - if (!d->stack.isEmpty() && d->stack.top().url == url) - return; - - if (!d->stack.isEmpty()) - d->stack.top() = historyEntry; - - QTextBrowserPrivate::HistoryEntry entry; - entry.url = url; - entry.title = documentTitle(); - entry.hpos = 0; - entry.vpos = 0; - d->stack.push(entry); - - emit backwardAvailable(d->stack.count() > 1); - - if (!d->forwardStack.isEmpty() && d->forwardStack.top().url == url) { - d->forwardStack.pop(); - emit forwardAvailable(d->forwardStack.count() > 0); - } else { - d->forwardStack.clear(); - emit forwardAvailable(false); - } - - emit historyChanged(); -} - -/*! - \fn void QTextBrowser::backwardAvailable(bool available) - - This signal is emitted when the availability of backward() - changes. \a available is false when the user is at home(); - otherwise it is true. -*/ - -/*! - \fn void QTextBrowser::forwardAvailable(bool available) - - This signal is emitted when the availability of forward() changes. - \a available is true after the user navigates backward() and false - when the user navigates or goes forward(). -*/ - -/*! - \fn void QTextBrowser::historyChanged() - \since 4.4 - - This signal is emitted when the history changes. - - \sa historyTitle(), historyUrl() -*/ - -/*! - \fn void QTextBrowser::sourceChanged(const QUrl &src) - - This signal is emitted when the source has changed, \a src - being the new source. - - Source changes happen both programmatically when calling - setSource(), forward(), backword() or home() or when the user - clicks on links or presses the equivalent key sequences. -*/ - -/*! \fn void QTextBrowser::highlighted(const QUrl &link) - - This signal is emitted when the user has selected but not - activated an anchor in the document. The URL referred to by the - anchor is passed in \a link. -*/ - -/*! \fn void QTextBrowser::highlighted(const QString &link) - \overload - - Convenience signal that allows connecting to a slot - that takes just a QString, like for example QStatusBar's - message(). -*/ - - -/*! - \fn void QTextBrowser::anchorClicked(const QUrl &link) - - This signal is emitted when the user clicks an anchor. The - URL referred to by the anchor is passed in \a link. - - Note that the browser will automatically handle navigation to the - location specified by \a link unless the openLinks property - is set to false or you call setSource() in a slot connected. - This mechanism is used to override the default navigation features of the browser. -*/ - -/*! - Changes the document displayed to the previous document in the - list of documents built by navigating links. Does nothing if there - is no previous document. - - \sa forward(), backwardAvailable() -*/ -void QTextBrowser::backward() -{ - Q_D(QTextBrowser); - if (d->stack.count() <= 1) - return; - - // Update the history entry - d->forwardStack.push(d->createHistoryEntry()); - d->stack.pop(); // throw away the old version of the current entry - d->restoreHistoryEntry(d->stack.top()); // previous entry - emit backwardAvailable(d->stack.count() > 1); - emit forwardAvailable(true); - emit historyChanged(); -} - -/*! - Changes the document displayed to the next document in the list of - documents built by navigating links. Does nothing if there is no - next document. - - \sa backward(), forwardAvailable() -*/ -void QTextBrowser::forward() -{ - Q_D(QTextBrowser); - if (d->forwardStack.isEmpty()) - return; - if (!d->stack.isEmpty()) { - // Update the history entry - d->stack.top() = d->createHistoryEntry(); - } - d->stack.push(d->forwardStack.pop()); - d->restoreHistoryEntry(d->stack.top()); - emit backwardAvailable(true); - emit forwardAvailable(!d->forwardStack.isEmpty()); - emit historyChanged(); -} - -/*! - Changes the document displayed to be the first document from - the history. -*/ -void QTextBrowser::home() -{ - Q_D(QTextBrowser); - if (d->home.isValid()) - setSource(d->home); -} - -/*! - The event \a ev is used to provide the following keyboard shortcuts: - \table - \header \i Keypress \i Action - \row \i Alt+Left Arrow \i \l backward() - \row \i Alt+Right Arrow \i \l forward() - \row \i Alt+Up Arrow \i \l home() - \endtable -*/ -void QTextBrowser::keyPressEvent(QKeyEvent *ev) -{ -#ifdef QT_KEYPAD_NAVIGATION - Q_D(QTextBrowser); - switch (ev->key()) { - case Qt::Key_Select: - if (QApplication::keypadNavigationEnabled()) { - if (!hasEditFocus()) { - setEditFocus(true); - return; - } else { - QTextCursor cursor = d->control->textCursor(); - QTextCharFormat charFmt = cursor.charFormat(); - if (!cursor.hasSelection() || charFmt.anchorHref().isEmpty()) { - ev->accept(); - return; - } - } - } - break; - case Qt::Key_Back: - if (QApplication::keypadNavigationEnabled()) { - if (hasEditFocus()) { - setEditFocus(false); - ev->accept(); - return; - } - } - QTextEdit::keyPressEvent(ev); - return; - default: - if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { - ev->ignore(); - return; - } - } -#endif - - if (ev->modifiers() & Qt::AltModifier) { - switch (ev->key()) { - case Qt::Key_Right: - forward(); - ev->accept(); - return; - case Qt::Key_Left: - backward(); - ev->accept(); - return; - case Qt::Key_Up: - home(); - ev->accept(); - return; - } - } -#ifdef QT_KEYPAD_NAVIGATION - else { - if (ev->key() == Qt::Key_Up) { - d->keypadMove(false); - return; - } else if (ev->key() == Qt::Key_Down) { - d->keypadMove(true); - return; - } - } -#endif - QTextEdit::keyPressEvent(ev); -} - -/*! - \reimp -*/ -void QTextBrowser::mouseMoveEvent(QMouseEvent *e) -{ - QTextEdit::mouseMoveEvent(e); -} - -/*! - \reimp -*/ -void QTextBrowser::mousePressEvent(QMouseEvent *e) -{ - QTextEdit::mousePressEvent(e); -} - -/*! - \reimp -*/ -void QTextBrowser::mouseReleaseEvent(QMouseEvent *e) -{ - QTextEdit::mouseReleaseEvent(e); -} - -/*! - \reimp -*/ -void QTextBrowser::focusOutEvent(QFocusEvent *ev) -{ -#ifndef QT_NO_CURSOR - Q_D(QTextBrowser); - d->viewport->setCursor((!(d->control->textInteractionFlags() & Qt::TextEditable)) ? d->oldCursor : Qt::IBeamCursor); -#endif - QTextEdit::focusOutEvent(ev); -} - -/*! - \reimp -*/ -bool QTextBrowser::focusNextPrevChild(bool next) -{ - Q_D(QTextBrowser); - if (d->control->setFocusToNextOrPreviousAnchor(next)) { -#ifdef QT_KEYPAD_NAVIGATION - // Might need to synthesize a highlight event. - if (d->prevFocus != d->control->textCursor() && d->control->textCursor().hasSelection()) { - const QString href = d->control->anchorAtCursor(); - QUrl url = d->resolveUrl(href); - emit highlighted(url); - emit highlighted(url.toString()); - } - d->prevFocus = d->control->textCursor(); -#endif - return true; - } else { -#ifdef QT_KEYPAD_NAVIGATION - // We assume we have no highlight now. - emit highlighted(QUrl()); - emit highlighted(QString()); -#endif - } - return QTextEdit::focusNextPrevChild(next); -} - -/*! - \reimp -*/ -void QTextBrowser::paintEvent(QPaintEvent *e) -{ - Q_D(QTextBrowser); - QPainter p(d->viewport); - d->paint(&p, e); -} - -/*! - This function is called when the document is loaded and for - each image in the document. The \a type indicates the type of resource - to be loaded. An invalid QVariant is returned if the resource cannot be - loaded. - - The default implementation ignores \a type and tries to locate - the resources by interpreting \a name as a file name. If it is - not an absolute path it tries to find the file in the paths of - the \l searchPaths property and in the same directory as the - current source. On success, the result is a QVariant that stores - a QByteArray with the contents of the file. - - If you reimplement this function, you can return other QVariant - types. The table below shows which variant types are supported - depending on the resource type: - - \table - \header \i ResourceType \i QVariant::Type - \row \i QTextDocument::HtmlResource \i QString or QByteArray - \row \i QTextDocument::ImageResource \i QImage, QPixmap or QByteArray - \row \i QTextDocument::StyleSheetResource \i QString or QByteArray - \endtable -*/ -QVariant QTextBrowser::loadResource(int /*type*/, const QUrl &name) -{ - Q_D(QTextBrowser); - - QByteArray data; - QString fileName = d->findFile(d->resolveUrl(name)); - QFile f(fileName); - if (f.open(QFile::ReadOnly)) { - data = f.readAll(); - f.close(); - } else { - return QVariant(); - } - - return data; -} - -/*! - \since 4.2 - - Returns true if the text browser can go backward in the document history - using backward(). - - \sa backwardAvailable(), backward() -*/ -bool QTextBrowser::isBackwardAvailable() const -{ - Q_D(const QTextBrowser); - return d->stack.count() > 1; -} - -/*! - \since 4.2 - - Returns true if the text browser can go forward in the document history - using forward(). - - \sa forwardAvailable(), forward() -*/ -bool QTextBrowser::isForwardAvailable() const -{ - Q_D(const QTextBrowser); - return !d->forwardStack.isEmpty(); -} - -/*! - \since 4.2 - - Clears the history of visited documents and disables the forward and - backward navigation. - - \sa backward(), forward() -*/ -void QTextBrowser::clearHistory() -{ - Q_D(QTextBrowser); - d->forwardStack.clear(); - if (!d->stack.isEmpty()) { - QTextBrowserPrivate::HistoryEntry historyEntry = d->stack.top(); - d->stack.resize(0); - d->stack.push(historyEntry); - d->home = historyEntry.url; - } - emit forwardAvailable(false); - emit backwardAvailable(false); - emit historyChanged(); -} - -/*! - Returns the url of the HistoryItem. - - \table - \header \i Input \i Return - \row \i \a{i} < 0 \i \l backward() history - \row \i\a{i} == 0 \i current, see QTextBrowser::source() - \row \i \a{i} > 0 \i \l forward() history - \endtable - - \since 4.4 -*/ -QUrl QTextBrowser::historyUrl(int i) const -{ - Q_D(const QTextBrowser); - return d->history(i).url; -} - -/*! - Returns the documentTitle() of the HistoryItem. - - \table - \header \i Input \i Return - \row \i \a{i} < 0 \i \l backward() history - \row \i \a{i} == 0 \i current, see QTextBrowser::source() - \row \i \a{i} > 0 \i \l forward() history - \endtable - - \snippet doc/src/snippets/code/src_gui_widgets_qtextbrowser.cpp 0 - - \since 4.4 -*/ -QString QTextBrowser::historyTitle(int i) const -{ - Q_D(const QTextBrowser); - return d->history(i).title; -} - - -/*! - Returns the number of locations forward in the history. - - \since 4.4 -*/ -int QTextBrowser::forwardHistoryCount() const -{ - Q_D(const QTextBrowser); - return d->forwardStack.count(); -} - -/*! - Returns the number of locations backward in the history. - - \since 4.4 -*/ -int QTextBrowser::backwardHistoryCount() const -{ - Q_D(const QTextBrowser); - return d->stack.count()-1; -} - -/*! - \property QTextBrowser::openExternalLinks - \since 4.2 - - Specifies whether QTextBrowser should automatically open links to external - sources using QDesktopServices::openUrl() instead of emitting the - anchorClicked signal. Links are considered external if their scheme is - neither file or qrc. - - The default value is false. -*/ -bool QTextBrowser::openExternalLinks() const -{ - Q_D(const QTextBrowser); - return d->openExternalLinks; -} - -void QTextBrowser::setOpenExternalLinks(bool open) -{ - Q_D(QTextBrowser); - d->openExternalLinks = open; -} - -/*! - \property QTextBrowser::openLinks - \since 4.3 - - This property specifies whether QTextBrowser should automatically open links the user tries to - activate by mouse or keyboard. - - Regardless of the value of this property the anchorClicked signal is always emitted. - - The default value is true. -*/ - -bool QTextBrowser::openLinks() const -{ - Q_D(const QTextBrowser); - return d->openLinks; -} - -void QTextBrowser::setOpenLinks(bool open) -{ - Q_D(QTextBrowser); - d->openLinks = open; -} - -/*! \reimp */ -bool QTextBrowser::event(QEvent *e) -{ - return QTextEdit::event(e); -} - -QT_END_NAMESPACE - -#include "moc_qtextbrowser.cpp" - -#endif // QT_NO_TEXTBROWSER |