| 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 "mondisplaychangeevent.h" 00021 00022 #include <MDebug> 00023 #include <mscenewindowevent_p.h> 00024 #include "mapplicationwindow_p.h" 00025 #include "mapplicationwindow.h" 00026 #include "mapplicationwindowstyle.h" 00027 #include "mapplicationpage.h" 00028 #include "mapplicationpage_p.h" 00029 #include "mnavigationbar.h" 00030 #include "mapplicationmenu.h" 00031 #include "mtoolbar.h" 00032 #include "mtoolbar_p.h" 00033 #include "mdockwidget.h" 00034 #include "mcomponentdata.h" 00035 #include "maction.h" 00036 #include "mhomebuttonpanel.h" 00037 #include "mapplication.h" 00038 #include "mcomponentdata.h" 00039 #include "mscenemanager.h" 00040 #include "mscene.h" 00041 #include "mstatusbar.h" 00042 #include "mdeviceprofile.h" 00043 #include "mcomponentdata.h" 00044 00045 #include <QList> 00046 #include <QEvent> 00047 #include <QRectF> 00048 #include <QActionEvent> 00049 00050 #ifdef Q_WS_X11 00051 # include <QX11Info> 00052 # include <X11/Xatom.h> 00053 # include <X11/Xlib.h> 00054 #endif 00055 00056 #ifdef M_OS_MAEMO5 00057 #include <QDBusConnection> 00058 #include <QDBusMessage> 00059 #endif //M_OS_MAEMO5 00060 00061 namespace { 00062 // TODO: this may be moved to some header if needed elsewhere 00063 // Returns the longest length variant of a translated string. 00064 // If a translated string has many length variants, they are 00065 // separated with U+009C (STRING TERMINATOR) character, and 00066 // according to DTD for .ts file format, they should be ordered 00067 // by decreasing length. 00068 // This helper function returns the longest length variant 00069 // by returning the string up to the first U+009C character. 00070 // If there's only one length variant, the function returns 00071 // the whole unprocessed string. 00072 QString longestLengthVariant(const QString &text) 00073 { 00074 return text.left(text.indexOf(QChar(0x9c))); 00075 } 00076 } 00077 00078 MApplicationWindowPrivate::MApplicationWindowPrivate() 00079 : MWindowPrivate() 00080 , page(NULL) 00081 , navigationBar(new MNavigationBar) 00082 , toolBar(new MToolBar) 00083 , dockWidget(new MDockWidget) 00084 , homeButtonPanel(new MHomeButtonPanel) 00085 , menu(new MApplicationMenu) 00086 , pageAreaMaximized(false) 00087 #ifdef Q_WS_X11 00088 , isChained(false) 00089 , chainParentWinId(0) 00090 , chainTaskTitle() 00091 #endif 00092 #ifdef HAVE_CONTEXTSUBSCRIBER 00093 , callStatusProperty("Phone.Call") 00094 #endif 00095 , showingStatusBar(false) 00096 , showingNavigationBar(false) 00097 , showingDockWidget(false) 00098 , style(0) 00099 { 00100 if(MDeviceProfile::instance()->showStatusbar()) { 00101 statusBar = new MStatusBar; 00102 } 00103 else{ 00104 statusBar = NULL; 00105 } 00106 } 00107 00108 MApplicationWindowPrivate::~MApplicationWindowPrivate() 00109 { 00110 delete dockWidget; 00111 dockWidget = 0; 00112 delete toolBar; 00113 toolBar = 0; 00114 delete menu; 00115 menu = 0; 00116 delete navigationBar; 00117 navigationBar = 0; 00118 delete homeButtonPanel; 00119 homeButtonPanel = 0; 00120 00121 MTheme::releaseStyle(style); 00122 style = 0; 00123 00124 if (statusBar) { 00125 delete statusBar; 00126 statusBar = 0; 00127 } 00128 } 00129 00130 void MApplicationWindowPrivate::init() 00131 { 00132 Q_Q(MApplicationWindow); 00133 00134 style = static_cast<const MApplicationWindowStyle *>(MTheme::style("MApplicationWindowStyle", "", "", "", q->orientation())); 00135 00136 q->connect(q, SIGNAL(orientationChanged(M::Orientation)), q, SLOT(_q_updateStyle())); 00137 q->connect(MTheme::instance(), SIGNAL(themeChangeCompleted()), q, SLOT(_q_updateStyle())); 00138 00139 q->setOptimizationFlag(QGraphicsView::DontSavePainterState); 00140 00141 #ifdef Q_WS_X11 00142 if (!MComponentData::chainDataStackIsEmpty()) { 00143 MComponentData::ChainData thisData = MComponentData::popChainData(); 00144 00145 WId thisDataWId = thisData.first; 00146 QString thisDataTaskTitle = thisData.second; 00147 00148 chainParentWinId = thisDataWId; 00149 bool taskTitleSet = !thisDataTaskTitle.isEmpty(); 00150 if (taskTitleSet) { 00151 chainTaskTitle = thisDataTaskTitle; 00152 } else { 00153 chainTaskTitle = MComponentData::appName(); 00154 } 00155 00156 isChained = true; 00157 00158 // for compositor page animation 00159 setWindowChainedProperty( chainParentWinId, q->effectiveWinId() ); 00160 } 00161 addMStatusBarOverlayProperty(); 00162 appendMApplicationWindowTypeProperty(); 00163 #endif 00164 00165 #ifdef M_OS_MAEMO5 00166 q->connect(homeButtonPanel, SIGNAL(buttonClicked()), q, SLOT(_q_exitAppView())); 00167 #else 00168 q->connect(homeButtonPanel, SIGNAL(buttonClicked()), q, SLOT(closeMenu())); 00169 q->connect(homeButtonPanel, SIGNAL(buttonClicked()), q, SLOT(showMinimized())); 00170 #endif //M_OS_MAEMO5 00171 00172 q->connect(navigationBar, SIGNAL(viewmenuTriggered()), 00173 q, SLOT(openMenu())); 00174 00175 q->connect(navigationBar, SIGNAL(sceneWindowStateChanged(MSceneWindow::SceneWindowState, MSceneWindow::SceneWindowState)), 00176 q, SLOT(_q_navigationBarStateChanged(MSceneWindow::SceneWindowState, MSceneWindow::SceneWindowState))); 00177 00178 q->connect(menu, SIGNAL(appeared()), 00179 q, SLOT(_q_menuAppeared())); 00180 q->connect(menu, SIGNAL(disappeared()), 00181 q, SLOT(_q_menuDisappeared())); 00182 q->connect(q, SIGNAL(switcherEntered()), 00183 SLOT(_q_handleInSwitcherVisibilityChange())); 00184 q->connect(q, SIGNAL(switcherExited()), 00185 SLOT(_q_handleInSwitcherVisibilityChange())); 00186 00187 sceneManager->appearSceneWindowNow(navigationBar); 00188 sceneManager->appearSceneWindowNow(homeButtonPanel); 00189 00190 // Initialize escape button to close mode. 00191 navigationBar->setEscapeButtonMode(MNavigationBarModel::EscapeButtonClose); 00192 QObject::connect(navigationBar, SIGNAL(closeButtonClicked()), q, SLOT(close())); 00193 00194 if (needsDockWidget()) { 00195 sceneManager->appearSceneWindowNow(dockWidget); 00196 } 00197 00198 if (!MApplication::fullScreen() && statusBar) { 00199 sceneManager->appearSceneWindowNow(statusBar); 00200 } 00201 00202 _q_placeToolBar(); 00203 00204 q->setBackgroundBrush(Qt::black); 00205 00206 initAutoHideComponentsTimer(); 00207 00208 #ifdef HAVE_CONTEXTSUBSCRIBER 00209 q->connect(&callStatusProperty, SIGNAL(valueChanged()), SLOT(_q_updateStatusBarVisibility())); 00210 #endif 00211 q->connect(q, SIGNAL(orientationAngleChanged(M::OrientationAngle)), 00212 SLOT(_q_updatePageExposedContentRect())); 00213 q->connect(MTheme::instance(), SIGNAL(themeChangeCompleted()), 00214 SLOT(_q_updatePageExposedContentRect())); 00215 } 00216 00217 void MApplicationWindowPrivate::_q_handleInSwitcherVisibilityChange() 00218 { 00219 if (isInSwitcher) { 00220 navigationBar->hide(); 00221 dockWidget->hide(); 00222 homeButtonPanel->hide(); 00223 closeMenu(); 00224 } else { 00225 if (navigationBar->sceneWindowState() == MSceneWindow::Appeared || 00226 navigationBar->sceneWindowState() == MSceneWindow::Appearing) 00227 navigationBar->show(); 00228 00229 if (dockWidget->sceneWindowState() == MSceneWindow::Appeared || 00230 dockWidget->sceneWindowState() == MSceneWindow::Appearing) 00231 dockWidget->show(); 00232 00233 if (homeButtonPanel->sceneWindowState() == MSceneWindow::Appeared || 00234 homeButtonPanel->sceneWindowState() == MSceneWindow::Appearing) 00235 homeButtonPanel->show(); 00236 } 00237 } 00238 00239 #ifdef Q_WS_X11 00240 void MApplicationWindowPrivate::setWindowChainedProperty( const Window &parentWinId, const Window &childWinId ) 00241 { 00242 Atom atomMInvokedBy = XInternAtom(QX11Info::display(), "_MEEGOTOUCH_WM_INVOKED_BY", False); 00243 Display *display = QX11Info::display(); 00244 00245 // for compositor page transition 00246 XChangeProperty(display, childWinId, 00247 atomMInvokedBy, XA_WINDOW, 00248 32, PropModeReplace, 00249 (unsigned char *)&parentWinId, 1); 00250 00251 // for task switcher view stacking 00252 XSetTransientForHint(display, childWinId, parentWinId); 00253 } 00254 00255 void MApplicationWindowPrivate::addMStatusBarOverlayProperty() 00256 { 00257 Q_Q(MWindow); 00258 00259 Atom atomMStatusBarOverlay = XInternAtom(QX11Info::display(), "_DUI_STATUSBAR_OVERLAY", False); 00260 long propertyData = 1; 00261 00262 XChangeProperty(QX11Info::display(), q->effectiveWinId(), 00263 atomMStatusBarOverlay, XA_CARDINAL /* type */, 00264 32 /* format, in bits */, PropModeReplace, 00265 (unsigned char *) &propertyData, 1 /* number of elements */); 00266 } 00267 00268 void MApplicationWindowPrivate::appendMApplicationWindowTypeProperty() 00269 { 00270 Q_Q(MApplicationWindow); 00271 00272 Atom atomWindowType = XInternAtom(QX11Info::display(), "_MEEGOTOUCH_NET_WM_WINDOW_TYPE_MAPPLICATION", False); 00273 XChangeProperty(QX11Info::display(), q->effectiveWinId(), 00274 XInternAtom(QX11Info::display(), "_NET_WM_WINDOW_TYPE", False), 00275 XA_ATOM, 32, PropModeAppend, (unsigned char*) &atomWindowType, 1); 00276 } 00277 #endif 00278 00279 void MApplicationWindowPrivate::initAutoHideComponentsTimer() 00280 { 00281 autoHideComponentsTimer.setInterval(style->autoHideTimeout()); 00282 autoHideComponentsTimer.setSingleShot(true); 00283 } 00284 00285 void MApplicationWindowPrivate::windowStateChangeEvent(QWindowStateChangeEvent *event) 00286 { 00287 Q_Q(MApplicationWindow); 00288 if (!statusBar) 00289 return; 00290 00291 if (q->isFullScreen() != event->oldState().testFlag(Qt::WindowFullScreen)) { 00292 _q_updateStatusBarVisibility(); 00293 } 00294 } 00295 00296 void MApplicationWindowPrivate::maximizePageArea() 00297 { 00298 pageAreaMaximized = true; 00299 00300 // When maximized, the window is in control of these components. 00301 setComponentDisplayMode(homeButtonPanel, MApplicationPageModel::Hide); 00302 00303 if (navigationBar->focusItem()) { 00304 // Always show focused navigation bar. 00305 setComponentDisplayMode(navigationBar, MApplicationPageModel::Show); 00306 } else { 00307 setComponentDisplayMode(navigationBar, MApplicationPageModel::Hide); 00308 } 00309 00310 if (needsDockWidget()) { 00311 if (dockWidget->focusItem()) { 00312 // Always show focused dock widget. 00313 setComponentDisplayMode(dockWidget, MApplicationPageModel::Show); 00314 } else { 00315 setComponentDisplayMode(dockWidget, MApplicationPageModel::Hide); 00316 } 00317 } 00318 00319 00320 // Now that we've set pageAreaMaximized, this update tries to hide status bar. 00321 _q_updateStatusBarVisibility(); 00322 } 00323 00324 void MApplicationWindowPrivate::restorePageArea() 00325 { 00326 if (!pageAreaMaximized) { 00327 return; 00328 } 00329 00330 pageAreaMaximized = false; 00331 00332 if (page) { 00333 setComponentDisplayMode(homeButtonPanel, page->model()->homeButtonDisplayMode()); 00334 setComponentDisplayMode(navigationBar, page->model()->navigationBarDisplayMode()); 00335 00336 if (needsDockWidget()) { 00337 // Dock widget follows navigation bar display mode. 00338 setComponentDisplayMode(dockWidget, page->model()->navigationBarDisplayMode()); 00339 } 00340 } 00341 00342 // Show status bar 00343 _q_updateStatusBarVisibility(); 00344 } 00345 00346 void MApplicationWindowPrivate::_q_updateStatusBarVisibility() 00347 { 00348 Q_Q(MApplicationWindow); 00349 if (!statusBar) 00350 return; 00351 00352 #ifdef HAVE_CONTEXTSUBSCRIBER 00353 // Status bar should always be appeared while a phone call is ongoing. 00354 if (callStatusProperty.value().toString() == "active") { 00355 statusBar->appear(q); 00356 return; 00357 } 00358 #endif 00359 00360 if (q->isFullScreen() || pageAreaMaximized) { 00361 statusBar->disappear(); 00362 } else { 00363 statusBar->appear(q); 00364 } 00365 } 00366 00367 void MApplicationWindowPrivate::_q_actionUpdated(QActionEvent *event) 00368 { 00369 QAction *action = event->action(); 00370 00371 if (event->type() == QEvent::ActionAdded) { 00372 QAction *before = event->before(); 00373 distributeAction(action, before); 00374 } else if (event->type() == QEvent::ActionRemoved) { 00375 menu->removeAction(action); 00376 toolBar->removeAction(action); 00377 } 00378 refreshArrowIconVisibility(); 00379 00380 if (page) { 00381 // Dock widget follows navigation bar display mode. 00382 setComponentDisplayMode(dockWidget, 00383 page->model()->navigationBarDisplayMode()); 00384 } 00385 } 00386 00387 void MApplicationWindowPrivate::_q_handlePageModelModifications(const QList<const char *> &modifications) 00388 { 00389 Q_Q(MApplicationWindow); 00390 const char *member; 00391 00392 foreach(member, modifications) { 00393 if (!pageAreaMaximized) { 00394 if (member == MApplicationPageModel::HomeButtonDisplayMode) { 00395 setComponentDisplayMode(homeButtonPanel, 00396 page->model()->homeButtonDisplayMode()); 00397 00398 } else if (member == MApplicationPageModel::NavigationBarDisplayMode) { 00399 setComponentDisplayMode(navigationBar, 00400 page->model()->navigationBarDisplayMode()); 00401 00402 // Dock widget follows navigation bar display mode. 00403 setComponentDisplayMode(dockWidget, 00404 page->model()->navigationBarDisplayMode()); 00405 00406 // Display mode can be changed between "auto-hide" and "show" which does not 00407 // affect appearance state. Need to update exposed rectangle explicitly. 00408 _q_updatePageExposedContentRect(); 00409 } 00410 } 00411 00412 if (member == MApplicationPageModel::ProgressIndicatorVisible) { 00413 navigationBar->setProgressIndicatorVisible(page->model()->progressIndicatorVisible()); 00414 00415 } else if (member == MApplicationPageModel::EscapeMode) { 00416 setupPageEscape(); 00417 00418 } else if (member == MApplicationPageModel::Title) { 00419 if (page->isVisible()) { 00420 navigationBar->setViewMenuDescription(page->model()->title()); 00421 q->setWindowTitle(longestLengthVariant(page->model()->title())); 00422 } 00423 } 00424 } 00425 } 00426 00427 void MApplicationWindowPrivate::_q_placeToolBar() 00428 { 00429 // set position of toolbar 00430 if (needsDockWidget()) { 00431 // take toolbar from navigation bar 00432 navigationBar->undockToolBar(); 00433 // dock it in lower dock widget 00434 dockWidget->dockToolBar(toolBar); 00435 // show dockwidget 00436 if (page) { 00437 // Dock widget follows navigation bar display mode. 00438 setComponentDisplayMode(dockWidget, 00439 page->model()->navigationBarDisplayMode()); 00440 } 00441 } else { 00442 // hide dockwidget 00443 dockWidget->disappear(); 00444 // undock toolbar 00445 dockWidget->undockToolBar(); 00446 // redock to navigation bar 00447 navigationBar->dockToolBar(toolBar); 00448 } 00449 } 00450 00451 void MApplicationWindowPrivate::_q_updatePageExposedContentRect() 00452 { 00453 Q_Q(MApplicationWindow); 00454 if (!page) { 00455 return; 00456 } 00457 00458 qreal topCoverage = 0.0f; 00459 qreal bottomCoverage = 0.0f; 00460 00461 QRectF pageExposedContentRect; 00462 00463 if (showingStatusBar) { 00464 topCoverage += statusBar->effectiveSizeHint(Qt::PreferredSize).height(); 00465 } 00466 00467 // Interpretation of whether the navigation bar is covering the page 00468 // changes from "auto-hide" to "show". On "auto-hide" the navigation 00469 // bar doesn't count as covering the page since it does so only momentarily. 00470 const bool navBarIsCovering = showingNavigationBar && 00471 page->componentDisplayMode(MApplicationPage::NavigationBar) != MApplicationPageModel::AutoHide; 00472 00473 if (navBarIsCovering) { 00474 if (navigationBar->alignment().testFlag(Qt::AlignTop)) 00475 topCoverage += navigationBar->size().height(); 00476 else if (navigationBar->alignment().testFlag(Qt::AlignBottom)) 00477 bottomCoverage += navigationBar->size().height(); 00478 } 00479 00480 00481 if (showingDockWidget) { 00482 if (dockWidget->alignment().testFlag(Qt::AlignTop)) 00483 topCoverage += dockWidget->size().height(); 00484 else if (dockWidget->alignment().testFlag(Qt::AlignBottom)) 00485 bottomCoverage += dockWidget->size().height(); 00486 } 00487 00488 pageExposedContentRect.setY(topCoverage); 00489 pageExposedContentRect.setWidth(q->visibleSceneSize().width()); 00490 pageExposedContentRect.setHeight(q->visibleSceneSize().height() 00491 - pageExposedContentRect.y() - bottomCoverage); 00492 00493 page->d_func()->setExposedContentRect(pageExposedContentRect); 00494 } 00495 00496 void MApplicationWindowPrivate::openMenu() 00497 { 00498 Q_Q(MApplicationWindow); 00499 if (navigationBar->isArrowIconVisible() && 00500 (navigationBar->sceneWindowState() != MSceneWindow::Disappearing)) { 00501 menu->appear(q); 00502 navigationBar->setEscapeButtonEnabled(false); 00503 00504 // Simply calling setEnabled(false) would uncheck the currently 00505 // checked item in the toolbar if tab view is being used. 00506 toolBar->setProperty(_M_IsEnabledPreservingSelection, QVariant(false)); 00507 } 00508 } 00509 00510 void MApplicationWindowPrivate::closeMenu() 00511 { 00512 if (menu->sceneWindowState() == MSceneWindow::Appeared || menu->sceneWindowState() == MSceneWindow::Appearing) 00513 menu->disappear(); 00514 } 00515 00516 bool MApplicationWindowPrivate::isMenuOpen() const 00517 { 00518 return (menu->sceneWindowState() == MSceneWindow::Appeared); 00519 } 00520 00521 void MApplicationWindowPrivate::_q_menuAppeared() 00522 { 00523 Q_Q(MApplicationWindow); 00524 QObject::disconnect(navigationBar, SIGNAL(viewmenuTriggered()), 00525 q, SLOT(openMenu())); 00526 QObject::connect(navigationBar, SIGNAL(viewmenuTriggered()), 00527 q, SLOT(closeMenu())); 00528 autoHideComponentsTimer.stop(); 00529 } 00530 00531 void MApplicationWindowPrivate::_q_menuDisappeared() 00532 { 00533 Q_Q(MApplicationWindow); 00534 QObject::disconnect(navigationBar, SIGNAL(viewmenuTriggered()), 00535 q, SLOT(closeMenu())); 00536 QObject::connect(navigationBar, SIGNAL(viewmenuTriggered()), 00537 q, SLOT(openMenu())); 00538 00539 navigationBar->setEscapeButtonEnabled(true); 00540 toolBar->setProperty(_M_IsEnabledPreservingSelection, QVariant(true)); 00541 00542 if (!componentsOnAutoHide.isEmpty() && !autoHideComponentsTimer.isActive()) 00543 autoHideComponentsTimer.start(); 00544 } 00545 00546 void MApplicationWindowPrivate::_q_navigationBarStateChanged( 00547 MSceneWindow::SceneWindowState newState, MSceneWindow::SceneWindowState oldState) 00548 { 00549 // Check for an animated or immediate disappearance. 00550 if (newState == MSceneWindow::Disappearing || 00551 (newState == MSceneWindow::Disappeared && oldState == MSceneWindow::Appeared)) { 00552 closeMenu(); 00553 } 00554 } 00555 00556 #ifdef M_OS_MAEMO5 00557 void MApplicationWindowPrivate::_q_exitAppView() 00558 { 00559 QDBusConnection bus = QDBusConnection::sessionBus(); 00560 QDBusMessage message = QDBusMessage::createSignal("/", "com.nokia.hildon_desktop", "exit_app_view"); 00561 bus.send(message); 00562 } 00563 #endif //M_OS_MAEMO5 00564 00565 void MApplicationWindowPrivate::manageActions() 00566 { 00567 Q_Q(MApplicationWindow); 00568 00569 QAction* checkedAction = findCheckedAction(page->actions()); 00570 if (!checkedAction) { 00571 checkedAction = findCheckedAction(q->actions()); 00572 } 00573 00574 toolBar->clearActions(); 00575 menu->clearActions(); 00576 00577 // add page actions 00578 QList<QAction *> actions = page->actions(); 00579 int actionsSize = actions.size(); 00580 for (int i = 0; i < actionsSize; ++i) { 00581 distributeAction(actions[i], NULL); 00582 } 00583 00584 // add window actions 00585 actions = q->actions(); 00586 actionsSize = actions.size(); 00587 for (int i = 0; i < actionsSize; ++i) { 00588 distributeAction(actions[i], NULL); 00589 } 00590 00591 if (checkedAction) { 00592 checkedAction->setChecked(true); 00593 } 00594 00595 refreshArrowIconVisibility(); 00596 } 00597 00598 void MApplicationWindowPrivate::distributeAction(QAction *action, QAction *before) 00599 { 00600 //The toolbar and menu will check for themselves whether to actually show the action or not 00601 toolBar->insertAction(before, action); 00602 menu->insertAction(before, action); 00603 } 00604 00605 void MApplicationWindowPrivate::refreshArrowIconVisibility() 00606 { 00607 bool haveVisibleMenuAction = false; 00608 foreach(QAction *action, menu->actions()) { 00609 if(action->isVisible()) { 00610 MAction *maction = qobject_cast<MAction*>(action); 00611 if(!maction || maction->location().testFlag(MAction::ApplicationMenuLocation)) { 00612 haveVisibleMenuAction = true; 00613 break; 00614 } 00615 } 00616 } 00617 navigationBar->setArrowIconVisible(haveVisibleMenuAction); 00618 updateNavigationBarVisibility(); 00619 } 00620 00621 void MApplicationWindowPrivate::setComponentDisplayMode( 00622 MSceneWindow *component, MApplicationPageModel::ComponentDisplayMode displayMode) 00623 { 00624 Q_Q(MApplicationWindow); 00625 00626 switch (displayMode) { 00627 case MApplicationPageModel::Show: 00628 removeComponentFromAutoHide(component); 00629 00630 if (component == dockWidget) { 00631 // Dock widget is a special guy. 00632 updateDockWidgetVisibility(); 00633 } else if (component == navigationBar) { 00634 updateNavigationBarVisibility(); 00635 } else { 00636 component->appear(q); 00637 } 00638 break; 00639 00640 case MApplicationPageModel::AutoHide: 00641 if (!componentsOnAutoHide.contains(component)) { 00642 component->connect(&autoHideComponentsTimer, SIGNAL(timeout()), 00643 SLOT(disappear())); 00644 00645 // Visibility in sync with other components in auto-hide mode. 00646 if (autoHideComponentsTimer.isActive()) { 00647 if (component == dockWidget) { 00648 // Dock widget is a special guy. 00649 updateDockWidgetVisibility(); 00650 } else if (component == navigationBar) { 00651 updateNavigationBarVisibility(); 00652 } else { 00653 sceneManager->appearSceneWindowNow(component); 00654 } 00655 } else { 00656 component->disappear(); 00657 } 00658 00659 componentsOnAutoHide << component; 00660 } 00661 break; 00662 00663 case MApplicationPageModel::Hide: 00664 removeComponentFromAutoHide(component); 00665 component->disappear(); 00666 break; 00667 }; 00668 00669 if (componentsOnAutoHide.count() == 0) { 00670 autoHideComponentsTimer.stop(); 00671 } 00672 } 00673 00674 void MApplicationWindowPrivate::removeComponentFromAutoHide(MSceneWindow *component) 00675 { 00676 if (componentsOnAutoHide.contains(component)) { 00677 autoHideComponentsTimer.disconnect(SIGNAL(timeout()), 00678 component, SLOT(disappear())); 00679 00680 componentsOnAutoHide.removeAll(component); 00681 } 00682 } 00683 00684 void MApplicationWindowPrivate::updateDockWidgetVisibility() 00685 { 00686 // Make dock widget visible only if a toolbar is docked and 00687 // the docked toolbar has some actions 00688 00689 if (!dockWidget->toolBar() || !needsDockWidget()) { 00690 return; 00691 } 00692 00693 QList<QAction *> actions = toolBar->actions(); 00694 int count = actions.count(); 00695 bool toolbarHasVisibleActions = false; 00696 for (int i = 0; i < count; ++i) { 00697 if (actions[i]->isVisible()) { 00698 MAction *action = qobject_cast<MAction*>(actions[i]); 00699 if(!action || action->location().testFlag(MAction::ToolBarPortraitLocation)) { 00700 toolbarHasVisibleActions = true; 00701 break; 00702 } 00703 } 00704 } 00705 00706 if (toolbarHasVisibleActions) { 00707 //TODO: no animation until appear/disappear starts working properly 00708 sceneManager->appearSceneWindowNow(dockWidget); 00709 } else { 00710 sceneManager->disappearSceneWindowNow(dockWidget); 00711 } 00712 00713 } 00714 00715 void MApplicationWindowPrivate::updateNavigationBarVisibility() 00716 { 00717 if (!page || page->model()->navigationBarDisplayMode() == MApplicationPageModel::Hide 00718 || (page->model()->navigationBarDisplayMode() == MApplicationPageModel::AutoHide 00719 && !autoHideComponentsTimer.isActive())) 00720 { 00721 return; 00722 } 00723 00724 Q_Q(MApplicationWindow); 00725 00726 bool emptyNavigationbar = navigationBar->property("isEmpty").toBool(); 00727 bool emptyToolbar = false; 00728 if (q->orientation() == M::Landscape) 00729 emptyToolbar = toolBar->property("emptyInLandscape").toBool(); 00730 else 00731 emptyToolbar = toolBar->property("emptyInPortrait").toBool(); 00732 00733 if (emptyNavigationbar && (needsDockWidget() || emptyToolbar)) 00734 sceneManager->disappearSceneWindow(navigationBar); 00735 else 00736 sceneManager->appearSceneWindow(navigationBar); 00737 } 00738 00739 void MApplicationWindowPrivate::sceneWindowAppearEvent(MSceneWindowEvent *event) 00740 { 00741 // Note that, when listening scene window state changed events, the actual state 00742 // of the scene window is not yet changed, and is needed to store separately 00743 // before call to _q_updatePageExposedContentRect(). 00744 00745 MSceneWindow *sceneWindow = event->sceneWindow(); 00746 00747 switch (sceneWindow->windowType()) { 00748 case MSceneWindow::ApplicationPage: 00749 { 00750 applicationPageAppearEvent(event); 00751 00752 #ifdef Q_WS_X11 00753 Q_Q(MApplicationWindow); 00754 if ( isChained && sceneManager ) { 00755 bool pageWindowIsFirstOne = sceneManager->pageHistory().isEmpty(); 00756 if ( pageWindowIsFirstOne ) { 00757 MApplicationPage *page = static_cast<MApplicationPage *>(sceneWindow); 00758 if ( page ) { 00759 page->setEscapeMode( MApplicationPageModel::EscapeManualBack ); 00760 QObject::connect( page, SIGNAL( backButtonClicked() ), q, SLOT( close() ) ); 00761 00762 // for title in task switcher 00763 page->setTitle( chainTaskTitle ); 00764 } 00765 } 00766 } 00767 #endif 00768 } 00769 break; 00770 00771 case MSceneWindow::StatusBar: 00772 if (!statusBar) 00773 return; 00774 showingStatusBar = true; 00775 _q_updatePageExposedContentRect(); 00776 break; 00777 00778 case MSceneWindow::NavigationBar: 00779 showingNavigationBar = true; 00780 _q_updatePageExposedContentRect(); 00781 break; 00782 00783 case MSceneWindow::DockWidget: 00784 showingDockWidget = true; 00785 _q_updatePageExposedContentRect(); 00786 break; 00787 00788 default: 00789 break; 00790 } 00791 00792 } 00793 00794 void MApplicationWindowPrivate::sceneWindowDisappearEvent(MSceneWindowEvent *event) 00795 { 00796 MSceneWindow *sceneWindow = event->sceneWindow(); 00797 00798 switch (sceneWindow->windowType()) { 00799 case MSceneWindow::ApplicationPage: 00800 applicationPageDisappearEvent(event); 00801 break; 00802 00803 case MSceneWindow::StatusBar: 00804 if(!statusBar) 00805 return; 00806 showingStatusBar = false; 00807 _q_updatePageExposedContentRect(); 00808 break; 00809 00810 case MSceneWindow::NavigationBar: 00811 showingNavigationBar = false; 00812 _q_updatePageExposedContentRect(); 00813 break; 00814 00815 case MSceneWindow::DockWidget: 00816 showingDockWidget = false; 00817 _q_updatePageExposedContentRect(); 00818 break; 00819 00820 default: 00821 break; 00822 } 00823 } 00824 00825 void MApplicationWindowPrivate::sceneWindowDismissEvent(MSceneWindowEvent *event) 00826 { 00827 // Currently we handle it in the same way as for a regular disappearance. 00828 sceneWindowDisappearEvent(event); 00829 } 00830 00831 void MApplicationWindowPrivate::applicationPageAppearEvent(MSceneWindowEvent *event) 00832 { 00833 MApplicationPage *pageFromEvent = static_cast<MApplicationPage *>(event->sceneWindow()); 00834 00835 // It cannot be the current page 00836 Q_ASSERT(pageFromEvent != page); 00837 00838 if (page != 0) { 00839 if (menu->isVisible()) 00840 menu->disappear(); 00841 disconnectPage(page); 00842 } 00843 00844 connectPage(pageFromEvent); 00845 _q_updatePageExposedContentRect(); 00846 } 00847 00848 void MApplicationWindowPrivate::applicationPageDisappearEvent(MSceneWindowEvent *event) 00849 { 00850 MApplicationPage *pageFromEvent = static_cast<MApplicationPage *>(event->sceneWindow()); 00851 00852 // Page is going away. Let's disconnect it if it's the current page. 00853 if (pageFromEvent == page) { 00854 if (menu->isVisible()) 00855 menu->disappear(); 00856 disconnectPage(pageFromEvent); 00857 } 00858 } 00859 00860 void MApplicationWindowPrivate::setupPageEscape() 00861 { 00862 if (!page) { 00863 // Nothing to be done. 00864 return; 00865 } 00866 00867 // Tear down any previous page escape setup. 00868 tearDownPageEscape(); 00869 00870 switch (page->escapeMode()) { 00871 case MApplicationPageModel::EscapeAuto: 00872 setupPageEscapeAuto(); 00873 break; 00874 00875 case MApplicationPageModel::EscapeManualBack: 00876 setupPageEscapeBack(); 00877 break; 00878 00879 case MApplicationPageModel::EscapeCloseWindow: 00880 setupPageEscapeClose(); 00881 break; 00882 00883 default: 00884 qFatal("MApplicationWindow: Invalid page escape mode"); 00885 }; 00886 00887 updateNavigationBarVisibility(); 00888 } 00889 00890 void MApplicationWindowPrivate::setupPageEscapeAuto() 00891 { 00892 Q_Q(MApplicationWindow); 00893 QList<MSceneWindow*> pageHistory = q->sceneManager()->pageHistory(); 00894 00895 if (pageHistory.isEmpty()) { 00896 setupPageEscapeClose(); 00897 } else { 00898 setupPageEscapeBack(); 00899 page->connect(page, SIGNAL(backButtonClicked()), SLOT(dismiss())); 00900 } 00901 00902 // We must update the wiring of our escape button if the application manually 00903 // changes the page history while a page in EscapeAuto mode is being displayed. 00904 q->connect(q->sceneManager(), SIGNAL(pageHistoryChanged()), SLOT(_q_updatePageEscapeAuto())); 00905 } 00906 00907 void MApplicationWindowPrivate::setupPageEscapeBack() 00908 { 00909 navigationBar->setEscapeButtonMode(MNavigationBarModel::EscapeButtonBack); 00910 } 00911 00912 void MApplicationWindowPrivate::setupPageEscapeClose() 00913 { 00914 navigationBar->setEscapeButtonMode(MNavigationBarModel::EscapeButtonClose); 00915 } 00916 00917 void MApplicationWindowPrivate::tearDownPageEscape() 00918 { 00919 Q_Q(MApplicationWindow); 00920 00921 QObject::disconnect(q->sceneManager(), SIGNAL(pageHistoryChanged()), 00922 q, SLOT(_q_updatePageEscapeAuto())); 00923 00924 QObject::disconnect(page, SIGNAL(backButtonClicked()), page, SLOT(dismiss())); 00925 } 00926 00927 void MApplicationWindowPrivate::_q_updatePageEscapeAuto() 00928 { 00929 Q_Q(MApplicationWindow); 00930 QList<MSceneWindow*> pageHistory = q->sceneManager()->pageHistory(); 00931 00932 Q_ASSERT(page != 0); 00933 Q_ASSERT(page->escapeMode() == MApplicationPageModel::EscapeAuto); 00934 00935 if (pageHistory.isEmpty() && 00936 (navigationBar->escapeButtonMode() != MNavigationBarModel::EscapeButtonClose)) { 00937 00938 QObject::disconnect(page, SIGNAL(backButtonClicked()), page, SLOT(dismiss())); 00939 // we don't want MEscapeButtonPanel::escapeModeChanged() to be intercepted 00940 // by the scene manager which would update close button geometry. 00941 // The geometry will be updated later on in connectPage(). 00942 navigationBar->blockSignals(true); 00943 setupPageEscapeClose(); 00944 navigationBar->blockSignals(false); 00945 00946 } else if (!pageHistory.isEmpty() && 00947 (navigationBar->escapeButtonMode() != MNavigationBarModel::EscapeButtonBack)) { 00948 00949 setupPageEscapeBack(); 00950 page->connect(page, SIGNAL(backButtonClicked()), SLOT(dismiss())); 00951 } 00952 } 00953 00954 bool MApplicationWindowPrivate::needsDockWidget() 00955 { 00956 return ((toolBar->viewType() == MToolBar::defaultType && style->floatableToolBar()) 00957 || (toolBar->viewType() == MToolBar::tabType && style->floatableTabBar())); 00958 } 00959 00960 void MApplicationWindowPrivate::setToolBarViewType(const MTheme::ViewType& viewType) 00961 { 00962 toolBar->setViewType(viewType); 00963 _q_placeToolBar(); 00964 updateNavigationBarVisibility(); 00965 } 00966 00967 void MApplicationWindowPrivate::_q_updateStyle() 00968 { 00969 Q_Q(MApplicationWindow); 00970 00971 const MApplicationWindowStyle *newStyle = 00972 static_cast<const MApplicationWindowStyle *>(MTheme::style( 00973 "MApplicationWindowStyle", "", "", "", q->orientation())); 00974 00975 if (style != newStyle) { 00976 MTheme::releaseStyle(style); 00977 style = newStyle; 00978 00979 _q_placeToolBar(); 00980 updateNavigationBarVisibility(); 00981 00982 } else 00983 MTheme::releaseStyle(newStyle); 00984 } 00985 00986 00987 MApplicationWindow::MApplicationWindow(MApplicationWindowPrivate &dd, QWidget *parent) 00988 : MWindow(dd, new MSceneManager, parent) 00989 { 00990 Q_D(MApplicationWindow); 00991 00992 d->init(); 00993 00994 MComponentData::registerWindow(this); 00995 } 00996 00997 MApplicationWindow::MApplicationWindow(MApplicationWindowPrivate &dd, MScene *scene, QWidget *parent) 00998 : MWindow(dd, scene, parent) 00999 { 01000 Q_D(MApplicationWindow); 01001 01002 d->init(); 01003 01004 MComponentData::registerWindow(this); 01005 } 01006 01007 MApplicationWindow::MApplicationWindow(QWidget *parent) 01008 : MWindow(*new MApplicationWindowPrivate, new MSceneManager, parent) 01009 { 01010 Q_D(MApplicationWindow); 01011 01012 d->init(); 01013 01014 MComponentData::registerWindow(this); 01015 } 01016 01017 MApplicationWindow::MApplicationWindow(MScene *scene, QWidget *parent) 01018 : MWindow(*new MApplicationWindowPrivate, scene, parent) 01019 { 01020 Q_D(MApplicationWindow); 01021 01022 d->init(); 01023 01024 MComponentData::registerWindow(this); 01025 } 01026 01027 MApplicationWindow::~MApplicationWindow() 01028 { 01029 MComponentData::unregisterWindow(this); 01030 } 01031 01032 MApplicationPage *MApplicationWindow::currentPage() const 01033 { 01034 Q_D(const MApplicationWindow); 01035 return d->page; 01036 } 01037 01038 bool MApplicationWindow::event(QEvent *event) 01039 { 01040 Q_D(MApplicationWindow); 01041 switch (event->type()) { 01042 case QEvent::ActionRemoved: { 01043 QActionEvent *actionEvent = static_cast<QActionEvent *>(event); 01044 QAction *action = actionEvent->action(); 01045 if (action) { 01046 action->disconnect(this); 01047 } 01048 //fall through is intentional 01049 } 01050 01051 case QEvent::ActionChanged: 01052 case QEvent::ActionAdded: { 01053 QActionEvent *actionEvent = static_cast<QActionEvent *>(event); 01054 d->_q_actionUpdated(actionEvent); 01055 return true; 01056 } 01057 01058 case QEvent::WindowStateChange: 01059 d->windowStateChangeEvent(static_cast<QWindowStateChangeEvent *>(event)); 01060 break; 01061 01062 default: 01063 // Do nothing 01064 break; 01065 } 01066 01067 return MWindow::event(event); 01068 } 01069 01070 // We have to send this root message because the window itself is managing 01071 // its close events. In directUi, there's no WM with a close button 01072 void MApplicationWindow::closeEvent(QCloseEvent *event) 01073 { 01074 // Don't really close if lazy shutdown used. 01075 if (!closeOnLazyShutdown()) { 01076 if (MApplication::prestartMode() == M::LazyShutdownMultiWindow || 01077 MApplication::prestartMode() == M::LazyShutdown) { 01078 closeMenu(); 01079 event->accept(); 01080 return; 01081 } 01082 } 01083 01084 #ifdef Q_WS_X11 01085 01086 if (testAttribute(Qt::WA_QuitOnClose) && windowState().testFlag(Qt::WindowNoState)) { 01087 XEvent ev; 01088 Display *dpy = QX11Info::display(); 01089 memset(&ev, 0, sizeof(ev)); 01090 01091 ev.xclient.type = ClientMessage; 01092 ev.xclient.display = dpy; 01093 ev.xclient.window = effectiveWinId(); 01094 ev.xclient.message_type = XInternAtom(dpy, "_NET_CLOSE_WINDOW", False); 01095 ev.xclient.format = 32; 01096 ev.xclient.data.l[0] = CurrentTime; 01097 ev.xclient.data.l[1] = QX11Info::appRootWindow(); 01098 01099 XSendEvent(dpy, QX11Info::appRootWindow(), False, SubstructureRedirectMask | SubstructureNotifyMask, 01100 &ev); 01101 01102 XSync(dpy, False); 01103 } 01104 #endif 01105 01106 event->accept(); 01107 } 01108 01109 void MApplicationWindow::openMenu() 01110 { 01111 Q_D(MApplicationWindow); 01112 d->openMenu(); 01113 } 01114 01115 void MApplicationWindow::closeMenu() 01116 { 01117 Q_D(MApplicationWindow); 01118 d->closeMenu(); 01119 } 01120 01121 void MApplicationWindow::setWindowIconID(const QString &windowIconID) 01122 { 01123 Q_D(MApplicationWindow); 01124 d->navigationBar->setViewMenuIconID(windowIconID); 01125 } 01126 01127 void MApplicationWindow::setToolbarViewType(const MTheme::ViewType& viewType) 01128 { 01129 Q_D(MApplicationWindow); 01130 d->setToolBarViewType(viewType); 01131 } 01132 01133 void MApplicationWindowPrivate::connectPage(MApplicationPage *newPage) 01134 { 01135 Q_Q(MApplicationWindow); 01136 01137 Q_ASSERT(newPage != 0); 01138 page = newPage; 01139 01140 q->connect(page, SIGNAL(actionUpdated(QActionEvent *)), SLOT(_q_actionUpdated(QActionEvent *))); 01141 01142 manageActions(); 01143 01144 q->connect(page->model(), SIGNAL(modified(QList<const char *>)), 01145 SLOT(_q_handlePageModelModifications(QList<const char *>))); 01146 01147 navigationBar->setViewMenuDescription(page->title()); 01148 q->setWindowTitle(longestLengthVariant(page->title())); 01149 01150 setComponentDisplayMode(homeButtonPanel, page->model()->homeButtonDisplayMode()); 01151 setComponentDisplayMode(navigationBar, page->model()->navigationBarDisplayMode()); 01152 01153 setupPageEscape(); 01154 01155 page->connect(navigationBar, SIGNAL(backButtonClicked()), SIGNAL(backButtonClicked())); 01156 page->connect(navigationBar, SIGNAL(closeButtonClicked()), SIGNAL(closeButtonClicked())); 01157 01158 // Dock widget follows navigation bar display mode. 01159 setComponentDisplayMode(dockWidget, page->model()->navigationBarDisplayMode()); 01160 01161 navigationBar->setProgressIndicatorVisible(page->model()->progressIndicatorVisible()); 01162 01163 emit q->pageChanged(page); 01164 } 01165 01166 void MApplicationWindowPrivate::disconnectPage(MApplicationPage *pageToDisconnect) 01167 { 01168 Q_UNUSED(pageToDisconnect) 01169 Q_Q(MApplicationWindow); 01170 01171 Q_ASSERT(pageToDisconnect == page); 01172 01173 QObject::disconnect(page, SIGNAL(actionUpdated(QActionEvent *)), 01174 q, SLOT(_q_actionUpdated(QActionEvent *))); 01175 01176 QObject::disconnect(page->model(), SIGNAL(modified(QList<const char *>)), 01177 q, SLOT(_q_handlePageModelModifications(QList<const char *>))); 01178 01179 tearDownPageEscape(); 01180 QObject::disconnect(navigationBar, SIGNAL(backButtonClicked()), page, 0); 01181 QObject::disconnect(navigationBar, SIGNAL(closeButtonClicked()), page, 0); 01182 01183 01184 removePageActions(); 01185 01186 page = 0; 01187 } 01188 01189 void MApplicationWindowPrivate::removePageActions() 01190 { 01191 QAction* checkedAction = findCheckedAction(page->actions()); 01192 01193 // remove all the page actions 01194 QList<QAction *> actions = page->actions(); 01195 int actionsSize = actions.size(); 01196 for (int i = 0; i < actionsSize; ++i) { 01197 QAction* action = actions[i]; 01198 QAction* toolbarAction = 0; 01199 if (toolBar->viewType() == MToolBar::tabType && 01200 toolBar->actions().contains(action)) { 01201 toolbarAction = action; 01202 } 01203 toolBar->removeAction(action); 01204 menu->removeAction(action); 01205 if (toolbarAction) 01206 toolbarAction->setChecked(false); 01207 } 01208 01209 // restore the checked action 01210 if (checkedAction) { 01211 checkedAction->setChecked(true); 01212 } 01213 } 01214 01215 QAction* MApplicationWindowPrivate::findCheckedAction(const QList<QAction *> &actions) const 01216 { 01217 QAction* checkedAction = 0; 01218 int actionsSize = actions.size(); 01219 if (toolBar->viewType() == MToolBar::tabType) { 01220 for (int i = 0; i < actionsSize; ++i) { 01221 QAction* action = actions[i]; 01222 MAction* mAction = qobject_cast<MAction*>(action); 01223 bool isToolbarAction = (!mAction || mAction->location().testFlag(MAction::ToolBarPortraitLocation) || 01224 mAction->location().testFlag(MAction::ToolBarLandscapeLocation)); 01225 if (action->isChecked() && isToolbarAction) { 01226 checkedAction = action; 01227 break; 01228 } 01229 } 01230 } 01231 return checkedAction; 01232 } 01233 01234 QString MApplicationWindow::windowIconID() const 01235 { 01236 Q_D(const MApplicationWindow); 01237 return d->navigationBar->viewMenuIconID(); 01238 } 01239 01240 MTheme::ViewType MApplicationWindow::toolbarViewType() const 01241 { 01242 Q_D(const MApplicationWindow); 01243 return d->toolBar->viewType(); 01244 } 01245 01246 bool MApplicationWindow::isMenuOpen() const 01247 { 01248 Q_D(const MApplicationWindow); 01249 return d->isMenuOpen(); 01250 } 01251 01252 #ifdef Q_WS_X11 01253 WId MApplicationWindow::chainParentWinId() const 01254 { 01255 Q_D(const MApplicationWindow); 01256 return d->chainParentWinId; 01257 } 01258 01259 bool MApplicationWindow::isChained() const 01260 { 01261 Q_D(const MApplicationWindow); 01262 return d->isChained; 01263 } 01264 #endif 01265 01266 void MApplicationWindow::mousePressEvent(QMouseEvent *event) 01267 { 01268 Q_D(MApplicationWindow); 01269 01270 if (d->autoHideComponentsTimer.isActive()) { 01271 d->autoHideComponentsTimer.stop(); 01272 } 01273 01274 MWindow::mousePressEvent(event); 01275 } 01276 01277 void MApplicationWindow::mouseReleaseEvent(QMouseEvent *event) 01278 { 01279 Q_D(MApplicationWindow); 01280 MSceneWindow *component; 01281 01282 if (isMenuOpen()) { 01283 if (d->navigationBar->boundingRect().contains(d->navigationBar->mapFromScene(event->pos().x(), event->pos().y())) 01284 || d->toolBar->boundingRect().contains(d->toolBar->mapFromScene(event->pos().x(), event->pos().y()))) { 01285 closeMenu(); 01286 } 01287 } 01288 01289 MWindow::mouseReleaseEvent(event); 01290 01291 if (d->componentsOnAutoHide.count() > 0) { 01292 // restart timer 01293 d->autoHideComponentsTimer.start(); 01294 01295 const int count = d->componentsOnAutoHide.count(); 01296 for (int i = 0; i < count; ++i) { 01297 component = d->componentsOnAutoHide.at(i); 01298 01299 if (component == d->dockWidget) { 01300 // Dock widget is a special guy. 01301 d->updateDockWidgetVisibility(); 01302 } else if (component == d->navigationBar) { 01303 d->updateNavigationBarVisibility(); 01304 } else if (component->sceneWindowState() != MSceneWindow::Disappearing) { 01305 component->appear(this); 01306 } 01307 } 01308 01309 } 01310 } 01311 01312 #include "moc_mapplicationwindow.cpp"
| Copyright © 2010 Nokia Corporation | Generated on Thu Nov 4 2010 18:14:20 (PDT) Doxygen 1.7.1 |
MeeGo Touch |