Home · All Classes · Main Classes · Deprecated

mwidgetcontroller.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002 **
00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
00004 ** All rights reserved.
00005 ** Contact: Nokia Corporation (directui@nokia.com)
00006 **
00007 ** This file is part of libmeegotouch.
00008 **
00009 ** If you have questions regarding the use of this file, please contact
00010 ** Nokia at directui@nokia.com.
00011 **
00012 ** This library is free software; you can redistribute it and/or
00013 ** modify it under the terms of the GNU Lesser General Public
00014 ** License version 2.1 as published by the Free Software Foundation
00015 ** and appearing in the file LICENSE.LGPL included in the packaging
00016 ** of this file.
00017 **
00018 ****************************************************************************/
00019 
00020 #include "mwidgetcontroller.h"
00021 #include "mwidgetcontroller_p.h"
00022 
00023 #include "mwidgetmodel.h"
00024 #include "mwidgetview.h"
00025 #include "mwidgetview_p.h"
00026 #include "mtheme.h"
00027 
00028 #include "mpannablewidget.h"
00029 
00030 #include <MDebug>
00031 #include <QSet>
00032 #include <QGraphicsSceneMouseEvent>
00033 #include <QInputContext>
00034 #include <QApplication>
00035 
00036 #include "mwidgetcreator.h"
00037 M_REGISTER_WIDGET(MWidgetController)
00038 
00039 const MTheme::ViewType MWidgetController::defaultType = "default";
00040 
00041 static void combineSize(QSizeF &result, const QSizeF &size)
00042 {
00043     if (result.width() < 0)
00044         result.setWidth(size.width());
00045     if (result.height() < 0)
00046         result.setHeight(size.height());
00047 }
00048 
00049 // TODO: if model needs to be shared, a version of constructor is
00050 // needed which takes model as a parameter. Some consideration is also
00051 // needed of how the shared model is managed outside the controllers
00052 // (e.g. deleting after detached from the last controller). Reference
00053 // count maybe?
00054 
00056 // PRIVATE CLASS //
00058 
00059 QSet<MWidgetController *> MWidgetControllerPrivate::allSystemWidgets;
00060 
00061 MWidgetControllerPrivate::MWidgetControllerPrivate() :
00062     model(0),
00063     view(0),
00064     viewSetManually(false),
00065     active(false),
00066     constructingView(false),
00067     modelSetup(false)
00068 {
00069 }
00070 
00071 MWidgetControllerPrivate::~MWidgetControllerPrivate()
00072 {
00073 }
00074 
00076 // PUBLIC CLASS //
00078 
00079 MWidgetController::MWidgetController(QGraphicsItem *parent) :
00080     MWidget(*new MWidgetControllerPrivate, parent)
00081 {
00082     Q_D(MWidgetController);
00083     d->setModel(new MWidgetModel);
00084 
00085     MWidgetControllerPrivate::allSystemWidgets.insert(this);
00086 }
00087 
00088 MWidgetController::MWidgetController(MWidgetModel *model, QGraphicsItem *parent) :
00089     MWidget(*new MWidgetControllerPrivate, parent)
00090 {
00091     Q_D(MWidgetController);
00092     d->setModel(model == NULL ? new MWidgetModel : model);
00093 
00094     MWidgetControllerPrivate::allSystemWidgets.insert(this);
00095 }
00096 
00097 // protected constructor for derived classes
00098 MWidgetController::MWidgetController(MWidgetControllerPrivate *dd, MWidgetModel *model, QGraphicsItem *parent) :
00099     MWidget(*dd, parent)
00100 {
00101     //The parent class must set a model
00102     Q_ASSERT(model);
00103     Q_D(MWidgetController);
00104     d->setModel(model);
00105     MWidgetControllerPrivate::allSystemWidgets.insert(this);
00106 }
00107 
00108 // destructor
00109 MWidgetController::~MWidgetController()
00110 {
00111     Q_D(MWidgetController);
00112 
00113     // let the model know that we're not attached to it anymore.
00114     if (d->model) {
00115         d->model->decreaseReferenceCount();
00116         d->model = 0;
00117     }
00118 
00119     // let the view know that it can now animate away.
00120     if (d->view) {
00121         // TODO: later this should probably be done by MSceneManager.
00122         d->view->destroy();
00123         d->view = 0;
00124     }
00125 
00126     MWidgetControllerPrivate::allSystemWidgets.remove(this);
00127 }
00128 
00129 // const getter for model
00130 const MWidgetModel *MWidgetController::model() const
00131 {
00132     MWidgetControllerPrivate *d = (MWidgetControllerPrivate *)d_ptr;
00133 
00134     if (d->modelSetup == false) {
00135         // Clear the flag first to avoid recursion in case a derived setupModel calls model()
00136         d->modelSetup = true;
00137         const_cast<MWidgetController &>(*this).setupModel();
00138     }
00139 
00140     return d->model;
00141 }
00142 
00143 // getter for model
00144 MWidgetModel *MWidgetController::model()
00145 {
00146     return const_cast<MWidgetModel *>
00147            (static_cast<const MWidgetController &>(*this).model());
00148 }
00149 
00150 // const getter for view
00151 const MWidgetView *MWidgetController::view() const
00152 {
00153     Q_D(const MWidgetController);
00154 
00155     if (!d->view) {
00156         Q_ASSERT_X(d->model, "MWidgetController", "You should not call MWidgetController::view() before the widget has a model!");
00157         const_cast<MWidgetControllerPrivate *>(d)->createView();
00158     }
00159 
00160     return d->view;
00161 }
00162 
00163 // notification of model modifications
00164 void MWidgetController::updateData(const QList<const char *>& modifications)
00165 {
00166     Q_UNUSED(modifications);
00167 }
00168 
00169 // notification of model reset
00170 void MWidgetController::setupModel()
00171 {
00172     Q_D(MWidgetController);
00173     d->modelSetup = true;
00174 }
00175 
00176 void MWidgetController::updateMicroFocus()
00177 {
00178     QInputContext *ic = qApp->inputContext();
00179 
00180     if (ic != 0) {
00181         ic->update();
00182     }
00183 }
00184 
00185 // method for setting new model for this controller + view
00186 void MWidgetController::setModel(MWidgetModel *model)
00187 {
00188     Q_ASSERT_X(model, "MWidgetController", "MWidgetController::setModel() parameter model has to be valid!");
00189     Q_D(MWidgetController);
00190     d->setModel(model);
00191     //Call setupModel immediately since this is not called from the constructor
00192     setupModel();
00193 }
00194 
00195 void MWidgetControllerPrivate::setModel(MWidgetModel *newModel)
00196 {
00197     Q_Q(MWidgetController);
00198     if (newModel == model)
00199         return;
00200 
00201     if (model) {
00202         q->disconnect(model, 0, q, 0);
00203         model->decreaseReferenceCount();
00204     }
00205 
00206     model = newModel;
00207     model->increaseReferenceCount();
00208 
00209     q->connect(model, SIGNAL(modified(QList<const char *>)),
00210             q, SLOT(updateData(QList<const char *>)));
00211 
00212     // setupModel() will be called on the first model access to finalize the model switch
00213     modelSetup = false;
00214 
00215     // set the model also to view if we already have one
00216     if (view) {
00217         view->setModel(model);
00218     }
00219 }
00220 
00221 M::Position MWidgetController::layoutPosition() const
00222 {
00223     return model()->layoutPosition();
00224 }
00225 
00226 void MWidgetController::setLayoutPosition(M::Position layoutPosition)
00227 {
00228     model()->setLayoutPosition(layoutPosition);
00229 }
00230 
00231 // setter for view
00232 // manually sets the view to some specific view
00233 // after calling this the view won't change with theme
00234 void MWidgetController::setView(MWidgetView *view)
00235 {
00236     Q_D(MWidgetController);
00237 
00238     // check if we already had a view and destroy it.
00239     if (d->view != NULL)
00240         d->view->destroy();
00241 
00242     // set the new view
00243     d->view = view;
00244 
00245     // if the user gave us a view
00246     if (d->view) {
00247         // set the flag that user has manually set the view, so theme won't override it.
00248         d->viewSetManually = true;
00249 
00250         d->configureView(d->view);
00251 
00252         // TODO: check if this is really needed.
00253         prepareGeometryChange();
00254     } else {
00255         // user set a NULL view
00256 
00257         // unset the flag so now the view will be again controlled by the theme.
00258         d->viewSetManually = false;
00259     }
00260     updateGeometry();
00261 }
00262 
00263 // this method is called by MTheme when theme is changing.
00264 // deprecates the current view, if the user has not manually set the view
00265 void MWidgetControllerPrivate::deprecateView()
00266 {
00267     if (viewSetManually)
00268         return;
00269 
00270     if (view != NULL) {
00271         view->destroy();
00272         view = 0;
00273     }
00274 }
00275 
00276 // creates a view for this controller
00277 void MWidgetControllerPrivate::createView()
00278 {
00279     Q_Q(MWidgetController);
00280 
00281     // check that we don't have a view yet
00282     Q_ASSERT(!view);
00283 
00284     if (!constructingView) {
00285         constructingView = true;
00286         view = MTheme::view(q);
00287         constructingView = false;
00288     }
00289 
00290     if (view) {
00291         configureView(view);
00292         q->updateGeometry();
00293     }
00294 }
00295 
00296 void MWidgetControllerPrivate::configureView(MWidgetView *view)
00297 {
00298     Q_Q(MWidgetController);
00299 
00300     // set this as the controller of the view
00301     view->d_ptr->controller = q;
00302 
00303     // give our model to the view also
00304     view->setModel(model);
00305 }
00306 
00307 void MWidgetController::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
00308 {
00309     Q_D(MWidgetController);
00310 
00311     if (view()) {
00312         d->view->paint(painter, option, widget);
00313     }
00314 }
00315 
00316 QRectF MWidgetController::boundingRect() const
00317 {
00318     if (const MWidgetView *v = view()) {
00319         QRect margins = v->margins();
00320         QRect reactiveMargins = v->reactiveMargins();
00321         QRectF br = v->boundingRect();
00322 
00323         // height contains bottom margin and width contains the right margin
00324         br.adjust(-margins.left() - reactiveMargins.left(), -margins.top() - reactiveMargins.top(),
00325                   margins.width() + reactiveMargins.width(), margins.height() + reactiveMargins.height());
00326         br.translate(margins.left(), margins.top());
00327         return br;
00328     } else {
00329         return QRectF();
00330     }
00331 }
00332 
00333 QPainterPath MWidgetController::shape() const
00334 {
00335     Q_D(const MWidgetController);
00336     if (view()) {
00337         QPainterPath path;
00338         path.moveTo(d->view->marginLeft(), d->view->marginTop());
00339         path.addPath(d->view->shape());
00340         return path;
00341     } else {
00342         return QPainterPath();
00343     }
00344 }
00345 
00346 // this function takes a mouse event and translates every local(not scene) coordinate
00347 // of it by offset p.
00348 void translateMouseEvent(QGraphicsSceneMouseEvent *event, const QPointF &p)
00349 {
00350     event->setPos(event->pos() - p);
00351     event->setButtonDownPos(Qt::LeftButton, event->buttonDownPos(Qt::LeftButton) - p);
00352     event->setButtonDownPos(Qt::RightButton, event->buttonDownPos(Qt::RightButton) - p);
00353     event->setButtonDownPos(Qt::MidButton, event->buttonDownPos(Qt::MidButton) - p);
00354     event->setButtonDownPos(Qt::XButton1, event->buttonDownPos(Qt::XButton1) - p);
00355     event->setButtonDownPos(Qt::XButton2, event->buttonDownPos(Qt::XButton2) - p);
00356     event->setLastPos(event->lastPos() - p);
00357 }
00358 
00359 
00360 void MWidgetController::mousePressEvent(QGraphicsSceneMouseEvent *event)
00361 {
00362     Q_D(MWidgetController);
00363     // check if we have, or if we can create a view
00364     if (view()) {
00365         // forward the event to the view
00366         translateMouseEvent(event, QPointF(d->view->marginLeft(), d->view->marginTop()));
00367         d->view->mousePressEvent(event);
00368     }
00369 }
00370 
00371 void MWidgetController::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00372 {
00373     Q_D(MWidgetController);
00374     // check if we have, or if we can create a view
00375     if (view()) {
00376         // forward the event to the view
00377         translateMouseEvent(event, QPointF(d->view->marginLeft(), d->view->marginTop()));
00378         d->view->mouseReleaseEvent(event);
00379     }
00380 }
00381 
00382 void MWidgetController::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
00383 {
00384     Q_D(MWidgetController);
00385     // check if we have, or if we can create a view
00386     if (view()) {
00387         // forward the event to the view
00388         translateMouseEvent(event, QPointF(d->view->marginLeft(), d->view->marginTop()));
00389         d->view->mouseMoveEvent(event);
00390     }
00391 }
00392 
00393 void MWidgetController::cancelEvent(MCancelEvent *event)
00394 {
00395     Q_D(MWidgetController);
00396     if (view()) {
00397         d->view->cancelEvent(event);
00398     }
00399 }
00400 
00401 void MWidgetController::orientationChangeEvent(MOrientationChangeEvent *event)
00402 {
00403     Q_D(MWidgetController);
00404     if (view())
00405         d->view->orientationChangeEvent(event);
00406 }
00407 
00408 void MWidgetController::tapAndHoldGestureEvent(QGestureEvent *event, QTapAndHoldGesture *gesture)
00409 {
00410     Q_D(MWidgetController);
00411     if (view())
00412         d->view->tapAndHoldGestureEvent(event,gesture);
00413 }
00414 
00415 void MWidgetController::panGestureEvent(QGestureEvent *event, QPanGesture *gesture)
00416 {
00417     Q_D(MWidgetController);
00418     // We are using here a hack which will allow reimplementing the panGestureEvent
00419     // method in the pannable widget without recompilation of all client applications.
00420     // This needs to be deleted when API unfreeze will finally happen.
00421     if( MPannableWidget* pannableWidget = qobject_cast< MPannableWidget* >( this ))
00422         pannableWidget->MPannableWidget::panGestureEvent(event, gesture);
00423     else {
00424         if (view())
00425             d->view->panGestureEvent(event,gesture);
00426     }
00427 }
00428 
00429 void MWidgetController::pinchGestureEvent(QGestureEvent *event, QPinchGesture* gesture)
00430 {
00431     Q_D(MWidgetController);
00432     if (view())
00433         d->view->pinchGestureEvent(event,gesture);
00434 }
00435 
00436 void MWidgetController::tapGestureEvent(QGestureEvent *event, QTapGesture* gesture)
00437 {
00438     Q_D(MWidgetController);
00439     if (view())
00440         d->view->tapGestureEvent(event,gesture);
00441 }
00442 
00443 void MWidgetController::swipeGestureEvent(QGestureEvent *event, QSwipeGesture* gesture)
00444 {
00445     Q_D(MWidgetController);
00446     if (view())
00447         d->view->swipeGestureEvent(event,gesture);
00448 }
00449 
00450 QVariant MWidgetController::itemChange(GraphicsItemChange change, const QVariant &value)
00451 {
00452     Q_D(MWidgetController);
00453     if (d->view) {
00454         // forward the event to the view
00455         d->view->notifyItemChange(change, value);
00456     }
00457     return MWidget::itemChange(change, value);
00458 }
00459 
00460 
00461 QVariant MWidgetController::inputMethodQuery(Qt::InputMethodQuery query) const
00462 {
00463     Q_D(const MWidgetController);
00464     if (view()) {
00465         return d->view->inputMethodQuery(query);
00466     } else {
00467         return QVariant();
00468     }
00469 }
00470 
00471 void MWidgetController::setActive(bool targetState)
00472 {
00473     Q_D(MWidgetController);
00474     if (d->active != targetState) {
00475         d->active = targetState;
00476         if (view())
00477             d->view->setActive(targetState);
00478     }
00479 }
00480 
00481 bool MWidgetController::isActive() const
00482 {
00483     Q_D(const MWidgetController);
00484     return d->active;
00485 }
00486 
00487 void MWidgetController::setViewType(const MTheme::ViewType &type)
00488 {
00489     Q_D(MWidgetController);
00490     d->viewSetManually = false;
00491     d->deprecateView();
00492     model()->setViewType(type);
00493 }
00494 
00495 MTheme::ViewType MWidgetController::viewType() const
00496 {
00497     return model()->viewType();
00498 }
00499 
00500 void MWidgetController::setGeometry(const QRectF &rect)
00501 {
00502     Q_D(MWidgetController);
00503     MWidget::setGeometry(rect);
00504     // check if we have, or if we can create a view
00505     if (view()) {
00506         QRect margins = d->view->margins();
00507         // create a new smaller rect with topLeft-corner translated towards center
00508         // and bottomRight corner translated also towards center.
00509         QRectF viewGeom(rect.topLeft() + margins.topLeft(),
00510                         rect.bottomRight() - QPointF(margins.width(), margins.height()));
00511         d->view->setGeometry(viewGeom);
00512     }
00513 }
00514 
00515 void MWidgetController::setObjectName(const QString &name)
00516 {
00517     MWidget::setObjectName(name);
00518 
00519     model()->setObjectName(name);
00520 }
00521 
00522 void MWidgetController::setStyleName(const QString &name)
00523 {
00524     model()->setStyleName(name);
00525 }
00526 
00527 QSizeF MWidgetController::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
00528 {
00529     Q_D(const MWidgetController);
00530     QSizeF sh(constraint);
00531     // check if we have, or if we can create, a view
00532     if (view()) {
00533         QRect margins = d->view->margins();
00534         qreal widthMargin = margins.left() + margins.width();
00535         qreal heightMargin = margins.top() + margins.height();
00536 
00537         // Adjust the constraint to remove the margins
00538         if (sh.width() > 0)
00539             sh.setWidth( qMax((qreal)0, sh.width() - widthMargin) );
00540         if (sh.height() > 0)
00541             sh.setHeight( qMax((qreal)0, sh.height() - heightMargin) );
00542 
00543         //Combine the constraint with the size given by the style (e.g. as set by the CSS file),
00544         //with the constraint taking priority
00545         QSizeF styleSize;
00546         if (which == Qt::MinimumSize)
00547             styleSize = d->view->style()->minimumSize();
00548         else if (which == Qt::MaximumSize)
00549             styleSize = d->view->style()->maximumSize();
00550         else if (which == Qt::PreferredSize)
00551             styleSize = d->view->style()->preferredSize();
00552 
00553         combineSize(sh, styleSize);
00554 
00555         // The size isn't fully specified by the constraint and CSS.  Fetch the size hint from the view
00556         if (!sh.isValid())
00557             combineSize(sh, d->view->sizeHint(which, sh));
00558 
00559         // unless the final size dimensions are unconstrained, we need to add margins to them
00560         // so the layouting system reserves enough space for the content + margins.
00561         if (sh.width() >= 0)
00562             sh.rwidth() += widthMargin;
00563         if (sh.height() >= 0)
00564             sh.rheight() += heightMargin;
00565     }
00566 
00567     //If the size is not specified manually, nor by css, nor by the view, then
00568     //fallback to using the layout's sizeHint
00569     if (!sh.isValid()) {
00570         QSizeF widgetSize = MWidget::sizeHint(which, sh);
00571         if (widgetSize.width() == 0) // Work around bug NB#189091
00572             widgetSize = MWidget::sizeHint(which);
00573         combineSize(sh, widgetSize);
00574     }
00575 
00576     return sh;
00577 }
00578 
00579 void MWidgetController::resizeEvent(QGraphicsSceneResizeEvent *event)
00580 {
00581     Q_D(MWidgetController);
00582     // check if we have, or if we can create a view
00583     if (view()) {
00584         QRect margins = d->view->margins();
00585         QSizeF marginSize(margins.x() + margins.width(),
00586                           margins.top() + margins.height());
00587 
00588         event->setOldSize(event->oldSize() - marginSize);
00589         event->setNewSize(event->newSize() - marginSize);
00590 
00591         // forward the event to the view
00592         d->view->resizeEvent(event);
00593     }
00594 }
00595 
00596 
00597 void MWidgetController::changeEvent(QEvent *event)
00598 {
00599     Q_D(MWidgetController);
00600 
00601     MWidget::changeEvent(event);
00602 
00603     if (view()) {
00604         d->view->changeEvent(event);
00605     }
00606 }
00607 
00608 const QString &MWidgetController::styleName() const
00609 {
00610     return model()->styleName();
00611 }
00612 
00613 bool MWidgetController::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
00614 {
00615     Q_D(MWidgetController);
00616     // check if we have, or if we can create a view
00617     if (view())
00618         return d->view->sceneEventFilter(watched, event);
00619     return false;
00620 }
00621 
00622 MWidgetStyleContainer &MWidgetController::style()
00623 {
00624     return const_cast<MWidgetStyleContainer &>(view()->style());
00625 }
00626 
00627 const MWidgetStyleContainer &MWidgetController::style() const
00628 {
00629     return view()->style();
00630 }

Copyright © 2010 Nokia Corporation Generated on Thu Nov 4 2010 18:14:22 (PDT)
Doxygen 1.7.1
MeeGo Touch