| Home · All Classes · Main Classes · Deprecated |
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 |