diff -r b0dd75e285d2 -r 0954f5dd2cd0 ginebra2/ContentToolbarSnippet.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ginebra2/ContentToolbarSnippet.cpp Tue Jun 29 00:46:29 2010 -0400 @@ -0,0 +1,632 @@ + +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, version 2.1 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, +* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". +* +* Description: +* This class extends WebChromeContainerSnippet class to hold the +* content view toolbar buttons. Showing/Hiding of the sub-chrome snippets in response to +* the button selection is not entirely done here as we have a hybrid html-native design. +* MostVisited: Show/Hide is handled in handleMVButton. +* Menu: Show is handled in Javascript. Hide is handled here. +* Zoom: Show/Hide is handled here. Zoom action buttons +* Note: Most Visited is native while Menu and Zoom are html based. All three of them need to +* be dismissed if the user taps anywhere else on the screen. Since mv is native, it handles +* all mouse events and dismisses itself. Zoom/Menu are created as PopupChromeItem which receives +* the mouse events in its event filter and emits a signal if the user taps anywhere on the screen +* other than itself. This signal is handled here. +* Sub-chromes are hidden after a specified timeout if there is no user interaction with the +* particular chrome. This class listens to the mouse events of the sub-chromes and +* their children to manage this. +* +*/ + +#include "ContentToolbarSnippet.h" +#include "ContentToolbarChromeItem.h" +#include "mostvisitedsnippet.h" +#include "ViewStack.h" +#include "webpagecontroller.h" +#include "ExternalEventCharm.h" + +#include + + +namespace GVA { + + + ContentToolbarSnippet::ContentToolbarSnippet(const QString& elementId, ChromeWidget * chrome, const QWebElement & element) + : ToolbarSnippet(elementId, chrome, element), + m_middleSnippet(NULL), + m_subChromeSnippet(NULL) + { + + m_type = TOOLBAR_WEB_VIEW; + m_subChromeInactiveTimer = new QTimer(this); + connect(m_subChromeInactiveTimer, SIGNAL(timeout()), this, SLOT(onInactivityTimer())); + + } + + ContentToolbarSnippet::~ContentToolbarSnippet() + { + delete m_subChromeInactiveTimer; + } + + ContentToolbarSnippet * ContentToolbarSnippet::instance(const QString& elementId, ChromeWidget * chrome, const QWebElement & element) + { + ContentToolbarSnippet * that = new ContentToolbarSnippet( elementId, chrome, element ); + that->setChromeWidget( new ContentToolbarChromeItem( that ) ); + return that; + } + + void ContentToolbarSnippet::updateSize(QSize size) { + //qDebug() << "ContentToolbarSnippet::updateSize" << size.width() ; + setWidth(size.width()); + ToolbarSnippet::updateSize(size); + + } + + void ContentToolbarSnippet::updateOwnerArea() { + + + //qDebug() << "ContentToolbarSnippet::updateOwnerArea" << m_chrome->width() ; + setWidth(m_chrome->layout()->size().width()); + ToolbarSnippet::updateOwnerArea(); + + //qDebug() << "------------Relayout "<< elementId() << hidesContent(); + // If hidesContent is true, it means that the snippet is tied to the chrome's layout. Hence, we + // should invalidate and activate the layout here so that the layout and recalculate all + // edges (we don't want to wait for the asynchronous layout request to be handled as + // that would cause the this snippet to be painted in incorrect position before the layoutRequest + // is handled + if (hidesContent() ) { + chrome()->layout()->layout()->invalidate(); + chrome()->layout()->layout()->activate(); + } + } + + void ContentToolbarSnippet::setWidth(int width ){ + + QGraphicsLinearLayout* l = layout(); + + // We are using the width of the first element as the first and last elements are the same width + if (l && l->itemAt(0)) { + + qreal snippetWidth = width -(2 * l->itemAt(0)->geometry().width()); + m_middleSnippet->setLayoutWidth(snippetWidth, true); + + } + + } + + void ContentToolbarSnippet::childAdded(ChromeSnippet* child) { + + addActionInfo(child->elementId()); + } + + void ContentToolbarSnippet::addActionInfo(QString id) { + + ToolbarActions_t* t = new ToolbarActions_t(); + if (id == "BackButtonSnippet" ) { + t->actionId = CONTENT_VIEW_ACTION_BACK; + t->actionName = CONTENT_TOTOLBAR_BACK; + t->normalImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_back.png"; + t->disabledImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_back_disabled.png"; + t->activeImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_back_pressed.png"; + } + else if (id == "ZoomButtonSnippet" ) { + t->actionId = CONTENT_VIEW_ACTION_ZOOM; + t->actionName = CONTENT_TOTOLBAR_ZOOM; + t->normalImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_zoom.png"; + t->disabledImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_zoom_disabled.png"; + t->activeImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_zoom_pressed.png"; + } + else if (id == "MenuButtonSnippet" ) { + t->actionId = CONTENT_VIEW_ACTION_MENU; + t->actionName = CONTENT_TOTOLBAR_MENU; + t->normalImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_menu.png"; + t->disabledImg = ""; + t->activeImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_menu_pressed.png"; + } + else if (id == "MostVisitedButtonSnippet" ) { + t->actionId = CONTENT_VIEW_ACTION_MOSTVISITED; + t->actionName = CONTENT_TOTOLBAR_MOSTVISITED; + t->normalImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_mostvisited.png"; + t->disabledImg = ""; + t->activeImg = ":/chrome/bedrockchrome/toolbar.snippet/icons/icon_mostvisited_pressed.png"; + } + else if (id == "ToggleTBButtonSnippet" ) { + t->actionId = CONTENT_VIEW_ACTION_TOGGLETB; + t->actionName = CONTENT_TOTOLBAR_TOGGLETB; + t->normalImg = TOOLBAR_FULL_TB_TOGGLE_ICON; + t->disabledImg = ""; + t->activeImg = TOOLBAR_FULL_TB_SELECTED_TOGGLE_ICON; + } + t->id = id; + m_actionInfo.append(t); + } + + void ContentToolbarSnippet::addChild(ChromeSnippet* child) { + + WebChromeContainerSnippet * s = dynamic_cast(child); + if (s) { + connect(child, SIGNAL(childAdded(ChromeSnippet*)), this, SLOT(childAdded(ChromeSnippet*))); + m_middleSnippet = s; + // Set the snippet width + setWidth(m_chrome->layout()->size().width()); + } + else { + addActionInfo(child->elementId()); + } + + WebChromeContainerSnippet::addChild(child); + + } + + void ContentToolbarSnippet::onChromeComplete() { + + ChromeItem * item = static_cast(widget()); + manageChildren(item); + + // Connect back to initialLayoutCompleted signal + ActionButtonSnippet * button = getActionButtonSnippet(CONTENT_VIEW_ACTION_BACK); + connect(WebPageController::getSingleton(), SIGNAL(initialLayoutCompleted()), button->widget(), SLOT(onHidden())); + connect(WebPageController::getSingleton(), SIGNAL(loadFinished(bool)), button->widget(), SLOT(onHidden())); + + connect(m_chrome, SIGNAL(aspectChanged(int)) , this, SLOT(onAspectChanged())); + + } + + void ContentToolbarSnippet::manageChildren(ChromeItem * it) { + + + /*! + * Content toolbar needs to listen to mouse events of each of the toolbar + * buttons as well as the snippets that pop-up on selecting these + * buttons. Some of these buttons are not direct children of content toolbar + * but placed within another container. Also, the pop-ups are not directly + * linked to content toolbar. Here, all these snippets are determined to connect to the + * widget's mosueEvent signal + */ + QList items = it->childItems(); + //qDebug() << " ------------------- Num of children " << items.count(); + for (int i = 0; i < items.count() ; i++) { + + // Can't use qobject_cast since QGraphicsWdiget is not a QObject + ChromeItem * item = dynamic_cast(items.at(i)); + if (item ) { + + WebChromeContainerSnippet * s = dynamic_cast(item->snippet()); + // If it is a container, need to connect to it's child items, so recurse + if (s ) { + manageChildren(item); + } + else { // Individual item + //qDebug() << "Item: " << item->snippet()->elementId(); + ContentToolbarChromeItem * w = static_cast(widget()); + if (w->autoHideToolbar()) { + // Connect to the snippet's mouse event to cancel auto-timeout + connect(item, SIGNAL(mouseEvent(QEvent::Type)), w, SLOT(onSnippetMouseEvent(QEvent::Type))); + } + + setAction(item->snippet()); + manageLink(item); + } + } + } + + } + + void ContentToolbarSnippet::manageLink(ChromeItem * item) { + + // If it has a linked snippet, connect to it's mouse event and also + // to it's children's mouse events + ChromeSnippet * link = item->snippet()->linkedSnippet(); + if (link) { + ChromeItem* it = dynamic_cast (link->widget()); + if (it ) { + // Connect to linked snippet's mouse events to control the sub-chrome + connect(it, SIGNAL(mouseEvent(QEvent::Type)), this, SLOT(onSnippetMouseEvent(QEvent::Type))); + + // Save the linked children to be used later for hiding + ContentToolbarChromeItem * w = static_cast(widget()); + w->addLinkedChild(link); + + // In case it has children, connect to their mouse events as well + QList childItems = it->childItems(); + int count = childItems.count(); + + // If the linked snippet has children that are widgets themselves, listen to their + // mouse events as well. + for (int i = 0; i < count ; i++) { + ChromeItem * child = dynamic_cast(childItems.at(i)); + + // To control sub-chrome timer + connect(child, SIGNAL(mouseEvent(QEvent::Type)), this, SLOT(onSnippetMouseEvent(QEvent::Type))); + } + } + } + } + + + void ContentToolbarSnippet::setAction(ChromeSnippet * s) { + + //qDebug() << "setAction: " << s->elementId(); + ToolbarSnippet::setAction(s); + ActionButtonSnippet * button = static_cast (s); + + // Set selected on press to false here so that we can control when to + // change action button icon state + button->setActiveOnPress(false); + button->getDefaultAction()->setCheckable(true); + + ChromeItem * item = static_cast(s->widget()); + connect(item, SIGNAL(mouseEvent( QEvent::Type )), this, SLOT(onMouseEvent(QEvent::Type))); + + int index = getIndex(s); + + if (index != -1) { + QAction * action = button->getDefaultAction(); + ToolbarActions_t * t = m_actionInfo.at(index); + + switch (t->actionId) { + + case CONTENT_VIEW_ACTION_ZOOM: + addZoomButton(action, button); + break; + case CONTENT_VIEW_ACTION_MENU: + addMenuButton(action, button); + break; + case CONTENT_VIEW_ACTION_MOSTVISITED: + addMostVisitedButton(action, button); + break; + case CONTENT_VIEW_ACTION_TOGGLETB: + addToggleTBButton(action, button); + break; + default: + break; + } + } + + } + + void ContentToolbarSnippet::addZoomButton(QAction * action, ActionButtonSnippet* button) { + + assert(action); + assert(button); + connect(action, SIGNAL(triggered()), this, SLOT(handleZoomButton())); + + + // Connect to hide and show signals of the linked snippet + connectHideShowSignals(button); + connect( button->linkedSnippet(), SIGNAL(externalMouseEvent(QEvent *, const QString , const QString )), this, SLOT(onExternalMouse(QEvent *, const QString , const QString))); + + + } + + void ContentToolbarSnippet::addMenuButton(QAction * action, ActionButtonSnippet* button) { + + assert(action); + assert(button); + + connect(action, SIGNAL(triggered()), this, SLOT(handleMenuButton())); + + // Connect to hide and show signals of the linked snippet + connectHideShowSignals(button); + connect( button->linkedSnippet(), SIGNAL(externalMouseEvent(QEvent *, const QString , const QString )), this, SLOT(onExternalMouse(QEvent *, const QString , const QString))); + + } + + void ContentToolbarSnippet::addMostVisitedButton(QAction * action, ActionButtonSnippet* button) { + + assert(action); + assert(button); + + connect(action, SIGNAL(triggered()), this, SLOT(handleMVButton())); + + // Connect to hide and show signals of the linked snippet + connectHideShowSignals(button); + } + + void ContentToolbarSnippet::addToggleTBButton(QAction * action, ActionButtonSnippet* button) { + + assert(action); + assert(button); + + connect(action, SIGNAL(triggered()), this, SLOT(handleToggleTBButton())); + } + + + void ContentToolbarSnippet::handleZoomButton() { + + ActionButtonSnippet * button = getActionButtonSnippet(CONTENT_VIEW_ACTION_ZOOM); + ChromeSnippet * zoomSnippet = button->linkedSnippet(); + + + if (zoomSnippet->isVisible() ) { + zoomSnippet->hide(); + } + else { + hideOtherPopups(button->elementId()); + zoomSnippet->show(); + + // Show the action buttons. We can get the snippets by their id or do this to show them. + ChromeItem* it = dynamic_cast (zoomSnippet->widget()); + QList childItems = it->childItems(); + int count = childItems.count(); + + for (int i = 0; i < count ; i++) { + ChromeItem * child = dynamic_cast(childItems.at(i)); + child->snippet()->show(); + + } + } + + } + + void ContentToolbarSnippet::handleMenuButton() { + + ActionButtonSnippet * button = getActionButtonSnippet(CONTENT_VIEW_ACTION_MENU); + ChromeSnippet * menuSnippet = button->linkedSnippet(); + + if (!menuSnippet->isVisible() ) { + + emit menuButtonSelected(); + hideOtherPopups(button->elementId()); + + } + else { + menuSnippet->hide(); + } + + } + + void ContentToolbarSnippet::handleMVButton() { + + //qDebug() << "ContentToolbarSnippet::handleMVButton() "; + ActionButtonSnippet * button = getActionButtonSnippet(CONTENT_VIEW_ACTION_MOSTVISITED); + hideOtherPopups(button->elementId()); + button->linkedSnippet()->toggleVisibility(); + } + + void ContentToolbarSnippet::handleToggleTBButton() { + ContentToolbarChromeItem * w = static_cast(widget()); + w->toggleMiddleSnippet(); + } + + + void ContentToolbarSnippet::hideOtherPopups(QString id) { + + + for (int i = 0; i < m_actionInfo.size() ; i++ ) { + + ToolbarActions_t * t = m_actionInfo.at(i); + if (t->id != id ) { + ActionButtonSnippet * buttonSnippet = static_cast ( m_chrome->getSnippet(t->id)); + ChromeSnippet * linkedSnippet = buttonSnippet->linkedSnippet(); + + // If there is another sub-chrome visible, hide it + if (linkedSnippet ) { + if ( linkedSnippet->isVisible()) { + linkedSnippet->hide(); + } + else { + // When the user selects the menu button, menu is displayed after certain timeout + // and it is possible that the user can select another button. So cancel it if the + // button is 'checked' if we get another action trigger + + //qDebug() << "ContentToolbarSnippet::hideOtherPopups: " << id << "Button: " << t->id << buttonSnippet->isChecked(); + + if ( (buttonSnippet->elementId() == "MenuButtonSnippet" ) && (buttonSnippet->isChecked() )) { + emit menuButtonCanceled(); + buttonSnippet->updateButtonState(false); + } + } + } + } + + } + + + } + + void ContentToolbarSnippet::connectHideShowSignals(ActionButtonSnippet * button) { + + // Connect to hide and show signals of the linked snippet + ChromeSnippet * snippet = button->linkedSnippet(); + ActionButton * actionButton = static_cast(button->widget()); + connect(snippet, SIGNAL(hidden()), actionButton, SLOT(onHidden())); + connect(snippet, SIGNAL(shown()), actionButton, SLOT(onShown())); + + connect(snippet, SIGNAL(hidden()), this, SLOT(onHidden())); + connect(snippet, SIGNAL(shown()), this, SLOT(onShown())); + + } + + void ContentToolbarSnippet::onAspectChanged( ) { + + // Hide any pop-up that is visible + hideOtherPopups(QString()); + } + + void ContentToolbarSnippet::onSnippetMouseEvent( QEvent::Type type) { + + //qDebug() << "ContentToolbarSnippet::onSnippetMouseEvent : Type" << type; + if (type == QEvent::GraphicsSceneMousePress || type == QEvent::MouseButtonPress ) { + resetTimer(false); + } + else if (type == QEvent::GraphicsSceneMouseRelease || type == QEvent::MouseButtonRelease ) { + resetTimer(); + } + } + + void ContentToolbarSnippet::onMouseEvent( QEvent::Type type) { + + ActionButton* button = static_cast ( sender()); + ActionButtonSnippet * buttonSnippet = static_cast( button->snippet()); + ChromeSnippet * linkedSnippet = buttonSnippet->linkedSnippet(); + //qDebug() << "ContentToolbarSnippet::onMouseEvent : Button : " << buttonSnippet->elementId() << " type: " << type ; + + // Set the action button state to active so that we can show a selected image before the + // action is acted upon + if ( (button->defaultAction()->isEnabled() && type == QEvent::GraphicsSceneMousePress ) || + (button->defaultAction()->isEnabled() && type == QEvent::GraphicsSceneMouseDoubleClick )) { + + // Set active flag if there is no linked snippet (the button acts as toggle if it + // has a linked snippet. If there is linked snippet, set active flag if the linked snippet + // is not visible + if (!linkedSnippet || (linkedSnippet && (!linkedSnippet->isVisible() ))) { + buttonSnippet->setActive(true); + } + } + } + + void ContentToolbarSnippet::onHidden() { + + ChromeSnippet * snippet = static_cast (sender()); + //qDebug() << "ContentToolbarSnippet::onHidden" << snippet->elementId(); + if (snippet == m_subChromeSnippet ) { + + //qDebug() << "ContentToolbarSnippet::onHidden hide shown snippet" << snippet->elementId(); + resetTimer(false); + m_subChromeSnippet = NULL; + } + + } + + void ContentToolbarSnippet::onShown() { + + // If one sub-chrome is being displayed when another is requested to be launched by the user, to avoid + //depending on the order of receiving hidden and shown signals for each of those, we save the snippet + // being shown and then later when hidden signal is received, the sender is compared to the + // snippet for which we started the timer so that the timer is started and stopped for the + // correct snippet. If 'shown' signal for the second is received before hidden for the second, the timer + // is stopped and restarted and the sub-chrome snippet is set to the new one. When 'hidden' is received + // for the first, it is ignored as it doesn't match our saved snippet value. + m_subChromeSnippet = static_cast (sender()); + //qDebug() << "ContentToolbarSnippet::onShown" << m_subChromeSnippet->elementId(); + + resetTimer(); + + } + + + void ContentToolbarSnippet::onInactivityTimer() { + + //qDebug() << "ContentToolbarSnippet::onInactivityTimer" << m_subChromeSnippet->elementId(); + if (m_subChromeSnippet->elementId() == "MostVisitedViewId" ) { + MostVisitedSnippet * mv = static_cast(m_subChromeSnippet); + mv->close(); + // Stop the timer here as there is animation to complete before hide is received + resetTimer(false); + m_subChromeSnippet = NULL; + } + else { + + // Hide the snippet. onHidden slot will be called when the snippet is hidden + // and there we will stop the timer and reset m_subChromeSnippet + m_subChromeSnippet->hide(); + } + } + + + void ContentToolbarSnippet::resetTimer(bool start) { + + int duration = TOOLBAR_POPUP_INACTIVITY_DURATION; + if (m_subChromeInactiveTimer->isActive() ) { + //qDebug() << " Stop timer for " << m_subChromeSnippet->elementId(); + m_subChromeInactiveTimer->stop(); + } + + if (start) { + if (m_subChromeSnippet->elementId() == "ZoomBarId" ) { + duration = TOOLBAR_ZOOMBAR_INACTIVITY_DURATION; + } + //qDebug() << " Start timer for " << m_subChromeSnippet->elementId(); + m_subChromeInactiveTimer->start(duration); + } + + } + void ContentToolbarSnippet::onExternalMouse( QEvent * ev , + const QString & name, + const QString & description) { + + Q_UNUSED(description); + ChromeSnippet * snippet = static_cast (sender()); + QGraphicsSceneMouseEvent * me = static_cast(ev); + ChromeSnippet * linkedButton = getLinkedButton(snippet); + + // For sub-chromes like zoom and menu, we get mouse events anywhere on the + // screen including the ones on the corresponding button on the toolbar. Hide + // the sub-chrome only if the mouse press is anywhere other than the + // corresponding button + if (linkedButton ) { + ChromeItem * item = static_cast(linkedButton->widget()); + if (item && item->sceneBoundingRect().contains(me->scenePos() )) { + return; + } + } + + if (name == ExternalEventCharm::s_mouseClick) { + snippet->hide(); + } + + + } + + +void ContentToolbarSnippet::handleToolbarStateChange(ContentToolbarState state){ + + + ActionButtonSnippet * button = getActionButtonSnippet(CONTENT_VIEW_ACTION_TOGGLETB); + + // set the appopriate icons based on the state + + if (state != CONTENT_TOOLBAR_STATE_INVALID ) { + if (state == CONTENT_TOOLBAR_STATE_PARTIAL ) { + button->setIcon(TOOLBAR_PARTIAL_TB_TOGGLE_ICON); + button->setActiveIcon(TOOLBAR_PARTIAL_TB_SELECTED_TOGGLE_ICON); + } + else if (state == CONTENT_TOOLBAR_STATE_FULL ) { + button->setIcon(TOOLBAR_FULL_TB_TOGGLE_ICON); + button->setActiveIcon(TOOLBAR_FULL_TB_SELECTED_TOGGLE_ICON); + + } + // Also reset the button state if the change in state was triggered by toggle-button selection + button->updateButtonState(false); + + } +} + +ChromeSnippet* ContentToolbarSnippet::getLinkedButton(ChromeSnippet * snippet ) { + + ChromeSnippet * linkedButton = NULL; + for (int i = 0; i < m_actionInfo.size() ; i++ ) { + ToolbarActions_t * t = m_actionInfo.at(i); + ChromeSnippet * s = getActionButtonSnippet (t->actionId) ; + if (s->linkedSnippet() && s->linkedSnippet()->elementId() == snippet->elementId() ) { + linkedButton = s; + break; + } + + } + return linkedButton; + + +} + +} // end of namespace GVA + +