diff -r c84cf270c54f -r 92ab7f8d0eab phoneuis/bubblemanager2/bubblecore/src/bubblemanager2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phoneuis/bubblemanager2/bubblecore/src/bubblemanager2.cpp Fri Mar 19 09:28:42 2010 +0200 @@ -0,0 +1,854 @@ +/*! +* 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: BubbleManager widget. +* +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "bubblemanager2.h" +#include "bubbleheader.h" +#include "bubbleconferenceheader.h" +#include "bubbleutils.h" +#include "bubblewidgetmanager.h" +#include "bubblehandler.h" + + +BubbleManager::BubbleManager( QGraphicsItem *parent ) : + HbWidget( parent ), + mIsReadyToDraw(0), + mMuted(0), + mMutedIcon(0), + mSortHeaders(false), + mInitialized(false), + mBubbleSelectionDisabled(0) +{ + // allocate headers + BubbleHeader* header; + for ( int i = 0 ; i < BUBBLE_MAX_CALL_COUNT ; i++ ) { + header = new BubbleHeader; + header->setBubbleId( i ); + mCallHeaders.append( header ); + } + + mConferenceHeader = new BubbleConferenceHeader(); + mConferenceHeader->setBubbleId(BUBBLE_CONF_CALL_ID); + + mWidgetManager = new BubbleWidgetManager(mDefaultStyleBaseId,this); + mWidgetManager->setStylePluginName( + BubbleUtils::stylePluginNameWithPath("bubblestyleplugin.dll")); + + mMainLayout = new HbStackedLayout(this); + mMainLayout->setContentsMargins(0.0,0.0,0.0,0.0); + setLayout(mMainLayout); + + // preload views on boot + mWidgetManager->view(BubbleWidgetManager::SingleCallView); +} + +BubbleManager::~BubbleManager() +{ + qDeleteAll(mCallHeaders); + mCallHeaders.clear(); + delete mConferenceHeader; +} + +/** +* Before making any changes to bubble headers, call this function so +* manager can prapare for them properly. +*/ +void BubbleManager::startChanges() +{ + mIsReadyToDraw++; + if ( mIsReadyToDraw > 1 ) { + return; + } + + if (parentItem()) { + // reset/hide on outlooks may result clearFocus() call, + // which means that there is no focused item. move focus + // to parent item, before reset/hide calls. + parentItem()->setFocus(); + } + + // invalidate current widgets + for (int i=0; icount(); i++) { + mMainLayout->itemAt(i)->graphicsItem()->hide(); + } + + // reset active handlers + foreach (BubbleHandler* handler, mActiveHandlers) { + handler->reset(); + } + mActiveHandlers.clear(); +} + +/** +* After the changes to bubble headers call this function so manager +* can prepare bubbles to right places and check the drawing order. +* Memory for arrays has been allocated beforehand. +*/ +void BubbleManager::endChanges() +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + mIsReadyToDraw--; + if ( mIsReadyToDraw != 0 ) { + return; + } + + if (!mInitialized) { + if (mainWindow()) { + mWidgetManager->handleOrientationChange(mainWindow()->orientation()); + mInitialized=true; + } + } + + // sort active headers + if ( mActiveHeaders.count() && mSortHeaders) { + qStableSort(mActiveHeaders.begin(), + mActiveHeaders.end(), + BubbleUtils::compareHeaders ); + mSortHeaders = false; + } + + // select view + QGraphicsWidget* view = selectView(); + + if (view) { + setViewData(view); + view->show(); + } + + // restore mute state + setPhoneMuted(mMuted); + + update(); +} + +QGraphicsWidget* BubbleManager::selectView() +{ + QGraphicsWidget* view=0; + int bubbleCount = shownHeaderCount(); + + if (bubbleCount && isConferenceExpanded()) { + view = mWidgetManager->view(BubbleWidgetManager::ConferenceView); + } else { + switch(bubbleCount) { + case 1: + view = mWidgetManager->view(BubbleWidgetManager::SingleCallView); + break; + case 2: + view = mWidgetManager->view(BubbleWidgetManager::TwoCallsView); + break; + case 3: + view = mWidgetManager->view(BubbleWidgetManager::ThreeCallsView); + break; + default: + break; + } + } + + if (view) { + if (addToLayout(view)) { + // connect signals + connectSignals(view); + } + } + + return view; +} + +bool BubbleManager::addToLayout(QGraphicsWidget* widget) +{ + Q_ASSERT(widget); + + bool added=false; + int index = mMainLayout->indexOf(widget); + if (index == -1) { + mMainLayout->addItem(widget); + added=true; + } + + return added; +} + +void BubbleManager::removeFromLayout(QGraphicsWidget* widget) +{ + mMainLayout->removeItem(widget); +} + +void BubbleManager::connectSignals(QGraphicsWidget* widget) +{ + QList* handlers = mWidgetManager->handlers(widget); + if (handlers) { + foreach (BubbleHandler* handler, *handlers) { + connect(handler,SIGNAL(headerSelected(int)), + SLOT(showExpanded(int))); + } + } +} + +void BubbleManager::setViewData(QGraphicsWidget* view) +{ + Q_ASSERT(view); + + QList* handlers = + mWidgetManager->handlers(view); + + if (handlers) { + if (isConferenceExpanded()) { + // only conference call is displayed + Q_ASSERT(handlers->count()==1); + BubbleHandler* handler = handlers->at(0); + handler->readBubbleHeader(*mConferenceHeader); + mActiveHandlers.append(handler); + } else { + int i=0; + foreach (BubbleHandler* handler, *handlers) { + findNextDrawableHeader(i); + handler->readBubbleHeader(*mActiveHeaders.at(i)); + mActiveHandlers.append(handler); + i++; + if (i==mActiveHeaders.count()) { + break; + } + } + } + } +} + +/** +* Takes a new call header in use. +* Returns bubble idenfication number. +*/ +int BubbleManager::createCallHeader() +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + quint8 index = 0; + while ( mCallHeaders[index]->isUsed( ) ) { + index++; + Q_ASSERT( index < mCallHeaders.size() ); + } + + BubbleHeader* header = mCallHeaders[index]; + + header->setIsUsed( true ); + + mActiveHeaders.insert( 0, header ); // in priority order + + return header->bubbleId(); +} + +/** +* Removes call header from use +*/ +void BubbleManager::removeCallHeader( int bubbleId ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + for ( int i=0; i < mActiveHeaders.size(); i++ ) { + if ( mActiveHeaders[i]->bubbleId() == bubbleId ) { + mActiveHeaders[i]->reset(); + mActiveHeaders.remove( i ); + break; + } + } +} + +/** +* Finds header by bubble id. +*/ +bool BubbleManager::findActiveHeader( int bubbleId, BubbleHeader*& header ) +{ + header = 0; + for ( int i=0; i < mActiveHeaders.size(); i++ ) { + if ( mActiveHeaders[i]->bubbleId() == bubbleId ) { + header = mActiveHeaders[i]; + break; + } + } + + return header ? true : false; +} + +void BubbleManager::findNextDrawableHeader(int& index) const +{ + while (mActiveHeaders.at(index)->isInConference()) { + index++; + } +} + +/** +* Sets call state to header. +*/ +void BubbleManager::setState( + int bubbleId, + PhoneCallState state ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + BubbleManager::PhoneCallState oldState = + header->callState(); + + if ( shownHeaderCount()<3 && + !header->isInConference() && + (expandedBubble() != bubbleId) && + (oldState==OnHold && state==Active) ) { + // send key swap -> make active call expanded + int i = mActiveHeaders.indexOf(header); + mActiveHeaders.remove(i); + mActiveHeaders.insert(0, header); + } + + header->setCallState( state ); +} + +/** +* Sets text label to header. For conf also. +* Text to be seen in bubble ( e.g. 'on hold' ) +*/ +void BubbleManager::setLabel( + int bubbleId, + const QString& text, + Qt::TextElideMode clipDirection ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setText( text, clipDirection ); +} + +/** +* Sets caller's line identification ( name or number) to header. +* For conf also. Caller's CLI ( e.g. 'Mother' ) +*/ +void BubbleManager::setCli( + int bubbleId, + const QString& cliText, + Qt::TextElideMode clipDirection ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setCli( cliText, clipDirection ); +} + +/** +* Updates caller's line identification ( name or number) to header. +* Caller's CLI ( e.g. 'Daddy' )- +*/ +void BubbleManager::updateCLI( + int bubbleId, + const QString& cliText, + Qt::TextElideMode clipDirection ) +{ + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setCli( cliText, clipDirection ); + + // ToDo: take care of redrawing +} + +/** +* Number or voip adress, when phonebook name takes Cli. +*/ +void BubbleManager::setSecondaryCli( + int bubbleId, + const QString& cliText, + Qt::TextElideMode clipDirection ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setSecondaryCli( cliText, clipDirection ); +} + +/** +* Sets call time or cost text to header. For conf also. +*/ +void BubbleManager::setCallTime( + int bubbleId, + const QString& callTime ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setTimerCost( callTime ); +} + +/** +* Updates call time or cost text to header. For conf also. +* Timer or cost text ( e.g. '00:12:34' or '£01.23' ). +*/ +void BubbleManager::updateCallTime( + int bubbleId, + const QString& callTime ) +{ + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setTimerCost( callTime ); + + foreach (BubbleHandler* handler,mActiveHandlers) { + handler->updateTimerDisplayNow(); + } +} + +/** +* Attach a call image to header. +*/ +void BubbleManager::setCallObjectImage( + int bubbleId, + const QString& fileName ) +{ + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setCallImage(fileName); +} + +/** +* Attach the theme call image to header. +*/ +void BubbleManager::setCallObjectFromTheme( + int bubbleId ) +{ + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setCallImage(":resources/qtg_large_avatar.svg"); +} + +/** +* Sets call flags to header. +*/ +void BubbleManager::setCallFlags( + int bubbleId, + int flags ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setCallFlags( flags ); +} + +/** +* Sets call flags to header. +*/ +void BubbleManager::setCallFlag( + int bubbleId, + PhoneCallFlags flag, + bool set ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + if ( set ) { + header->setCallFlag( flag ); + } + else { + header->removeCallFlag( flag ); + } +} + +/** +* Sets number type. +*/ +void BubbleManager::setNumberType( + int bubbleId, + PhoneNumberType type ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->setNumberType( type ); +} + +/** +* Sets phone muted/unmuted. +* @param aIsMuted ETrue if phone is muted. +*/ +void BubbleManager::setPhoneMuted( + bool muted ) +{ + if (!mMutedIcon && muted) { + mMutedIcon = mWidgetManager->view(BubbleWidgetManager::MutedOverlay); + Q_ASSERT(mMutedIcon); + addToLayout(mMutedIcon); + mMutedIcon->setZValue(10.0); + } + + mMuted = muted; + if (mMutedIcon) { + mMutedIcon->setVisible(mMuted); + } +} + +/** +* Creates a conference call based upon two calls. Bubbles must be +* created first. +*/ +int BubbleManager::createConference( + int bubble1, + int bubble2 ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + mConferenceHeader->setIsUsed(true); + mActiveHeaders.append(mConferenceHeader); + addRowToConference(bubble1); + addRowToConference(bubble2); + return mConferenceHeader->bubbleId(); +} + +/** +* Splits conference call into invidual two calls. Call headers stays +* in use. Headers' state will not be changed. +*/ +void BubbleManager::removeConference() +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + mConferenceHeader->reset(); + mSortHeaders = true; + + for ( int i=0; i < mActiveHeaders.size(); i++ ) { + if ( mActiveHeaders[i]->bubbleId() == BUBBLE_CONF_CALL_ID ) { + mActiveHeaders.remove( i ); + break; + } + } +} + +/** +* Adds new call to conference call. +*/ +void BubbleManager::addRowToConference( int bubbleId ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + Q_ASSERT( !header->isInConference() ); + Q_ASSERT( !header->isConference() ); + + mConferenceHeader->addHeader(header); +} + +/** +* Takes specified call out of conference. Use RemoveConference if +* conference has only two calls in it. Header's state is same as +* before adding it to conference (if not changed inside the conf). +*/ +void BubbleManager::removeRowFromConference( int bubbleId ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + mConferenceHeader->removeHeader(bubbleId); + mSortHeaders = true; +} + +/** +* Counts calls in conference call. +*/ +int BubbleManager::conferenceRowCount() const +{ + return mConferenceHeader->headers().count(); +} + + +/** +* Sets highlight to specified line in conference. +*/ +void BubbleManager::setSelectionInConference( int rowNumber ) +{ + Q_UNUSED(rowNumber) +} + +/** +* Sets highlight to specified bubble id in conference. +*/ +void BubbleManager::setSelectionIdInConference( int bubbleId ) +{ + Q_UNUSED(bubbleId) +} + +/** +* Gets highlighted item in conference. +*/ +int BubbleManager::selectionInConference() const +{ + return -1; +} + +/** +* Gets highlighted item in conference. +*/ +int BubbleManager::selectionIdInConference() const +{ + return mConferenceHeader->selectedHeader(); +} + +/** +* Moves highligh one up if possible +*/ +void BubbleManager::moveHighlightOneUpInConference() +{ +// may be needed in non-touch +} + +/** +* Moves highligh one down if possible +*/ +void BubbleManager::moveHighlightOneDownInConference() +{ +// may be needed in non-touch +} + +/** +* Use this function to expand or shrink conference bubble. +*/ +void BubbleManager::setExpandedConferenceCallHeader( + bool expanded ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + if ( mConferenceHeader->isUsed() ) { + mConferenceHeader->setExpanded(expanded); + } +} + +/** +* Query: is conference expanded? +*/ +bool BubbleManager::isConferenceExpanded( ) const +{ + return mConferenceHeader->isExpanded(); +} + + +/** +* Number of headers shown on the screen. +*/ +int BubbleManager::shownHeaderCount() const +{ + QVectorIterator i(mActiveHeaders); + int count = 0; + while (i.hasNext()) { + if ( !i.next()->isInConference() ) { + count++; + } + } + return count; +} + +/** +* Set CLI used in participant list (text or phonenumber). +*/ +void BubbleManager::setParticipantListCli( + int bubbleId, + ParticipantListCli aParticipantCli ) +{ + Q_UNUSED(bubbleId) + Q_UNUSED(aParticipantCli) +} + +void BubbleManager::addAction( int bubbleId, HbAction* action ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->addAction(action); +} + +void BubbleManager::clearActions( int bubbleId ) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + + header->clearActions(); +} + +QGraphicsWidget* BubbleManager::graphicsWidgetForAction( + HbAction* action ) const +{ + QGraphicsWidget* widget = 0; + + foreach (BubbleHandler* handler,mActiveHandlers) { + widget = handler->graphicsWidgetForAction(action); + if (widget) { + break; + } + } + + if (!widget) { + // check if it's expand action + QVectorIterator i(mActiveHeaders); + bool bubbleWidget=false; + while (i.hasNext()) { + BubbleHeader* h = i.next(); + if ( h->expandAction() && + (h->expandAction()->text()==action->text()) ) { + bubbleWidget=true; + break; + } + } + + if (bubbleWidget) { + if ( mActiveHandlers.count()==2 ) { + widget = mWidgetManager->container( + BubbleWidgetManager::TwoCallsView, + BubbleWidgetManager::CollapsedBubble ); + } else if ( mActiveHandlers.count()==3 ) { + // return top most bubble + widget = mWidgetManager->container( + BubbleWidgetManager::ThreeCallsView, + BubbleWidgetManager::CollapsedBubble2 ); + } + } + } + + return widget; +} + +void BubbleManager::addParticipantListAction(HbAction *action) +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + mConferenceHeader->addParticipantListAction(action); +} + +void BubbleManager::clearParticipantListActions() +{ + Q_ASSERT( mIsReadyToDraw > 0 ); + mConferenceHeader->clearParticipantListActions(); +} + +int BubbleManager::expandedBubble() const +{ + // shall not be called without creating call headers first + Q_ASSERT(mActiveHeaders.count()); + + if (isConferenceExpanded()) { + return mConferenceHeader->bubbleId(); + } else { + int i=0; + findNextDrawableHeader(i); + return mActiveHeaders.at(i)->bubbleId(); + } +} + +void BubbleManager::setExpandAction(int bubbleId, HbAction* action) +{ + BubbleHeader* header = 0; + findActiveHeader( bubbleId, header ); + Q_ASSERT( header ); + header->setExpandAction(action); +} + +void BubbleManager::setBubbleSelectionDisabled(bool disabled) +{ + mBubbleSelectionDisabled = disabled; +} + +void BubbleManager::handleOrientationChange( + Qt::Orientation orientation) +{ + mWidgetManager->handleOrientationChange(orientation); +} + +void BubbleManager::polishEvent() +{ + // for debugging - remove + HbWidget::polishEvent(); +} + +void BubbleManager::showExpanded( int bubbleId ) +{ + if ( !mBubbleSelectionDisabled && (mActiveHeaders.count() > 1) ) { + int expanded = mActiveHeaders[0]->bubbleId(); + if ( bubbleId != expanded ) { + startChanges(); + // find header + BubbleHeader* header = 0; + for ( int i=0; i < mActiveHeaders.size(); i++ ) { + if ( mActiveHeaders[i]->bubbleId() == bubbleId ) { + header = mActiveHeaders[i]; + mActiveHeaders.remove(i); + break; + } + } + + Q_ASSERT(header); + + // set it first + mActiveHeaders.insert(0,header); + endChanges(); + + // trigger the expand action + HbAction* action = header->expandAction(); + if (action) { + action->trigger(); + } + } + } +} + +