src/hbcore/gui/hbtoolbarextension.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbCore module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 
       
    26 #include "hbtoolbarextension.h"
       
    27 #include "hbtoolbarextension_p.h"
       
    28 #include "hbaction.h"
       
    29 #include "hbtoolbutton.h"
       
    30 #include "hbtoolbutton_p.h"
       
    31 #include "hbdialog_p.h"
       
    32 #include "hbdeviceprofile.h"
       
    33 #include "hbtoolbar_p.h"
       
    34 #include "hbmainwindow.h"
       
    35 #ifdef HB_EFFECTS
       
    36 #include <hbeffect.h>
       
    37 #include <hbeffectinternal_p.h>
       
    38 bool HbToolBarExtensionPrivate::extensionEffectsLoaded = false;
       
    39 #endif
       
    40 
       
    41 #include <QDebug>
       
    42 #include <QGraphicsGridLayout>
       
    43 #include <QEventLoop>
       
    44 #include <QPainter>
       
    45 #include <QGraphicsLinearLayout> 
       
    46 
       
    47 /*!
       
    48     @stable
       
    49     @hbcore
       
    50     \class HbToolBarExtension
       
    51 
       
    52     \brief HbToolBarExtension is a popup style component that adds
       
    53     extra functionality to an HbToolBar. A toolbar can contain more
       
    54     than one toolbar extension.  An extension popup is opened when a
       
    55     toolbar button with associated with the extension is triggered.
       
    56 
       
    57     A toolbar extension uses the QGraphicsWidget action API to manage
       
    58     buttons. In addition the HbDialog API can be used to fill the
       
    59     extension popup with custom widgets (e.g.  list or line edit). If
       
    60     custom content widget is set, buttons generated based on actions
       
    61     will not be visible.
       
    62 
       
    63     An example of how to add a toolbar extension button to the toolbar:
       
    64     \snippet{ultimatecodesnippet/ultimatecodesnippet.cpp,27}
       
    65 */
       
    66 
       
    67 /*!
       
    68     \reimp
       
    69     \fn int HbToolBarExtension::type() const
       
    70  */
       
    71 
       
    72 HbToolBarExtensionPrivate::HbToolBarExtensionPrivate() :
       
    73         HbDialogPrivate(),
       
    74         mToolButtons(),
       
    75         mLayout(0),
       
    76         extensionAction(0),
       
    77         mAlignment(Qt::AlignTop),
       
    78         mDefaultContentWidget(false),
       
    79         // default values, in case CSS parsing fails
       
    80         mMargins(0),
       
    81         mRowsPortrait(4),
       
    82         mRowsLandscape(3),
       
    83         mColsPortrait(3),
       
    84         mColsLandscape(4),
       
    85         lazyInitDone(false),
       
    86         //
       
    87         mExtendedButton(0),
       
    88         mToolBar(0)
       
    89 {
       
    90 }
       
    91 
       
    92 HbToolBarExtensionPrivate::~HbToolBarExtensionPrivate()
       
    93 {
       
    94 }
       
    95 
       
    96 void HbToolBarExtensionPrivate::init()
       
    97 {
       
    98     Q_Q(HbToolBarExtension);
       
    99     extensionAction = new HbAction(q);
       
   100     extensionAction->setToolBarExtension(q);
       
   101     q->setTimeout(HbDialog::NoTimeout);
       
   102     q->setDismissPolicy(HbPopup::TapOutside);
       
   103     q->setBackgroundFaded(false);
       
   104     q->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
       
   105 }
       
   106 
       
   107 void HbToolBarExtensionPrivate::doLazyInit()
       
   108 {
       
   109     Q_Q(HbToolBarExtension);
       
   110     if ( !lazyInitDone ) {
       
   111         q->setBackgroundItem( HbStyle::P_ToolBarExtension_background );
       
   112 #ifdef HB_EFFECTS
       
   113         if (!extensionEffectsLoaded){
       
   114             HbEffectInternal::add("HB_TBE", "tbe_button_click", "clicked");
       
   115             extensionEffectsLoaded = true;
       
   116         }
       
   117 #endif
       
   118         lazyInitDone = true;
       
   119     }
       
   120 }
       
   121 
       
   122 void HbToolBarExtensionPrivate::initialiseContent()
       
   123 {
       
   124     Q_Q(HbToolBarExtension);
       
   125 
       
   126     QGraphicsWidget *tbeContentWidget = q->contentWidget();
       
   127 
       
   128     if ( !tbeContentWidget ) {
       
   129         tbeContentWidget = new QGraphicsWidget(q);
       
   130         q->setContentWidget( tbeContentWidget );
       
   131         mDefaultContentWidget = true;
       
   132     }
       
   133 }
       
   134 
       
   135 /*!
       
   136     Creates a new grid layout and populates tool buttons into it.
       
   137  */
       
   138 void HbToolBarExtensionPrivate::doLayout()
       
   139 {
       
   140     Q_Q(HbToolBarExtension);
       
   141     if (!q->mainWindow() ) return;  // workaround unittest
       
   142 
       
   143     int columns( q->mainWindow()->orientation() == Qt::Vertical ? 
       
   144                  mColsPortrait : mColsLandscape );
       
   145     int maxRow( q->mainWindow()->orientation() == Qt::Vertical ? 
       
   146                 mRowsPortrait : mRowsLandscape );
       
   147     int column (0);
       
   148     int row(0);
       
   149     initialiseContent();
       
   150 
       
   151     if (!mDefaultContentWidget)
       
   152         return;
       
   153 
       
   154     foreach (HbToolButton* button, mToolButtons) {
       
   155         button->setVisible(button->action()->isVisible());
       
   156     }
       
   157 
       
   158     mLayout = new QGraphicsGridLayout();
       
   159     mLayout->setContentsMargins( mMargins, mMargins, mMargins, mMargins );
       
   160     mLayout->setSpacing(0.0);  // if non zero spacing needed, add to css
       
   161     for ( int i(0), j(0), ie(mToolButtons.count()); i < ie; ++i ) {
       
   162         HbToolButton *button = mToolButtons.at(i);
       
   163         if ( button->action()->isVisible() ) {
       
   164             // Calculate the row and column indices
       
   165             column = ( j % columns );
       
   166             row = ( (j - column) / columns );
       
   167             if ( row >= maxRow ) {
       
   168                 qWarning() << "Too many items in extension!";
       
   169             }
       
   170             HbToolButtonPrivate::d_ptr(button)->setBackgroundVisible(false);
       
   171             mLayout->addItem( button, row, column );
       
   172             ++j;
       
   173         }
       
   174     }
       
   175     q->contentWidget()->setLayout(mLayout);
       
   176 }
       
   177 
       
   178 void HbToolBarExtensionPrivate::placeToolBarExtension()
       
   179 {
       
   180     Q_Q(HbToolBarExtension);
       
   181 
       
   182     if (mExtendedButton) {
       
   183         if (mAlignment == Qt::AlignLeft) {
       
   184             QPointF position = QPointF(mExtendedButton->scenePos().x(),
       
   185                                        mExtendedButton->scenePos().y() +
       
   186                                        (mExtendedButton->geometry().height()/2));
       
   187             q->setPreferredPos(position, HbPopup::RightEdgeCenter);
       
   188         } else if (mAlignment == Qt::AlignRight) {
       
   189             QPointF position = QPointF(mExtendedButton->scenePos().x() +
       
   190                                        (mExtendedButton->geometry().width()),
       
   191                                        mExtendedButton->scenePos().y() +
       
   192                                        (mExtendedButton->geometry().height()/2));
       
   193             q->setPreferredPos(position, HbPopup::LeftEdgeCenter);
       
   194         } else if (mAlignment == Qt::AlignTop) {
       
   195             QPointF position = QPointF(mExtendedButton->scenePos().x() +
       
   196                                        (mExtendedButton->geometry().width()/2),
       
   197                                        mExtendedButton->scenePos().y());
       
   198             q->setPreferredPos(position, HbPopup::BottomEdgeCenter);
       
   199         }
       
   200     }
       
   201 }
       
   202 
       
   203 void HbToolBarExtensionPrivate::actionAdded( QActionEvent *event )
       
   204 {
       
   205     Q_Q(HbToolBarExtension);
       
   206 
       
   207     HbAction *action = qobject_cast<HbAction *>( event->action() );
       
   208 
       
   209     if (action) {
       
   210         HbToolButton *button = new HbToolButton(action, q->contentWidget());
       
   211 
       
   212         if (!button->action()->icon().isNull()) {
       
   213             if (button->action()->text().isEmpty()) {
       
   214                 button->setToolButtonStyle(HbToolButton::ToolButtonIcon);
       
   215             } else {
       
   216                 button->setToolButtonStyle(HbToolButton::ToolButtonTextAndIcon);
       
   217             }
       
   218         } else {
       
   219             button->setToolButtonStyle(HbToolButton::ToolButtonText);
       
   220         }
       
   221 
       
   222         button->setProperty("toolbutton_extension_layout", true);
       
   223         button->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, 
       
   224                                             QSizePolicy::Preferred) );
       
   225 
       
   226         // Find out index where to insert button
       
   227         int index = q->actions().indexOf( event->action() );
       
   228 
       
   229         mToolButtons.insert( index, button );
       
   230         
       
   231         q->connect(button, SIGNAL(clicked()), q, SLOT(_q_animateButtonClicked()));
       
   232         q->connect(action, SIGNAL(triggered()), q, SLOT(close()));
       
   233         
       
   234         if (contentWidget){
       
   235             doLayout();
       
   236         }
       
   237     } else {
       
   238         qWarning() << "Use HbAction instead of QAction!";
       
   239     }
       
   240 }
       
   241 
       
   242 void HbToolBarExtensionPrivate::actionRemoved( QActionEvent *event )
       
   243 {
       
   244     for ( int i(0); i < mToolButtons.count(); ++i ) {
       
   245         HbToolButton *button = mToolButtons.at(i);
       
   246         if ( button->action() == event->action() ) {            
       
   247             mToolButtons.removeAt(i);                   
       
   248             if (contentWidget) {
       
   249                 mLayout->removeAt(i);
       
   250                 doLayout();
       
   251             }
       
   252             delete button;
       
   253             return;
       
   254         }
       
   255     }
       
   256 }
       
   257 
       
   258 void HbToolBarExtensionPrivate::actionChanged()
       
   259 {
       
   260     if (contentWidget) {
       
   261         doLayout(); // for action()->setVisible(visible) support
       
   262     }
       
   263 }
       
   264 
       
   265 void HbToolBarExtensionPrivate::setAlignment(Qt::Alignment alignment)
       
   266 {
       
   267     mAlignment = alignment;
       
   268 }
       
   269 
       
   270 void HbToolBarExtensionPrivate::setExtensionAction(HbAction *action)
       
   271 {
       
   272     Q_Q(HbToolBarExtension);
       
   273     if (extensionAction == action) {
       
   274         return;
       
   275     }
       
   276     if (extensionAction) {
       
   277         delete extensionAction;
       
   278     }
       
   279     extensionAction = action;
       
   280     extensionAction->setToolBarExtension(q);
       
   281 
       
   282 }
       
   283 
       
   284 void HbToolBarExtensionPrivate::_q_orientationChanged()
       
   285 {
       
   286     Q_Q(HbToolBarExtension);
       
   287     if (mToolBar) {
       
   288         if (mToolBar->orientation() == Qt::Horizontal) {
       
   289             HbToolBarExtensionPrivate::d_ptr(q)->setAlignment(Qt::AlignTop);
       
   290         } else if (mToolBar->orientation() == Qt::Vertical 
       
   291                    && q->layoutDirection() == Qt::LeftToRight) {
       
   292             HbToolBarExtensionPrivate::d_ptr(q)->setAlignment(Qt::AlignLeft);
       
   293         } else {
       
   294             HbToolBarExtensionPrivate::d_ptr(q)->setAlignment(Qt::AlignRight);
       
   295         }
       
   296     }
       
   297     doLayout();
       
   298 }
       
   299 
       
   300 void HbToolBarExtensionPrivate::_q_animateButtonClicked()
       
   301 {
       
   302 #ifdef HB_EFFECTS
       
   303     Q_Q(HbToolBarExtension);
       
   304     HbToolButton *button = static_cast<HbToolButton *>(q->sender());
       
   305     if (button) {
       
   306         HbEffect::start(button, "TBEButtonClicked", "clicked");
       
   307     }
       
   308 #endif
       
   309 }
       
   310 
       
   311 // ======== MEMBER FUNCTIONS ========
       
   312 
       
   313 /*!
       
   314     Constructs a new HbToolBarExtension. \a parent graphics item can be set.
       
   315  */
       
   316 HbToolBarExtension::HbToolBarExtension( QGraphicsItem *parent ) :
       
   317         HbDialog(*new HbToolBarExtensionPrivate(), parent)
       
   318 {
       
   319     Q_D(HbToolBarExtension);
       
   320     d->q_ptr = this;
       
   321 
       
   322     d->init();
       
   323 }
       
   324 
       
   325 /*!
       
   326     Destructor.
       
   327  */
       
   328 HbToolBarExtension::~HbToolBarExtension()
       
   329 {
       
   330 }
       
   331 
       
   332 /*!
       
   333     \overload
       
   334 
       
   335     Creates a new action with the given \a text. 
       
   336     This action is added to the end of the toolbar extension.
       
   337     TODO: If the grid is already full, this call will be ignored.
       
   338     TODO: Find a way to notificate the caller.
       
   339 */
       
   340 HbAction *HbToolBarExtension::addAction( const QString &text )
       
   341 {
       
   342     HbAction *action = new HbAction( text, this );
       
   343     addAction(action);
       
   344     return action;
       
   345 }
       
   346 
       
   347 /*!
       
   348     \overload
       
   349 
       
   350     Creates a new action with the given \a icon and \a text.
       
   351     This action is added to the end of the toolbar extension.
       
   352     TODO: If the grid is already full, this call will be ignored.
       
   353     TODO: Find a way to notificate the caller.
       
   354 */
       
   355 HbAction *HbToolBarExtension::addAction( const HbIcon &icon, 
       
   356                                          const QString &text )
       
   357 {
       
   358     HbAction *action = new HbAction( icon, text, this );
       
   359     addAction(action);
       
   360     return action;
       
   361 }
       
   362 
       
   363 /*!
       
   364     \overload
       
   365 
       
   366     Creates a new action with the given \a text. 
       
   367     This action is added to the end of the toolbar extension.
       
   368     TODO: If the grid is already full, this call will be ignored.
       
   369     The action's \link HbAction::triggered()
       
   370     triggered()\endlink signal is connected to \a member in \a
       
   371     receiver.
       
   372     TODO: Find a way to notificate the caller.
       
   373 */
       
   374 HbAction *HbToolBarExtension::addAction( const QString &text, 
       
   375                                          const QObject *receiver, 
       
   376                                          const char *member )
       
   377 {
       
   378     HbAction *action = new HbAction( text, this );
       
   379     QObject::connect( action, SIGNAL( triggered(bool) ), receiver, member );
       
   380     addAction(action);
       
   381     return action;
       
   382 }
       
   383 
       
   384 /*!
       
   385     \overload
       
   386 
       
   387     Creates a new action with the given  \a icon and \a text. 
       
   388     This action is added to the end of the toolbar extension.
       
   389     TODO: If the grid is already full, this call will be ignored.
       
   390     The action's \link HbAction::triggered()
       
   391     triggered()\endlink signal is connected to \a member in \a
       
   392     receiver.
       
   393     TODO: Find a way to notificate the caller.
       
   394 */
       
   395 HbAction *HbToolBarExtension::addAction( const HbIcon &icon, 
       
   396                                          const QString &text, 
       
   397                                          const QObject *receiver, 
       
   398                                          const char *member )
       
   399 {
       
   400     HbAction *action = new HbAction( icon, text, this );
       
   401     QObject::connect( action, SIGNAL( triggered(bool) ), receiver, member );
       
   402     addAction(action);
       
   403     return action;
       
   404 }
       
   405 
       
   406 /*!
       
   407     Returns the action associated with this extension.
       
   408  */
       
   409 HbAction *HbToolBarExtension::extensionAction() const
       
   410 {
       
   411     Q_D( const HbToolBarExtension );
       
   412     return d->extensionAction;
       
   413 }
       
   414 
       
   415 /*!
       
   416     Protected constructor.
       
   417 */
       
   418 HbToolBarExtension::HbToolBarExtension( HbToolBarExtensionPrivate &dd, QGraphicsItem *parent ) :
       
   419         HbDialog( dd, parent )
       
   420 {
       
   421 }
       
   422 
       
   423 /*!
       
   424     \reimp
       
   425  */
       
   426 bool HbToolBarExtension::event( QEvent *event )
       
   427 {
       
   428     Q_D( HbToolBarExtension );    
       
   429     if ( event->type() == QEvent::ActionAdded ) {
       
   430         d->actionAdded( static_cast<QActionEvent *>(event) );
       
   431         return true;
       
   432     } else if ( event->type() == QEvent::ActionRemoved ) {
       
   433         d->actionRemoved( static_cast<QActionEvent *>(event) );    
       
   434         return true;
       
   435     } else if (event->type() == QEvent::ActionChanged ) {
       
   436         d->actionChanged();
       
   437         return true;
       
   438     } else if ( event->type() == QEvent::GraphicsSceneResize ) {
       
   439         d->doLayout();
       
   440         // fall trough
       
   441     }
       
   442     return HbDialog::event(event);
       
   443 }
       
   444 
       
   445 void HbToolBarExtension::polish( HbStyleParameters &params )
       
   446 {    
       
   447     Q_D(HbToolBarExtension);  
       
   448     d->doLazyInit();
       
   449     const QString Margins       = "content-margins";
       
   450     const QString RowsPortrait  = "max-rows-portrait";
       
   451     const QString RowsLandscape = "max-rows-landscape";
       
   452     const QString ColsPortrait  = "max-columns-portrait";
       
   453     const QString ColsLandscape = "max-columns-landscape";
       
   454 
       
   455     params.addParameter( Margins );
       
   456     params.addParameter( RowsPortrait );
       
   457     params.addParameter( RowsLandscape );
       
   458     params.addParameter( ColsPortrait );
       
   459     params.addParameter( ColsLandscape );
       
   460     d->initialiseContent();
       
   461     if (d->mDefaultContentWidget) {
       
   462         QGraphicsWidget *tbeContentWidget = contentWidget();
       
   463         style()->setItemName( tbeContentWidget, "HbToolBarExtension" );
       
   464         HbDialog::polish(params);
       
   465         if ( params.value( Margins ).isValid() 
       
   466              && params.value( RowsPortrait ).isValid() 
       
   467              && params.value( RowsLandscape ).isValid() 
       
   468              && params.value( ColsPortrait ).isValid() 
       
   469              && params.value( ColsLandscape ).isValid() ) {
       
   470             d->mMargins = params.value( Margins ).toReal();
       
   471             d->mRowsPortrait  = params.value( RowsPortrait ).toInt();
       
   472             d->mRowsLandscape = params.value( RowsLandscape ).toInt();
       
   473             d->mColsPortrait  = params.value( ColsPortrait ).toInt();
       
   474             d->mColsLandscape = params.value( ColsLandscape ).toInt();
       
   475             d->doLayout();
       
   476         }
       
   477     } else {
       
   478         HbDialog::polish(params);
       
   479     }
       
   480 }
       
   481 
       
   482 QVariant HbToolBarExtension::itemChange(GraphicsItemChange change, 
       
   483                                         const QVariant &value)
       
   484 {
       
   485     Q_D(HbToolBarExtension);
       
   486     if (change == QGraphicsItem::ItemVisibleHasChanged) {
       
   487         if (value.toBool() == true) {
       
   488             d->placeToolBarExtension();
       
   489         }
       
   490     }
       
   491 
       
   492     return HbDialog::itemChange(change, value);
       
   493 }
       
   494 
       
   495 #include "moc_hbtoolbarextension.cpp"