urllineedit.cpp Example File

webenginewidgets/demobrowser/urllineedit.cpp

  /****************************************************************************
  **
  ** Copyright (C) 2016 The Qt Company Ltd.
  ** Contact: https://www.qt.io/licensing/
  **
  ** This file is part of the demonstration applications of the Qt Toolkit.
  **
  ** $QT_BEGIN_LICENSE:BSD$
  ** 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 https://www.qt.io/terms-conditions. For further
  ** information use the contact form at https://www.qt.io/contact-us.
  **
  ** BSD License Usage
  ** Alternatively, you may use this file under the terms of the BSD license
  ** as follows:
  **
  ** "Redistribution and use in source and binary forms, with or without
  ** modification, are permitted provided that the following conditions are
  ** met:
  **   * Redistributions of source code must retain the above copyright
  **     notice, this list of conditions and the following disclaimer.
  **   * Redistributions in binary form must reproduce the above copyright
  **     notice, this list of conditions and the following disclaimer in
  **     the documentation and/or other materials provided with the
  **     distribution.
  **   * Neither the name of The Qt Company Ltd nor the names of its
  **     contributors may be used to endorse or promote products derived
  **     from this software without specific prior written permission.
  **
  **
  ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  **
  ** $QT_END_LICENSE$
  **
  ****************************************************************************/

  #include "urllineedit.h"

  #include "browserapplication.h"
  #include "searchlineedit.h"
  #include "webview.h"

  #include <QtCore/QEvent>
  #include <QtCore/QMimeData>

  #include <QtWidgets/QApplication>
  #include <QtWidgets/QCompleter>
  #include <QtGui/QFocusEvent>
  #include <QtWidgets/QHBoxLayout>
  #include <QtWidgets/QLabel>
  #include <QtWidgets/QLineEdit>
  #include <QtGui/QDrag>
  #include <QtGui/QPainter>
  #include <QtWidgets/QStyle>
  #include <QtWidgets/QStyleOptionFrame>

  #include <QtCore/QDebug>

  ExLineEdit::ExLineEdit(QWidget *parent)
      : QWidget(parent)
      , m_leftWidget(0)
      , m_lineEdit(new QLineEdit(this))
      , m_clearButton(0)
  {
      setFocusPolicy(m_lineEdit->focusPolicy());
      setAttribute(Qt::WA_InputMethodEnabled);
      setSizePolicy(m_lineEdit->sizePolicy());
      setBackgroundRole(m_lineEdit->backgroundRole());
      setMouseTracking(true);
      setAcceptDrops(true);
      setAttribute(Qt::WA_MacShowFocusRect, true);
      QPalette p = m_lineEdit->palette();
      setPalette(p);

      // line edit
      m_lineEdit->setFrame(false);
      m_lineEdit->setFocusProxy(this);
      m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
      QPalette clearPalette = m_lineEdit->palette();
      clearPalette.setBrush(QPalette::Base, QBrush(Qt::transparent));
      m_lineEdit->setPalette(clearPalette);

      // clearButton
      m_clearButton = new ClearButton(this);
      connect(m_clearButton, SIGNAL(clicked()),
              m_lineEdit, SLOT(clear()));
      connect(m_lineEdit, SIGNAL(textChanged(QString)),
              m_clearButton, SLOT(textChanged(QString)));
  }

  void ExLineEdit::setLeftWidget(QWidget *widget)
  {
      m_leftWidget = widget;
  }

  QWidget *ExLineEdit::leftWidget() const
  {
      return m_leftWidget;
  }

  void ExLineEdit::resizeEvent(QResizeEvent *event)
  {
      Q_ASSERT(m_leftWidget);
      updateGeometries();
      QWidget::resizeEvent(event);
  }

  void ExLineEdit::updateGeometries()
  {
      QStyleOptionFrame panel;
      initStyleOption(&panel);
      QRect rect = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);

      int height = rect.height();
      int width = rect.width();

      int m_leftWidgetHeight = m_leftWidget->height();
      m_leftWidget->setGeometry(rect.x() + 2,          rect.y() + (height - m_leftWidgetHeight)/2,
                                m_leftWidget->width(), m_leftWidget->height());

      int clearButtonWidth = this->height();
      m_lineEdit->setGeometry(m_leftWidget->x() + m_leftWidget->width(),        0,
                              width - clearButtonWidth - m_leftWidget->width(), this->height());

      m_clearButton->setGeometry(this->width() - clearButtonWidth, 0,
                                 clearButtonWidth, this->height());
  }

  void ExLineEdit::initStyleOption(QStyleOptionFrame *option) const
  {
      option->initFrom(this);
      option->rect = contentsRect();
      option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, option, this);
      option->midLineWidth = 0;
      option->state |= QStyle::State_Sunken;
      if (m_lineEdit->isReadOnly())
          option->state |= QStyle::State_ReadOnly;
  #ifdef QT_KEYPAD_NAVIGATION
      if (hasEditFocus())
          option->state |= QStyle::State_HasEditFocus;
  #endif
      option->features = QStyleOptionFrame::None;
  }

  QSize ExLineEdit::sizeHint() const
  {
      m_lineEdit->setFrame(true);
      QSize size = m_lineEdit->sizeHint();
      m_lineEdit->setFrame(false);
      return size;
  }

  void ExLineEdit::focusInEvent(QFocusEvent *event)
  {
      m_lineEdit->event(event);
      QWidget::focusInEvent(event);
  }

  void ExLineEdit::focusOutEvent(QFocusEvent *event)
  {
      m_lineEdit->event(event);

      if (m_lineEdit->completer()) {
          connect(m_lineEdit->completer(), SIGNAL(activated(QString)),
                           m_lineEdit, SLOT(setText(QString)));
          connect(m_lineEdit->completer(), SIGNAL(highlighted(QString)),
                           m_lineEdit, SLOT(_q_completionHighlighted(QString)));
      }
      QWidget::focusOutEvent(event);
  }

  void ExLineEdit::keyPressEvent(QKeyEvent *event)
  {
      m_lineEdit->event(event);
  }

  bool ExLineEdit::event(QEvent *event)
  {
      if (event->type() == QEvent::ShortcutOverride)
          return m_lineEdit->event(event);
      return QWidget::event(event);
  }

  void ExLineEdit::paintEvent(QPaintEvent *)
  {
      QPainter p(this);
      QStyleOptionFrame panel;
      initStyleOption(&panel);
      style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p, this);
  }

  QVariant ExLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const
  {
      return m_lineEdit->inputMethodQuery(property);
  }

  void ExLineEdit::inputMethodEvent(QInputMethodEvent *e)
  {
      m_lineEdit->event(e);
  }

  class UrlIconLabel : public QLabel
  {

  public:
      UrlIconLabel(QWidget *parent);

      WebView *m_webView;

  protected:
      void mousePressEvent(QMouseEvent *event);
      void mouseMoveEvent(QMouseEvent *event);

  private:
      QPoint m_dragStartPos;

  };

  UrlIconLabel::UrlIconLabel(QWidget *parent)
      : QLabel(parent)
      , m_webView(0)
  {
      setMinimumWidth(16);
      setMinimumHeight(16);
  }

  void UrlIconLabel::mousePressEvent(QMouseEvent *event)
  {
      if (event->button() == Qt::LeftButton)
          m_dragStartPos = event->pos();
      QLabel::mousePressEvent(event);
  }

  void UrlIconLabel::mouseMoveEvent(QMouseEvent *event)
  {
      if (event->buttons() == Qt::LeftButton
          && (event->pos() - m_dragStartPos).manhattanLength() > QApplication::startDragDistance()
           && m_webView) {
          QDrag *drag = new QDrag(this);
          QMimeData *mimeData = new QMimeData;
          mimeData->setText(QString::fromUtf8(m_webView->url().toEncoded()));
          QList<QUrl> urls;
          urls.append(m_webView->url());
          mimeData->setUrls(urls);
          drag->setMimeData(mimeData);
          drag->exec();
      }
  }

  UrlLineEdit::UrlLineEdit(QWidget *parent)
      : ExLineEdit(parent)
      , m_webView(0)
      , m_iconLabel(0)
  {
      // icon
      m_iconLabel = new UrlIconLabel(this);
      m_iconLabel->resize(16, 16);
      setLeftWidget(m_iconLabel);
      m_defaultBaseColor = palette().color(QPalette::Base);
  }

  void UrlLineEdit::setWebView(WebView *webView)
  {
      Q_ASSERT(!m_webView);
      m_webView = webView;
      m_iconLabel->m_webView = webView;
      connect(webView, SIGNAL(urlChanged(QUrl)),
          this, SLOT(webViewUrlChanged(QUrl)));
      connect(webView, SIGNAL(iconChanged(QIcon)),
          this, SLOT(webViewIconChanged(QIcon)));
      connect(webView, SIGNAL(loadProgress(int)),
          this, SLOT(update()));
  }

  void UrlLineEdit::webViewUrlChanged(const QUrl &url)
  {
      m_lineEdit->setText(QString::fromUtf8(url.toEncoded()));
      m_lineEdit->setCursorPosition(0);
  }

  void UrlLineEdit::webViewIconChanged(const QIcon &icon)
  {
      Q_ASSERT(m_webView);
      m_iconLabel->setPixmap(icon.pixmap(16, 16));
  }

  QLinearGradient UrlLineEdit::generateGradient(const QColor &color) const
  {
      QLinearGradient gradient(0, 0, 0, height());
      gradient.setColorAt(0, m_defaultBaseColor);
      gradient.setColorAt(0.15, color.lighter(120));
      gradient.setColorAt(0.5, color);
      gradient.setColorAt(0.85, color.lighter(120));
      gradient.setColorAt(1, m_defaultBaseColor);
      return gradient;
  }

  void UrlLineEdit::focusOutEvent(QFocusEvent *event)
  {
      if (m_lineEdit->text().isEmpty() && m_webView)
          m_lineEdit->setText(QString::fromUtf8(m_webView->url().toEncoded()));
      ExLineEdit::focusOutEvent(event);
  }

  void UrlLineEdit::paintEvent(QPaintEvent *event)
  {
      QPalette p = palette();
      if (m_webView && m_webView->url().scheme() == QLatin1String("https")) {
          QColor lightYellow(248, 248, 210);
          p.setBrush(QPalette::Base, generateGradient(lightYellow));
      } else {
          p.setBrush(QPalette::Base, m_defaultBaseColor);
      }
      setPalette(p);
      ExLineEdit::paintEvent(event);

      QPainter painter(this);
      QStyleOptionFrame panel;
      initStyleOption(&panel);
      QRect backgroundRect = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
      if (m_webView && !hasFocus()) {
          int progress = m_webView->progress();
          QColor loadingColor = QColor(116, 192, 250);
          painter.setBrush(generateGradient(loadingColor));
          painter.setPen(Qt::transparent);
          int mid = backgroundRect.width() / 100.0f * progress;
          QRect progressRect(backgroundRect.x(), backgroundRect.y(), mid, backgroundRect.height());
          painter.drawRect(progressRect);
      }
  }