--- /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 <QtGui>
+#include <QDebug>
+#include <QtAlgorithms>
+
+#include <hblabel.h>
+#include <hbstyle.h>
+#include <hbiconitem.h>
+#include <hbaction.h>
+#include <hbstackedlayout.h>
+#include <hbmainwindow.h>
+
+#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; i<mMainLayout->count(); 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<BubbleHandler*>* 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<BubbleHandler*>* 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<BubbleHeader*> 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<BubbleHeader*> 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();
+ }
+ }
+ }
+}
+
+