src/hbcore/gui/hbtoolbarextension.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
--- /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 <hbeffect.h>
+#include <hbeffectinternal_p.h>
+bool HbToolBarExtensionPrivate::extensionEffectsLoaded = false;
+#endif
+
+#include <QDebug>
+#include <QGraphicsGridLayout>
+#include <QEventLoop>
+#include <QPainter>
+#include <QGraphicsLinearLayout> 
+
+/*!
+    @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<HbAction *>( 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<HbToolButton *>(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<QActionEvent *>(event) );
+        return true;
+    } else if ( event->type() == QEvent::ActionRemoved ) {
+        d->actionRemoved( static_cast<QActionEvent *>(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 &params )
+{    
+    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"