ginebra2/UrlSearchSnippet.cpp
changeset 0 1450b09d0cfd
child 3 0954f5dd2cd0
child 5 0f2326c2a325
equal deleted inserted replaced
-1:000000000000 0:1450b09d0cfd
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "UrlSearchSnippet.h"
       
    20 #include "Utilities.h"
       
    21 
       
    22 #include "ChromeRenderer.h"
       
    23 #include "ChromeWidget.h"
       
    24 #include "ViewController.h"
       
    25 #include "WebChromeSnippet.h"
       
    26 
       
    27 #include "webpagecontroller.h"
       
    28 
       
    29 namespace GVA {
       
    30 
       
    31 // Methods for class UrlEditorWidget
       
    32 
       
    33 UrlEditorWidget::UrlEditorWidget(QGraphicsItem * parent)
       
    34 : QGraphicsTextItem(parent)
       
    35 {
       
    36     // Disable wrapping, force text to be stored and displayed
       
    37     // as a single line.
       
    38 
       
    39     QTextOption textOption = document()->defaultTextOption();
       
    40     textOption.setWrapMode(QTextOption::NoWrap);
       
    41     document()->setDefaultTextOption(textOption);
       
    42 
       
    43     // Enable cursor keys.
       
    44 
       
    45     setTextInteractionFlags(Qt::TextEditorInteraction);
       
    46 
       
    47     // This is needed to initialize m_textLine.
       
    48 
       
    49     setText("");
       
    50 }
       
    51 
       
    52 UrlEditorWidget::~UrlEditorWidget()
       
    53 {
       
    54 }
       
    55 
       
    56 void UrlEditorWidget::setText(const QString & text)
       
    57 {
       
    58     setPlainText(text);
       
    59     m_textLine = document()->begin().layout()->lineForTextPosition(0);
       
    60 }
       
    61 
       
    62 qreal UrlEditorWidget::cursorX()
       
    63 {
       
    64     return m_textLine.cursorToX(textCursor().position());
       
    65 }
       
    66 
       
    67 void UrlEditorWidget::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
       
    68 {
       
    69     // Paint without ugly selection ants (the dashed line that surrounds
       
    70     // the selected text).
       
    71 
       
    72     QStyleOptionGraphicsItem newOption = *option;
       
    73     newOption.state &= (!QStyle::State_Selected | !QStyle::State_HasFocus);
       
    74 
       
    75     painter->save();
       
    76 
       
    77     QGraphicsTextItem::paint(painter, &newOption, widget);
       
    78 
       
    79     painter->restore();
       
    80 }
       
    81 
       
    82 void UrlEditorWidget::keyPressEvent(QKeyEvent * event)
       
    83 {
       
    84     // Signal horizontal cursor movement so UrlSearchSnippet can
       
    85     // implement horizontal scrolling.
       
    86 
       
    87     qreal oldX = cursorX();
       
    88 
       
    89     QGraphicsTextItem::keyPressEvent(event);
       
    90 
       
    91     qreal newX = cursorX();
       
    92 
       
    93     if (newX != oldX) {
       
    94         emit cursorXChanged(newX);
       
    95     }
       
    96 }
       
    97 
       
    98 // Methods for class UrlSearchSnippet
       
    99 
       
   100 UrlSearchSnippet::UrlSearchSnippet(ChromeSnippet * snippet, ChromeWidget * chrome, QGraphicsItem * parent)
       
   101 : NativeChromeItem(snippet, parent)
       
   102 , m_chrome(chrome)
       
   103 , m_percent(0)
       
   104 , m_pendingClearCalls(0)
       
   105 , m_viewPortWidth(0.0)
       
   106 , m_viewPortHeight(0.0)
       
   107 {
       
   108     setFlags(QGraphicsItem::ItemIsMovable);
       
   109 
       
   110     // Extract style information from element CSS.
       
   111 
       
   112     // For border-related properties, we constrain all values (top, left, etc.)
       
   113     // to be the same.  These can be set using the css shorthand (e.g. padding:10px),
       
   114     // but the computed css style will be for the four primitive values (padding-top,
       
   115     // padding-left) etc, which will all be equal.  Hence we just use one of the
       
   116     // computed primitive values (top) to represent the common value.
       
   117 
       
   118     QWebElement we = m_snippet->element();
       
   119 
       
   120     NativeChromeItem::CSSToQColor(
       
   121             we.styleProperty("color", QWebElement::ComputedStyle),
       
   122             m_textColor);
       
   123 
       
   124     NativeChromeItem::CSSToQColor(
       
   125             we.styleProperty("background-color", QWebElement::ComputedStyle),
       
   126             m_backgroundColor);
       
   127 
       
   128     NativeChromeItem::CSSToQColor(
       
   129             we.styleProperty("border-top-color", QWebElement::ComputedStyle),
       
   130             m_borderColor);
       
   131 
       
   132     QString cssPadding = we.styleProperty("padding-top", QWebElement::ComputedStyle);
       
   133     m_padding = cssPadding.remove("px").toInt();
       
   134 
       
   135     QString cssBorder = we.styleProperty("border-top-width", QWebElement::ComputedStyle);
       
   136     m_border = cssBorder.remove("px").toInt();
       
   137 
       
   138     // The viewport clips the editor when text overflows
       
   139 
       
   140     m_viewPort = new QGraphicsWidget(this);
       
   141     m_viewPort->setFlags(QGraphicsItem::ItemClipsChildrenToShape);
       
   142 
       
   143     // The actual text editor item
       
   144 
       
   145     m_editor = new UrlEditorWidget(m_viewPort);
       
   146     m_editor->setDefaultTextColor(m_textColor);
       
   147     m_editor->installEventFilter(this);
       
   148 
       
   149     // Monitor editor cursor position changes for horizontal scrolling.
       
   150 
       
   151     safe_connect(m_editor, SIGNAL(cursorXChanged(qreal)),
       
   152             this, SLOT(makeVisible(qreal)));
       
   153 
       
   154     // Monitor resize events.
       
   155 
       
   156     safe_connect(m_chrome->renderer(), SIGNAL(chromeResized()),
       
   157             this, SLOT(resize()));
       
   158 
       
   159     // Update state as soon as chrome completes loading.
       
   160 
       
   161     safe_connect(m_chrome, SIGNAL(chromeComplete()),
       
   162             this, SLOT(setStarted()));
       
   163 
       
   164     // Monitor page loading.
       
   165 
       
   166     WebPageController * pageController = WebPageController::getSingleton();
       
   167 
       
   168     safe_connect(pageController, SIGNAL(pageUrlChanged(const QString)),
       
   169             this, SLOT(setUrlText(const QString &)));
       
   170 
       
   171     safe_connect(pageController, SIGNAL(pageLoadStarted()),
       
   172             this, SLOT(setStarted()));
       
   173 
       
   174     safe_connect(pageController, SIGNAL(pageLoadProgress(const int)),
       
   175             this, SLOT(setProgress(int)));
       
   176 
       
   177     safe_connect(pageController, SIGNAL(pageLoadFinished(bool)),
       
   178             this, SLOT(setFinished(bool)));
       
   179 
       
   180     // Monitor view changes.
       
   181 
       
   182     ViewController * viewController = chrome->viewController();
       
   183 
       
   184     safe_connect(viewController, SIGNAL(currentViewChanged()),
       
   185             this, SLOT(viewChanged()));
       
   186 }
       
   187 
       
   188 UrlSearchSnippet::~UrlSearchSnippet()
       
   189 {
       
   190 }
       
   191 
       
   192 bool UrlSearchSnippet::eventFilter(QObject * object, QEvent * event)
       
   193 {
       
   194     // Filter editor key events.
       
   195 
       
   196     if (object != m_editor) {
       
   197         return false;
       
   198     }
       
   199 
       
   200     if (event->type() != QEvent::KeyPress) {
       
   201         return false;
       
   202     }
       
   203 
       
   204     QKeyEvent * keyEvent = static_cast<QKeyEvent*>(event);
       
   205 
       
   206     switch (keyEvent->key()) {
       
   207     case Qt::Key_Select:
       
   208     case Qt::Key_Return:
       
   209     case Qt::Key_Enter:
       
   210         // Signal that a carriage return-like key-press happened.
       
   211         emit activated();
       
   212         return true;
       
   213 
       
   214     case Qt::Key_Down:
       
   215     case Qt::Key_Up:
       
   216         // Swallow arrow up/down keys, editor has just one line.
       
   217         return true;
       
   218 
       
   219     default:
       
   220         return false;
       
   221     }
       
   222 }
       
   223 
       
   224 void UrlSearchSnippet::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
       
   225 {
       
   226     // Make sure any required horizontal scrolling happens
       
   227     // before rendering UrlEditorWidget.
       
   228 
       
   229     makeVisible(m_editor->cursorX());
       
   230 
       
   231     NativeChromeItem::paint(painter, option,widget);
       
   232 
       
   233     painter->save();
       
   234 
       
   235     painter->setRenderHint(QPainter::Antialiasing);
       
   236     painter->setBrush(m_backgroundColor);
       
   237 
       
   238     // First, do progress bar.
       
   239 
       
   240     QRectF g = boundingRect();
       
   241     g.setWidth(g.width() * m_percent / 100.0);
       
   242     painter->fillRect(g, QColor::fromRgb(0, 200, 200, 50));
       
   243 
       
   244     // Next, background matte.
       
   245 
       
   246     if (m_border > 0) {
       
   247         QPen pen;
       
   248         pen.setWidth(m_border);
       
   249         pen.setBrush(m_borderColor);
       
   250         painter->setPen(pen);
       
   251     }
       
   252 
       
   253     QPainterPath background;
       
   254     background.addRect(boundingRect());
       
   255     background.addRoundedRect(
       
   256             m_padding,
       
   257             m_padding,
       
   258             m_viewPortWidth,
       
   259             m_viewPortHeight,
       
   260             4,
       
   261             4);
       
   262     painter->drawPath(background);
       
   263 
       
   264     painter->restore();
       
   265 }
       
   266 
       
   267 void UrlSearchSnippet::resizeEvent(QGraphicsSceneResizeEvent * event)
       
   268 {
       
   269     QSizeF size = event->newSize();
       
   270 
       
   271     m_viewPort->resize(size);
       
   272 
       
   273     m_viewPortWidth  = size.width()  - m_padding * 2;
       
   274     m_viewPortHeight = size.height() - m_padding * 2;
       
   275 
       
   276     m_viewPort->setGeometry(
       
   277             m_padding,
       
   278             (size.height() - m_editor->boundingRect().height()) / 2,
       
   279             m_viewPortWidth,
       
   280             m_viewPortHeight);
       
   281 
       
   282     m_editor->setTextWidth(m_viewPortWidth);
       
   283 }
       
   284 
       
   285 void UrlSearchSnippet::resize()
       
   286 {
       
   287     QWebElement we = m_snippet->element();
       
   288 
       
   289     QRectF g = we.geometry();
       
   290 
       
   291     qreal newWidth  = g.width();
       
   292 
       
   293     qreal newHeight = g.height();
       
   294 
       
   295     QGraphicsWidget::resize(newWidth, newHeight);
       
   296 }
       
   297 
       
   298 void UrlSearchSnippet::setUrlText(const QString & text)
       
   299 {
       
   300     m_editor->setText(text);
       
   301     m_editor->setPos(0, m_editor->pos().y());
       
   302 
       
   303     makeVisible(m_editor->cursorX());
       
   304 }
       
   305 
       
   306 void UrlSearchSnippet::setStarted()
       
   307 {
       
   308     // Strictly speaking we should set progress to 0.
       
   309     // But set it higher to give immediate visual feedback
       
   310     // that something is happening.
       
   311 
       
   312     int progress = 0;
       
   313 
       
   314     WebPageController * pageController = WebPageController::getSingleton();
       
   315 
       
   316     if (pageController->isPageLoading()) {
       
   317         progress = 5;
       
   318     }
       
   319 
       
   320     setProgress(progress);
       
   321 }
       
   322 
       
   323 void UrlSearchSnippet::setProgress(int percent)
       
   324 {
       
   325     m_percent = percent;
       
   326     update();
       
   327 }
       
   328 
       
   329 // Wait a half-second before actually clearing the progress bar.
       
   330 //
       
   331 // We have to be careful of the following two use cases:
       
   332 //
       
   333 // 1. Another page starts loading between the call to setFinished()
       
   334 //    and the scheduled call to clearProgress().
       
   335 //
       
   336 //    We don't want to clear the progress bar if another page is
       
   337 //    loading.  WebPageController::isPageLoading() can tell us
       
   338 //    if that is the case.
       
   339 //
       
   340 // 2. Another page finishes loading between the call to setFinished()
       
   341 //    and the scheduled call to clearProgress().  The sequence here is:
       
   342 //
       
   343 //      setFinished(ok) // for URL #1
       
   344 //      setFinished(ok) // for URL #2
       
   345 //      clearProgress() // for URL #1
       
   346 //      clearProgress() // for URL #2
       
   347 //
       
   348 //    We don't want to clear the progress bar in the first call to
       
   349 //    clearProgress() because we want the progress bar to retain its
       
   350 //    appearance for the full timeout period.  We manage this by
       
   351 //    tracking the number of pending calls to clearProgress() and
       
   352 //    only clearing the progress bar when that number becomes 0.
       
   353 
       
   354 void UrlSearchSnippet::setFinished(bool ok)
       
   355 {
       
   356     if (ok) {
       
   357         setProgress(99);
       
   358     }
       
   359 
       
   360     ++m_pendingClearCalls;
       
   361 
       
   362     QTimer::singleShot(500, this, SLOT(clearProgress()));
       
   363 }
       
   364 
       
   365 void UrlSearchSnippet::clearProgress()
       
   366 {
       
   367     --m_pendingClearCalls;
       
   368 
       
   369     if (m_pendingClearCalls > 0) {
       
   370         return;
       
   371     }
       
   372 
       
   373     WebPageController * pageController = WebPageController::getSingleton();
       
   374 
       
   375     if (pageController->isPageLoading()) {
       
   376         return;
       
   377     }
       
   378 
       
   379     setProgress(0);
       
   380 }
       
   381 
       
   382 void UrlSearchSnippet::viewChanged()
       
   383 {
       
   384     WebPageController * pageController = WebPageController::getSingleton();
       
   385 
       
   386     setUrlText(pageController->currentDocUrl());
       
   387 
       
   388     int progress = pageController->loadProgressValue();
       
   389     if (progress >= 100) {
       
   390         progress = 0;
       
   391     }
       
   392     setProgress(progress);
       
   393 }
       
   394 
       
   395 // We divide the viewport into 3 distinct regions:
       
   396 //
       
   397 //
       
   398 //        [ left | middle | right ]
       
   399 //
       
   400 // [ editor, shifted left by editorShift pixels ]
       
   401 //
       
   402 // When a cursor is in the middle section of the viewport we
       
   403 // leave the editor shift unchanged, to preserve stability.
       
   404 //
       
   405 // When a cursor is in the right section or beyond we shift
       
   406 // the editor left until the cursor appears at the border
       
   407 // between the middle and right sections.
       
   408 //
       
   409 // When a cursor is in the left section or beyond we shift
       
   410 // the editor right until the cursor appears at the border
       
   411 // between the left and middle sections.
       
   412 //
       
   413 // We never shift the editor right of the viewport.
       
   414 
       
   415 void UrlSearchSnippet::makeVisible(qreal cursorX)
       
   416 {
       
   417     qreal leftScrollBorder  = 0;
       
   418 
       
   419     qreal rightScrollBorder = m_viewPortWidth - 10;
       
   420 
       
   421     qreal editorShift = -1 * m_editor->pos().x();
       
   422 
       
   423     qreal localX = cursorX - editorShift;
       
   424 
       
   425     if (localX < leftScrollBorder) {
       
   426         // Before left section, scroll right.
       
   427         // In left section, scroll right.
       
   428         qreal shift = qMin(leftScrollBorder - localX, editorShift);
       
   429         m_editor->moveBy(shift, 0);
       
   430         return;
       
   431     }
       
   432 
       
   433     if (localX >= rightScrollBorder) {
       
   434         // In right section, scroll left.
       
   435         // After right section, scroll left.
       
   436         qreal shift = localX - rightScrollBorder;
       
   437         m_editor->moveBy(-shift, 0);
       
   438         return;
       
   439     }
       
   440 
       
   441     // In middle section, no scroll needed.
       
   442     return;
       
   443 }
       
   444 
       
   445 } // namespace GVA