diff -r 000000000000 -r 09774dfdd46b qtinternetradio/ui/src/irviewmanager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qtinternetradio/ui/src/irviewmanager.cpp Mon Apr 19 14:01:53 2010 +0300 @@ -0,0 +1,635 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ +#include +#include +#include + +#include "irviewmanager.h" +#include "irapplication.h" +#include "irmainview.h" +#include "ircategoryview.h" +#include "irstationsview.h" +#include "irnowplayingview.h" +#include "irsearchchannelsview.h" +#include "irfavoritesview.h" +#include "irhistoryview.h" +#include "irsettingsview.h" +#include "iropenwebaddressview.h" +#include "irsonghistoryview.h" +#include "irplsview.h" + +const int KCrossLineWidth = 30; // pixel +const double KCrossLineMinLenth = 180.0; // pixel + +const int KCrossLineTimeInterval = 1500; // ms +const int KExitTimeInterval = 800; // ms, used for showing cross Line + +const int KCrossLineMinAngle = 15; // degree +const int KCrossLineMaxAngle = 75; // degree + +static bool crossLineReady(const QLineF &aLine); +static bool crossLineIntersected(const QLineF &aLineA, const QLineF &aLineB); + +enum CrossLineAngleType +{ + EPositiveAngle = 0, // Line within 1,3 quadrant + ENegativeAngle // Line within 2,4 quadrant +}; +static CrossLineAngleType crossLineAngleType(const QLineF &aLine); + +/* + * Description : constructor. + * add a softkey action to it in order to know that back buttion is touched. + */ +IRViewManager::IRViewManager() : iViewToHide(NULL), + iCrossLineAReady(false), + iCrossLineBReady(false), + iCrossLineEnable(true), + iCrossLineShowing(false), + iCrossLineTimer(NULL), + iExitTimer(NULL), + iExiting(false) +{ + iBackAction = new HbAction(Hb::BackNaviAction, this); + connect(iBackAction, SIGNAL(triggered()), this, SLOT(backToPreviousView())); + + iExitAction = new HbAction(Hb::QuitNaviAction, this); + connect(iExitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + + connect(this, SIGNAL(currentViewChanged(HbView *)), this, SLOT(currentViewChanged(HbView *))); + + //effect for item selection + HbEffect::add("irview", ":/effect/viewchangeeffects_show.fxml", "show"); + HbEffect::add("irview", ":/effect/viewchangeeffects_hide.fxml", "hide"); + + iCrossLineTimer = new QTimer(this); + iExitTimer = new QTimer(this); + iCrossLineTimer->setSingleShot(true); + iExitTimer->setSingleShot(true); + connect(iCrossLineTimer,SIGNAL(timeout()),this,SLOT(crossLineReset())); + connect(iExitTimer,SIGNAL(timeout()),this,SLOT(exitTimeout())); +} + +/* + * Description : destructor + */ +IRViewManager::~IRViewManager() +{ + HbEffect::remove("irview", ":/effect/viewchangeeffects_show.fxml", "show"); + HbEffect::remove("irview", ":/effect/viewchangeeffects_hide.fxml", "hide"); +} + +/* + * Description : from base class IRAbstractViewManager. + * get a pointer to a specified view. If the view is not created yet, + * view manager can create it and then return pointer to it. + * Parameters : aViewId : the view's id + * aCreateIfNotExist : whether or not create a view if it doesn't exist + * Return : pointer to the specified view. + */ +IRBaseView* IRViewManager::getView(TIRViewId aViewId, bool aCreateIfNotExist) +{ + int viewNumber = views().count(); + for (int i = 0; i < viewNumber; ++i) + { + IRBaseView* addedView = static_cast(views().at(i)); + if (addedView && addedView->id() == aViewId) + { + return addedView; + } + } + + if (aCreateIfNotExist) + { + IRBaseView* newView = createView(iApplication, aViewId); + addView(newView); + return newView; + } + + return NULL; +} + +/* + * Description : from base class IRAbstractViewManager. + * Judge if a view is in the view stack. + * Parameters : aViewId : the view's id + * Return : true : the view is in view stack + * false : the view is not in view stack + */ +bool IRViewManager::isViewInStack(TIRViewId aViewId) const +{ + int numberOfViewsInStack = iViewStack.count(); + + for (int i = numberOfViewsInStack-1; i >=0 ; i--) + { + IRBaseView* view = iViewStack[i]; + if (view) + { + if (view->id() == aViewId) + { + return true; + } + } + } + + return false; +} + +/* + * Description : from base class IRAbstractViewManager. + * Activate a view specified aViewId. The new view will be current view. + * Old current view will be deactivated and pushed into view stack if + * aStackCurrent is true. + * Parameters : aViewId : the view's id. + * aStackCurrent : whether or not push current view into view stack + * Return : None + */ +void IRViewManager::activateView(TIRViewId aViewId, bool aPushCurrentView) +{ + if (isViewInStack(aViewId)) + { + backToView(aViewId); + return; + } + + IRBaseView *baseView = static_cast(currentView()); + if (baseView && baseView->id() == aViewId) + { + baseView->updateView(); + return; + } + + IRBaseView *view = getView(aViewId, true); + + if (view) + { + if (view->flag() & EViewFlag_ClearStackWhenActivate) + { + clearStack(); + } + else + { if (aPushCurrentView) + { + if (baseView && !(baseView->flag() & EViewFlag_UnStackable)) + { + iViewStack.push(baseView); + } + } + + //deactivate current view + if (baseView) + { + baseView->handleCommand(EIR_ViewCommand_DEACTIVATE, EIR_ViewCommandReason_Hide); + } + } + + switchToNextView(view); + } +} + +/* + * Description : from base class IRAbstractViewManager. + * Activate a view specified by aView. The new view will be current view. + * Old current view will be deactivated and pushed into view stack if + * aStackCurrent is true. + * Parameters : aView : pointer to the view to be activated. + * aStackCurrent : whether or not push current view into view stack + */ +void IRViewManager::activateView(IRBaseView *aView, bool aPushCurrentView) +{ + if (aView == NULL) + { + return; + } + + activateView(aView->id(), aPushCurrentView); +} + +/* + * Description : back view stack until a view whose id is aViewId. + * The view will become current view. + * Parameters : aViewId : the view's id + */ +void IRViewManager::backToView(TIRViewId aViewId) +{ + if (aViewId == currentViewId()) + { + return; + } + + //step 1 : back current view + IRBaseView *topView = static_cast(currentView()); + if (topView) + { + topView->handleCommand(EIR_ViewCommand_DEACTIVATE, EIR_ViewCommandReason_Back); + } + + //step 2 : back the views in view stack + while (!iViewStack.isEmpty()) + { + topView = iViewStack.top(); + if (topView->id() == aViewId) + { + break; + } + + topView->handleCommand(EIR_ViewCommand_DEACTIVATE, EIR_ViewCommandReason_Back); + iViewStack.pop(); + } + + //step 3 : we back to the view or the view is not in view stack. Activate it. + if (!iViewStack.isEmpty()) + { + topView = iViewStack.pop(); + Q_ASSERT(topView->id() == aViewId); + switchToNextView(topView); + + } + else + { + //backToView(id) is called when view is in stack, it's impossible to get here + Q_ASSERT(false); + } +} + +/* + * Description : from base class IRAbstractViewManager. + * return the current view's id. + * Return : current view's id. + */ +TIRViewId IRViewManager::currentViewId() const +{ + IRBaseView *topView = static_cast(currentView()); + if (topView) + { + return topView->id(); + } + + return EIRView_InvalidId; +} + +/* + * Description : from base class IRAbstractViewManager. + * handle system events reported by system event collector. + * Parameters : aEvent : see the definition of TIRSystemEventType + * Return : EIR_DoDefault : caller does default handling + * EIR_NoDefault : caller doesn't do default handling + */ +TIRHandleResult IRViewManager::handleSystemEvent(TIRSystemEventType aEvent) +{ + TIRHandleResult result = EIR_DoDefault; + IRBaseView *topView = static_cast(currentView()); + + if (topView) + { + result = topView->handleSystemEvent(aEvent); + } + + return result; +} + +/* + * Description : push a view into the view stack by id * + * Parameters : aEvent : see the definition of TIRSystemEventType + * Return : void : there is no return value for the function + * + */ +void IRViewManager::pushViewById(TIRViewId aViewId) +{ + if (isViewInStack(aViewId)) + { + return; + } + + IRBaseView *curView = getView(aViewId, true); + Q_ASSERT(curView); + iViewStack.push(curView); + + updateSoftkey(); +} + + +// slot functions + +/* + * Description : slot function for softkey action. + * Bring user to a previous view. If view stack is empty, quit application. + */ +void IRViewManager::backToPreviousView() +{ + if(iViewStack.isEmpty()) + { + return; + } + + IRBaseView *topView = static_cast(currentView()); + IRBaseView *viewToShow = iViewStack.pop(); + + if(viewToShow) + { + if(topView) + { + topView->handleCommand(EIR_ViewCommand_DEACTIVATE, EIR_ViewCommandReason_Back); + } + switchToNextView(viewToShow); + } +} + + +void IRViewManager::switchToNextView(IRBaseView *aView) +{ + if(NULL == aView) + { + return; + } + + // if this is the lauch view + if(views().count()<=1) + { + setCurrentView(aView,false); + aView->handleCommand(EIR_ViewCommand_ACTIVATED, EIR_ViewCommandReason_Show); + aView->handleCommand(EIR_ViewCommand_EffectFinished, EIR_ViewCommandReason_Show); + return; + } + + iViewToHide = static_cast(currentView()); + if(aView == iViewToHide) + { + aView->handleCommand(EIR_ViewCommand_ACTIVATED, EIR_ViewCommandReason_Show); + aView->handleCommand(EIR_ViewCommand_EffectFinished, EIR_ViewCommandReason_Show); + } + else + { + setCurrentView(aView,false); + aView->handleCommand(EIR_ViewCommand_ACTIVATED, EIR_ViewCommandReason_Show); + iViewToHide->setVisible(true); + + HbEffect::start(iViewToHide, "irview", "hide", this, "hideEffectFinished"); + HbEffect::start(aView, "irview", "show", this, "showEffectFinished"); + } +} + +void IRViewManager::hideEffectFinished(HbEffect::EffectStatus aStatus) +{ + Q_UNUSED(aStatus); + iViewToHide->setVisible(false); +} + +void IRViewManager::showEffectFinished(HbEffect::EffectStatus aStatus) +{ + Q_UNUSED(aStatus); + IRBaseView* viewToShow = static_cast(currentView()); + viewToShow->handleCommand(EIR_ViewCommand_EffectFinished, EIR_ViewCommandReason_Show); +} + + +void IRViewManager::currentViewChanged(HbView *aView) +{ + Q_UNUSED(aView); + + updateSoftkey(); +} + +/* + * Description : create a view specified by aViewId. A view is created only when it's + * first time requested + * Parameters : aApplication : pointer to ir application object + * aViewId : the view's id + * Return : pointer to the created view + */ +IRBaseView* IRViewManager::createView(IRApplication* aApplication, TIRViewId aViewId) +{ + switch (aViewId) + { + case EIRView_MainView: + return new IRMainView(aApplication, aViewId); + + case EIRView_CategoryView: + return new IRCategoryView(aApplication, aViewId); + + case EIRView_StationsView: + case EIRView_SearchResultView: + return new IRStationsView(aApplication, aViewId); + + case EIRView_PlayingView: + return new IRNowPlayingView(aApplication, aViewId); + + case EIRView_SearchView: + return new IRSearchChannelsView(aApplication, aViewId); + + case EIRView_FavoritesView: + return new IRFavoritesView(aApplication, aViewId); + + case EIRView_HistoryView: + return new IRHistoryView(aApplication, aViewId); + + case EIRView_SettingsView: + return new IRSettingsView(aApplication, aViewId); + + case EIRView_OpenWebAddressView: + return new IROpenWebAddressView(aApplication, aViewId); + + case EIRView_SongHistoryView: + return new IRSongHistoryView(aApplication, aViewId); + + case EIRView_PlsView: + return new IRPlsView(aApplication, aViewId); + + default: + break; + } + + return NULL; +} + +void IRViewManager::clearStack() +{ + IRBaseView *topView = NULL; + + //deactivate and back current view if it exists + topView = static_cast(currentView()); + if (topView) + { + topView->handleCommand(EIR_ViewCommand_DEACTIVATE, EIR_ViewCommandReason_Back); + } + + while (!iViewStack.isEmpty()) + { + topView = iViewStack.top(); + if (topView) + { + topView->handleCommand(EIR_ViewCommand_DEACTIVATE, EIR_ViewCommandReason_Back); + } + iViewStack.pop(); + } +} + +void IRViewManager::updateSoftkey() +{ + HbView *topView = currentView(); + if (topView) + { + if (iViewStack.isEmpty()) + { + topView->setNavigationAction(iExitAction); + } + else + { + topView->setNavigationAction(iBackAction); + } + } +} + +void IRViewManager::mousePressEvent(QMouseEvent *aEvent) +{ + if(iCrossLineEnable) + { + if(iCrossLineAReady) + { + iCrossLineB.setP1(aEvent->posF()); + } + else + { + iCrossLineA.setP1(aEvent->posF()); + } + } + + HbMainWindow::mousePressEvent(aEvent); +} + +void IRViewManager::mouseReleaseEvent(QMouseEvent *aEvent) +{ + if(iCrossLineEnable) + { + if(iCrossLineAReady) + { + iCrossLineTimer->stop(); + + iCrossLineB.setP2(aEvent->posF()); + iCrossLineBReady = crossLineReady(iCrossLineB); + + if(iCrossLineBReady && readyToQuit()) + { + iCrossLineEnable = false; + iCrossLineShowing = true; + viewport()->repaint(); + iExitTimer->start(KExitTimeInterval); + } + else + { + crossLineReset(); + } + } + else + { + iCrossLineA.setP2(aEvent->posF()); + iCrossLineAReady = crossLineReady(iCrossLineA); + + if(iCrossLineAReady) + { + iCrossLineTimer->stop(); + iCrossLineTimer->start(KCrossLineTimeInterval); + } + } + } + + HbMainWindow::mouseReleaseEvent(aEvent); +} + +bool IRViewManager::readyToQuit() +{ + if(iCrossLineAReady && iCrossLineBReady) + { + return crossLineIntersected(iCrossLineA,iCrossLineB); + } + + return false; +} + +bool crossLineIntersected(const QLineF &aLineA, const QLineF &aLineB) +{ + if(crossLineAngleType(aLineA) != crossLineAngleType(aLineB)) + { + return QLineF::BoundedIntersection == aLineA.intersect(aLineB,NULL); + } + + return false; +} + +void IRViewManager::paintEvent(QPaintEvent *aEvent) +{ + HbMainWindow::paintEvent(aEvent); + + if(iCrossLineShowing) + { + QPainter painter(viewport()); + painter.setPen(QPen(QColor(225,225,225,200),KCrossLineWidth)); + painter.drawLine(iCrossLineA); + painter.drawLine(iCrossLineB); + } +} + +void IRViewManager::crossLineReset() +{ + iCrossLineAReady = false; + iCrossLineBReady = false; + iCrossLineShowing = false; +} + +void IRViewManager::exitTimeout() +{ + crossLineReset(); + viewport()->repaint(); + HbMessageBox exitNote(hbTrId("txt_common_info_exiting"), + HbMessageBox::MessageTypeInformation); + exitNote.setPrimaryAction(NULL); + exitNote.exec(); + qApp->quit(); + iExiting = true; +} + +bool IRViewManager::isExiting() const +{ + return iExiting; +} + + + +CrossLineAngleType crossLineAngleType(const QLineF &aLine) +{ + int linePos = aLine.angle() / 90; + if( 0==linePos || 2==linePos ) + { + return EPositiveAngle; + } + else + { + return ENegativeAngle; + } +} + +bool crossLineReady(const QLineF &aLine) +{ + if(aLine.length()> KCrossLineMinLenth) + { + int lineDegree = qRound(aLine.angle()) % 90; + return (lineDegree<=KCrossLineMaxAngle) && (lineDegree>=KCrossLineMinAngle) ? true : false; + } + return false; +} + +