webview.cpp Example File

webkitwidgets/browser/webview.cpp

  /****************************************************************************
  **
  ** Copyright (C) 2015 The Qt Company Ltd.
  ** Contact: http://www.qt.io/licensing/
  **
  ** This file is part of the demonstration applications of the Qt Toolkit.
  **
  ** $QT_BEGIN_LICENSE:LGPL21$
  ** Commercial License Usage
  ** Licensees holding valid commercial Qt licenses may use this file in
  ** accordance with the commercial license agreement provided with the
  ** Software or, alternatively, in accordance with the terms contained in
  ** a written agreement between you and The Qt Company. For licensing terms
  ** and conditions see http://www.qt.io/terms-conditions. For further
  ** information use the contact form at http://www.qt.io/contact-us.
  **
  ** 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 or version 3 as published by the Free
  ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
  ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
  ** following information to ensure the GNU Lesser General Public License
  ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
  ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  **
  ** As a special exception, The Qt Company gives you certain additional
  ** rights. These rights are described in The Qt Company LGPL Exception
  ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  **
  ** $QT_END_LICENSE$
  **
  ****************************************************************************/

  #include "browserapplication.h"
  #include "browsermainwindow.h"
  #include "cookiejar.h"
  #include "downloadmanager.h"
  #include "networkaccessmanager.h"
  #include "tabwidget.h"
  #include "webview.h"

  #include <QtGui/QClipboard>
  #include <QtWidgets/QMenu>
  #include <QtWidgets/QMessageBox>
  #include <QtGui/QMouseEvent>

  #include <QWebHitTestResult>

  #ifndef QT_NO_UITOOLS
  #include <QtUiTools/QUiLoader>
  #endif  //QT_NO_UITOOLS

  #include <QtCore/QDebug>
  #include <QtCore/QBuffer>

  WebPage::WebPage(QObject *parent)
      : QWebPage(parent)
      , m_keyboardModifiers(Qt::NoModifier)
      , m_pressedButtons(Qt::NoButton)
      , m_openInNewTab(false)
  {
      setNetworkAccessManager(BrowserApplication::networkAccessManager());
      connect(this, SIGNAL(unsupportedContent(QNetworkReply*)),
              this, SLOT(handleUnsupportedContent(QNetworkReply*)));
  }

  BrowserMainWindow *WebPage::mainWindow()
  {
      QObject *w = this->parent();
      while (w) {
          if (BrowserMainWindow *mw = qobject_cast<BrowserMainWindow*>(w))
              return mw;
          w = w->parent();
      }
      return BrowserApplication::instance()->mainWindow();
  }

  bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type)
  {
      // ctrl open in new tab
      // ctrl-shift open in new tab and select
      // ctrl-alt open in new window
      if (type == QWebPage::NavigationTypeLinkClicked
          && (m_keyboardModifiers & Qt::ControlModifier
              || m_pressedButtons == Qt::MidButton)) {
          bool newWindow = (m_keyboardModifiers & Qt::AltModifier);
          WebView *webView;
          if (newWindow) {
              BrowserApplication::instance()->newMainWindow();
              BrowserMainWindow *newMainWindow = BrowserApplication::instance()->mainWindow();
              webView = newMainWindow->currentTab();
              newMainWindow->raise();
              newMainWindow->activateWindow();
              webView->setFocus();
          } else {
              bool selectNewTab = (m_keyboardModifiers & Qt::ShiftModifier);
              webView = mainWindow()->tabWidget()->newTab(selectNewTab);
          }
          webView->load(request);
          m_keyboardModifiers = Qt::NoModifier;
          m_pressedButtons = Qt::NoButton;
          return false;
      }
      if (frame == mainFrame()) {
          m_loadingUrl = request.url();
          emit loadingUrl(m_loadingUrl);
      }
      return QWebPage::acceptNavigationRequest(frame, request, type);
  }

  QWebPage *WebPage::createWindow(QWebPage::WebWindowType type)
  {
      Q_UNUSED(type);
      if (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton)
          m_openInNewTab = true;
      if (m_openInNewTab) {
          m_openInNewTab = false;
          return mainWindow()->tabWidget()->newTab()->page();
      }
      BrowserApplication::instance()->newMainWindow();
      BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
      return mainWindow->currentTab()->page();
  }

  #if !defined(QT_NO_UITOOLS)
  QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
  {
      Q_UNUSED(url);
      Q_UNUSED(paramNames);
      Q_UNUSED(paramValues);
      QUiLoader loader;
      return loader.createWidget(classId, view());
  }
  #endif // !defined(QT_NO_UITOOLS)

  void WebPage::handleUnsupportedContent(QNetworkReply *reply)
  {
      QString errorString = reply->errorString();

      if (m_loadingUrl != reply->url()) {
          // sub resource of this page
          qWarning() << "Resource" << reply->url().toEncoded() << "has unknown Content-Type, will be ignored.";
          reply->deleteLater();
          return;
      }

      if (reply->error() == QNetworkReply::NoError && !reply->header(QNetworkRequest::ContentTypeHeader).isValid()) {
          errorString = "Unknown Content-Type";
      }

      QFile file(QLatin1String(":/notfound.html"));
      bool isOpened = file.open(QIODevice::ReadOnly);
      Q_ASSERT(isOpened);
      Q_UNUSED(isOpened)

      QString title = tr("Error loading page: %1").arg(reply->url().toString());
      QString html = QString(QLatin1String(file.readAll()))
                          .arg(title)
                          .arg(errorString)
                          .arg(reply->url().toString());

      QBuffer imageBuffer;
      imageBuffer.open(QBuffer::ReadWrite);
      QIcon icon = view()->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, view());
      QPixmap pixmap = icon.pixmap(QSize(32,32));
      if (pixmap.save(&imageBuffer, "PNG")) {
          html.replace(QLatin1String("IMAGE_BINARY_DATA_HERE"),
                       QString(QLatin1String(imageBuffer.buffer().toBase64())));
      }

      QList<QWebFrame*> frames;
      frames.append(mainFrame());
      while (!frames.isEmpty()) {
          QWebFrame *frame = frames.takeFirst();
          if (frame->url() == reply->url()) {
              frame->setHtml(html, reply->url());
              return;
          }
          QList<QWebFrame *> children = frame->childFrames();
          foreach(QWebFrame *frame, children)
              frames.append(frame);
      }
      if (m_loadingUrl == reply->url()) {
          mainFrame()->setHtml(html, reply->url());
      }
  }

  WebView::WebView(QWidget* parent)
      : QWebView(parent)
      , m_progress(0)
      , m_page(new WebPage(this))
  {
      setPage(m_page);
      connect(page(), SIGNAL(statusBarMessage(QString)),
              SLOT(setStatusBarText(QString)));
      connect(this, SIGNAL(loadProgress(int)),
              this, SLOT(setProgress(int)));
      connect(this, SIGNAL(loadFinished(bool)),
              this, SLOT(loadFinished()));
      connect(page(), SIGNAL(loadingUrl(QUrl)),
              this, SIGNAL(urlChanged(QUrl)));
      connect(page(), SIGNAL(downloadRequested(QNetworkRequest)),
              this, SLOT(downloadRequested(QNetworkRequest)));
      page()->setForwardUnsupportedContent(true);

  }

  void WebView::contextMenuEvent(QContextMenuEvent *event)
  {
      QWebHitTestResult r = page()->mainFrame()->hitTestContent(event->pos());
      if (!r.linkUrl().isEmpty()) {
          QMenu menu(this);
          menu.addAction(pageAction(QWebPage::OpenLinkInNewWindow));
          menu.addAction(tr("Open in New Tab"), this, SLOT(openLinkInNewTab()));
          menu.addSeparator();
          menu.addAction(pageAction(QWebPage::DownloadLinkToDisk));
          // Add link to bookmarks...
          menu.addSeparator();
          menu.addAction(pageAction(QWebPage::CopyLinkToClipboard));
          if (page()->settings()->testAttribute(QWebSettings::DeveloperExtrasEnabled))
              menu.addAction(pageAction(QWebPage::InspectElement));
          menu.exec(mapToGlobal(event->pos()));
          return;
      }
      QWebView::contextMenuEvent(event);
  }

  void WebView::wheelEvent(QWheelEvent *event)
  {
      if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
          int numDegrees = event->delta() / 8;
          int numSteps = numDegrees / 15;
          setTextSizeMultiplier(textSizeMultiplier() + numSteps * 0.1);
          event->accept();
          return;
      }
      QWebView::wheelEvent(event);
  }

  void WebView::openLinkInNewTab()
  {
      m_page->m_openInNewTab = true;
      pageAction(QWebPage::OpenLinkInNewWindow)->trigger();
  }

  void WebView::setProgress(int progress)
  {
      m_progress = progress;
  }

  void WebView::loadFinished()
  {
      if (100 != m_progress) {
          qWarning() << "Received finished signal while progress is still:" << progress()
                     << "Url:" << url();
      }
      m_progress = 0;
  }

  void WebView::loadUrl(const QUrl &url)
  {
      m_initialUrl = url;
      load(url);
  }

  QString WebView::lastStatusBarText() const
  {
      return m_statusBarText;
  }

  QUrl WebView::url() const
  {
      QUrl url = QWebView::url();
      if (!url.isEmpty())
          return url;

      return m_initialUrl;
  }

  void WebView::mousePressEvent(QMouseEvent *event)
  {
      m_page->m_pressedButtons = event->buttons();
      m_page->m_keyboardModifiers = event->modifiers();
      QWebView::mousePressEvent(event);
  }

  void WebView::mouseReleaseEvent(QMouseEvent *event)
  {
      QWebView::mouseReleaseEvent(event);
  #ifndef QT_NO_CLIPBOARD
      if (!event->isAccepted() && (m_page->m_pressedButtons & Qt::MidButton)) {
          QUrl url(QApplication::clipboard()->text(QClipboard::Selection));
          if (!url.isEmpty() && url.isValid() && !url.scheme().isEmpty()) {
              setUrl(url);
          }
      }
  #endif
  }

  void WebView::setStatusBarText(const QString &string)
  {
      m_statusBarText = string;
  }

  void WebView::downloadRequested(const QNetworkRequest &request)
  {
      BrowserApplication::downloadManager()->download(request);
  }