diff -r 000000000000 -r 16d8024aca5e src/hbcore/gui/hbtoolbarextension.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hbcore/gui/hbtoolbarextension.cpp Mon Apr 19 14:02:13 2010 +0300 @@ -0,0 +1,495 @@ +/**************************************************************************** +** +** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (developer.feedback@nokia.com) +** +** This file is part of the HbCore module of the UI Extensions for Mobile. +** +** GNU Lesser General Public License Usage +** 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 developer.feedback@nokia.com. +** +****************************************************************************/ + +#include "hbtoolbarextension.h" +#include "hbtoolbarextension_p.h" +#include "hbaction.h" +#include "hbtoolbutton.h" +#include "hbtoolbutton_p.h" +#include "hbdialog_p.h" +#include "hbdeviceprofile.h" +#include "hbtoolbar_p.h" +#include "hbmainwindow.h" +#ifdef HB_EFFECTS +#include +#include +bool HbToolBarExtensionPrivate::extensionEffectsLoaded = false; +#endif + +#include +#include +#include +#include +#include + +/*! + @stable + @hbcore + \class HbToolBarExtension + + \brief HbToolBarExtension is a popup style component that adds + extra functionality to an HbToolBar. A toolbar can contain more + than one toolbar extension. An extension popup is opened when a + toolbar button with associated with the extension is triggered. + + A toolbar extension uses the QGraphicsWidget action API to manage + buttons. In addition the HbDialog API can be used to fill the + extension popup with custom widgets (e.g. list or line edit). If + custom content widget is set, buttons generated based on actions + will not be visible. + + An example of how to add a toolbar extension button to the toolbar: + \snippet{ultimatecodesnippet/ultimatecodesnippet.cpp,27} +*/ + +/*! + \reimp + \fn int HbToolBarExtension::type() const + */ + +HbToolBarExtensionPrivate::HbToolBarExtensionPrivate() : + HbDialogPrivate(), + mToolButtons(), + mLayout(0), + extensionAction(0), + mAlignment(Qt::AlignTop), + mDefaultContentWidget(false), + // default values, in case CSS parsing fails + mMargins(0), + mRowsPortrait(4), + mRowsLandscape(3), + mColsPortrait(3), + mColsLandscape(4), + lazyInitDone(false), + // + mExtendedButton(0), + mToolBar(0) +{ +} + +HbToolBarExtensionPrivate::~HbToolBarExtensionPrivate() +{ +} + +void HbToolBarExtensionPrivate::init() +{ + Q_Q(HbToolBarExtension); + extensionAction = new HbAction(q); + extensionAction->setToolBarExtension(q); + q->setTimeout(HbDialog::NoTimeout); + q->setDismissPolicy(HbPopup::TapOutside); + q->setBackgroundFaded(false); + q->setFlag(QGraphicsItem::ItemClipsChildrenToShape); +} + +void HbToolBarExtensionPrivate::doLazyInit() +{ + Q_Q(HbToolBarExtension); + if ( !lazyInitDone ) { + q->setBackgroundItem( HbStyle::P_ToolBarExtension_background ); +#ifdef HB_EFFECTS + if (!extensionEffectsLoaded){ + HbEffectInternal::add("HB_TBE", "tbe_button_click", "clicked"); + extensionEffectsLoaded = true; + } +#endif + lazyInitDone = true; + } +} + +void HbToolBarExtensionPrivate::initialiseContent() +{ + Q_Q(HbToolBarExtension); + + QGraphicsWidget *tbeContentWidget = q->contentWidget(); + + if ( !tbeContentWidget ) { + tbeContentWidget = new QGraphicsWidget(q); + q->setContentWidget( tbeContentWidget ); + mDefaultContentWidget = true; + } +} + +/*! + Creates a new grid layout and populates tool buttons into it. + */ +void HbToolBarExtensionPrivate::doLayout() +{ + Q_Q(HbToolBarExtension); + if (!q->mainWindow() ) return; // workaround unittest + + int columns( q->mainWindow()->orientation() == Qt::Vertical ? + mColsPortrait : mColsLandscape ); + int maxRow( q->mainWindow()->orientation() == Qt::Vertical ? + mRowsPortrait : mRowsLandscape ); + int column (0); + int row(0); + initialiseContent(); + + if (!mDefaultContentWidget) + return; + + foreach (HbToolButton* button, mToolButtons) { + button->setVisible(button->action()->isVisible()); + } + + mLayout = new QGraphicsGridLayout(); + mLayout->setContentsMargins( mMargins, mMargins, mMargins, mMargins ); + mLayout->setSpacing(0.0); // if non zero spacing needed, add to css + for ( int i(0), j(0), ie(mToolButtons.count()); i < ie; ++i ) { + HbToolButton *button = mToolButtons.at(i); + if ( button->action()->isVisible() ) { + // Calculate the row and column indices + column = ( j % columns ); + row = ( (j - column) / columns ); + if ( row >= maxRow ) { + qWarning() << "Too many items in extension!"; + } + HbToolButtonPrivate::d_ptr(button)->setBackgroundVisible(false); + mLayout->addItem( button, row, column ); + ++j; + } + } + q->contentWidget()->setLayout(mLayout); +} + +void HbToolBarExtensionPrivate::placeToolBarExtension() +{ + Q_Q(HbToolBarExtension); + + if (mExtendedButton) { + if (mAlignment == Qt::AlignLeft) { + QPointF position = QPointF(mExtendedButton->scenePos().x(), + mExtendedButton->scenePos().y() + + (mExtendedButton->geometry().height()/2)); + q->setPreferredPos(position, HbPopup::RightEdgeCenter); + } else if (mAlignment == Qt::AlignRight) { + QPointF position = QPointF(mExtendedButton->scenePos().x() + + (mExtendedButton->geometry().width()), + mExtendedButton->scenePos().y() + + (mExtendedButton->geometry().height()/2)); + q->setPreferredPos(position, HbPopup::LeftEdgeCenter); + } else if (mAlignment == Qt::AlignTop) { + QPointF position = QPointF(mExtendedButton->scenePos().x() + + (mExtendedButton->geometry().width()/2), + mExtendedButton->scenePos().y()); + q->setPreferredPos(position, HbPopup::BottomEdgeCenter); + } + } +} + +void HbToolBarExtensionPrivate::actionAdded( QActionEvent *event ) +{ + Q_Q(HbToolBarExtension); + + HbAction *action = qobject_cast( event->action() ); + + if (action) { + HbToolButton *button = new HbToolButton(action, q->contentWidget()); + + if (!button->action()->icon().isNull()) { + if (button->action()->text().isEmpty()) { + button->setToolButtonStyle(HbToolButton::ToolButtonIcon); + } else { + button->setToolButtonStyle(HbToolButton::ToolButtonTextAndIcon); + } + } else { + button->setToolButtonStyle(HbToolButton::ToolButtonText); + } + + button->setProperty("toolbutton_extension_layout", true); + button->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, + QSizePolicy::Preferred) ); + + // Find out index where to insert button + int index = q->actions().indexOf( event->action() ); + + mToolButtons.insert( index, button ); + + q->connect(button, SIGNAL(clicked()), q, SLOT(_q_animateButtonClicked())); + q->connect(action, SIGNAL(triggered()), q, SLOT(close())); + + if (contentWidget){ + doLayout(); + } + } else { + qWarning() << "Use HbAction instead of QAction!"; + } +} + +void HbToolBarExtensionPrivate::actionRemoved( QActionEvent *event ) +{ + for ( int i(0); i < mToolButtons.count(); ++i ) { + HbToolButton *button = mToolButtons.at(i); + if ( button->action() == event->action() ) { + mToolButtons.removeAt(i); + if (contentWidget) { + mLayout->removeAt(i); + doLayout(); + } + delete button; + return; + } + } +} + +void HbToolBarExtensionPrivate::actionChanged() +{ + if (contentWidget) { + doLayout(); // for action()->setVisible(visible) support + } +} + +void HbToolBarExtensionPrivate::setAlignment(Qt::Alignment alignment) +{ + mAlignment = alignment; +} + +void HbToolBarExtensionPrivate::setExtensionAction(HbAction *action) +{ + Q_Q(HbToolBarExtension); + if (extensionAction == action) { + return; + } + if (extensionAction) { + delete extensionAction; + } + extensionAction = action; + extensionAction->setToolBarExtension(q); + +} + +void HbToolBarExtensionPrivate::_q_orientationChanged() +{ + Q_Q(HbToolBarExtension); + if (mToolBar) { + if (mToolBar->orientation() == Qt::Horizontal) { + HbToolBarExtensionPrivate::d_ptr(q)->setAlignment(Qt::AlignTop); + } else if (mToolBar->orientation() == Qt::Vertical + && q->layoutDirection() == Qt::LeftToRight) { + HbToolBarExtensionPrivate::d_ptr(q)->setAlignment(Qt::AlignLeft); + } else { + HbToolBarExtensionPrivate::d_ptr(q)->setAlignment(Qt::AlignRight); + } + } + doLayout(); +} + +void HbToolBarExtensionPrivate::_q_animateButtonClicked() +{ +#ifdef HB_EFFECTS + Q_Q(HbToolBarExtension); + HbToolButton *button = static_cast(q->sender()); + if (button) { + HbEffect::start(button, "TBEButtonClicked", "clicked"); + } +#endif +} + +// ======== MEMBER FUNCTIONS ======== + +/*! + Constructs a new HbToolBarExtension. \a parent graphics item can be set. + */ +HbToolBarExtension::HbToolBarExtension( QGraphicsItem *parent ) : + HbDialog(*new HbToolBarExtensionPrivate(), parent) +{ + Q_D(HbToolBarExtension); + d->q_ptr = this; + + d->init(); +} + +/*! + Destructor. + */ +HbToolBarExtension::~HbToolBarExtension() +{ +} + +/*! + \overload + + Creates a new action with the given \a text. + This action is added to the end of the toolbar extension. + TODO: If the grid is already full, this call will be ignored. + TODO: Find a way to notificate the caller. +*/ +HbAction *HbToolBarExtension::addAction( const QString &text ) +{ + HbAction *action = new HbAction( text, this ); + addAction(action); + return action; +} + +/*! + \overload + + Creates a new action with the given \a icon and \a text. + This action is added to the end of the toolbar extension. + TODO: If the grid is already full, this call will be ignored. + TODO: Find a way to notificate the caller. +*/ +HbAction *HbToolBarExtension::addAction( const HbIcon &icon, + const QString &text ) +{ + HbAction *action = new HbAction( icon, text, this ); + addAction(action); + return action; +} + +/*! + \overload + + Creates a new action with the given \a text. + This action is added to the end of the toolbar extension. + TODO: If the grid is already full, this call will be ignored. + The action's \link HbAction::triggered() + triggered()\endlink signal is connected to \a member in \a + receiver. + TODO: Find a way to notificate the caller. +*/ +HbAction *HbToolBarExtension::addAction( const QString &text, + const QObject *receiver, + const char *member ) +{ + HbAction *action = new HbAction( text, this ); + QObject::connect( action, SIGNAL( triggered(bool) ), receiver, member ); + addAction(action); + return action; +} + +/*! + \overload + + Creates a new action with the given \a icon and \a text. + This action is added to the end of the toolbar extension. + TODO: If the grid is already full, this call will be ignored. + The action's \link HbAction::triggered() + triggered()\endlink signal is connected to \a member in \a + receiver. + TODO: Find a way to notificate the caller. +*/ +HbAction *HbToolBarExtension::addAction( const HbIcon &icon, + const QString &text, + const QObject *receiver, + const char *member ) +{ + HbAction *action = new HbAction( icon, text, this ); + QObject::connect( action, SIGNAL( triggered(bool) ), receiver, member ); + addAction(action); + return action; +} + +/*! + Returns the action associated with this extension. + */ +HbAction *HbToolBarExtension::extensionAction() const +{ + Q_D( const HbToolBarExtension ); + return d->extensionAction; +} + +/*! + Protected constructor. +*/ +HbToolBarExtension::HbToolBarExtension( HbToolBarExtensionPrivate &dd, QGraphicsItem *parent ) : + HbDialog( dd, parent ) +{ +} + +/*! + \reimp + */ +bool HbToolBarExtension::event( QEvent *event ) +{ + Q_D( HbToolBarExtension ); + if ( event->type() == QEvent::ActionAdded ) { + d->actionAdded( static_cast(event) ); + return true; + } else if ( event->type() == QEvent::ActionRemoved ) { + d->actionRemoved( static_cast(event) ); + return true; + } else if (event->type() == QEvent::ActionChanged ) { + d->actionChanged(); + return true; + } else if ( event->type() == QEvent::GraphicsSceneResize ) { + d->doLayout(); + // fall trough + } + return HbDialog::event(event); +} + +void HbToolBarExtension::polish( HbStyleParameters ¶ms ) +{ + Q_D(HbToolBarExtension); + d->doLazyInit(); + const QString Margins = "content-margins"; + const QString RowsPortrait = "max-rows-portrait"; + const QString RowsLandscape = "max-rows-landscape"; + const QString ColsPortrait = "max-columns-portrait"; + const QString ColsLandscape = "max-columns-landscape"; + + params.addParameter( Margins ); + params.addParameter( RowsPortrait ); + params.addParameter( RowsLandscape ); + params.addParameter( ColsPortrait ); + params.addParameter( ColsLandscape ); + d->initialiseContent(); + if (d->mDefaultContentWidget) { + QGraphicsWidget *tbeContentWidget = contentWidget(); + style()->setItemName( tbeContentWidget, "HbToolBarExtension" ); + HbDialog::polish(params); + if ( params.value( Margins ).isValid() + && params.value( RowsPortrait ).isValid() + && params.value( RowsLandscape ).isValid() + && params.value( ColsPortrait ).isValid() + && params.value( ColsLandscape ).isValid() ) { + d->mMargins = params.value( Margins ).toReal(); + d->mRowsPortrait = params.value( RowsPortrait ).toInt(); + d->mRowsLandscape = params.value( RowsLandscape ).toInt(); + d->mColsPortrait = params.value( ColsPortrait ).toInt(); + d->mColsLandscape = params.value( ColsLandscape ).toInt(); + d->doLayout(); + } + } else { + HbDialog::polish(params); + } +} + +QVariant HbToolBarExtension::itemChange(GraphicsItemChange change, + const QVariant &value) +{ + Q_D(HbToolBarExtension); + if (change == QGraphicsItem::ItemVisibleHasChanged) { + if (value.toBool() == true) { + d->placeToolBarExtension(); + } + } + + return HbDialog::itemChange(change, value); +} + +#include "moc_hbtoolbarextension.cpp"