diff -r 1a6714c53019 -r cce62ebc198e radiohswidget/src/radiohswidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radiohswidget/src/radiohswidget.cpp Tue Aug 31 15:15:02 2010 +0300 @@ -0,0 +1,1101 @@ +/* +* Copyright (c) 2010 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: FM Radio home screen widget +* +*/ + +// System includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// User includes +#include "radiohswidget.h" +#include "radiohswidgetprofilereader.h" +#include "radiohswidgetradioserviceclient.h" +#include "radioservicedef.h" +#include "radio_global.h" +#include "radiologger.h" + +// Constants +/** Path to docml file */ +const QString DOCML(":/ui/resource/fmradiohswidget.docml"); + +/** DOCML object name for mainLayout */ +const QString DOCML_OBJECT_NAME_MAIN_LAYOUT("mainLayout"); +/** DOCML object name for contentLayout */ +const QString DOCML_OBJECT_NAME_CONTENT_LAYOUT("contentLayout"); +/** DOCML object name for tunerBackgroundPushButton */ +const QString DOCML_OBJECT_NAME_TUNER_BACKGROUND_BUTTON( + "tunerBackgroundPushButton"); +/** DOCML object name for tunerStackedLayout */ +const QString DOCML_OBJECT_NAME_TUNER_STACKED_LAYOUT("tunerStackedLayout"); +/** DOCML object name for tunerInformationStackedLayout */ +const QString DOCML_OBJECT_NAME_TUNER_INFORMATION_STACKED_LAYOUT( + "tunerInformationStackedLayout"); +/** DOCML object name for controlButtons */ +const QString DOCML_OBJECT_NAME_CONTROL_BUTTONS_LAYOUT("controlButtons"); +/** DOCML object name for powerToggleButton */ +const QString DOCML_OBJECT_NAME_POWER_BUTTON("powerButton"); +/** DOCML object name for previousPushButton */ +const QString DOCML_OBJECT_NAME_PREVIOUS_BUTTON("previousPushButton"); +/** DOCML object name for nextPushButton */ +const QString DOCML_OBJECT_NAME_NEXT_BUTTON("nextPushButton"); +/** DOCML object name for twoRowsLayout */ +const QString DOCML_OBJECT_NAME_TWO_ROWS_LAYOUT("twoRowsLayout"); +/** DOCML object name for firstRowLabel */ +const QString DOCML_OBJECT_NAME_FIRST_ROW_LABEL("firstRowLabel"); +/** DOCML object name for secondRowLabel */ +const QString DOCML_OBJECT_NAME_SECOND_ROW_LABEL("secondRowLabel"); +/** DOCML object name for lonelyRowLabel */ +const QString DOCML_OBJECT_NAME_LONELY_ROW_LABEL("lonelyRowLabel"); +/** DOCML object name for animationIcon */ +const QString DOCML_OBJECT_NAME_ANIMATION_ICON("animationIcon"); + +/** Unknown favorite station count. */ +const int FAVORITE_STATION_COUNT_UNDEFINED(-1); +/** One favorite station set. */ +const int FAVORITE_STATION_COUNT_ONE(1); +/** Favorite station count lower boundary including this number. */ +const int FAVORITE_STATION_COUNT_LOWER_BOUNDARY(0); +/** Favorite station count upper boundary including this number. */ +const int FAVORITE_STATION_COUNT_UPPER_BOUNDARY(100); + +// Graphics identifiers for different push button states +const QString CONTROL_BUTTON_GRAPHICS_NORMAL ("qtg_fr_hsbutton_normal"); +const QString CONTROL_BUTTON_GRAPHICS_PRESSED ("qtg_fr_hsbutton_pressed"); +const QString CONTROL_BUTTON_GRAPHICS_DISABLED("qtg_fr_hsbutton_disabled"); +const QString CONTROL_BUTTON_GRAPHICS_LATCHED ("qtg_fr_hsbutton_latched"); + +// Push button icon colors for each of the states (normal, pressed, disabled +// and latched) +const QString CONTROL_BUTTON_ICON_COLOR_NORMAL ("qtc_button_normal"); +const QString CONTROL_BUTTON_ICON_COLOR_PRESSED ("qtc_button_pressed"); +const QString CONTROL_BUTTON_ICON_COLOR_DISABLED("qtc_button_disabled"); +const QString CONTROL_BUTTON_ICON_COLOR_LATCHED ("qtc_button_latched"); + +// File name suffix lists for push buttons +const QStringList POWER_BUTTON_SUFFIX( + (QStringList() << "_l" << "_c" << "_cr")); +const QStringList PREVIOUS_BUTTON_SUFFIX( + (QStringList() << "_cl" << "_c" << "_cr")); +const QStringList NEXT_BUTTON_SUFFIX( + (QStringList() << "_cl" << "_c" << "_r")); + +/** Icon for power button off. */ +const QString POWER_BUTTON_ICON_OFF("qtg_mono_power"); +/** Icon for power button on. */ +const QString POWER_BUTTON_ICON_ON ("qtg_mono_power"); + +// Tuner background button graphics for different states. +const QString TUNER_BUTTON_NORMAL_OFF("qtg_fr_tuner"); +const QString TUNER_BUTTON_NORMAL_ON("qtg_fr_tuner"); +const QString TUNER_BUTTON_NORMAL_PRESSED("qtg_fr_hsitems2_pressed"); + +/*! + \class RadioHsWidget + \brief Implementation of FM Radio home screen widget. + + RadioHsWidget implements needed functions for the FM Radio home screen + widget. +*/ + +// ======== MEMBER FUNCTIONS ======== + +/*! + Constructs a widget which is a child of \a parent, with widget flags set + to \a flags. + + Constructor should be empty and all the actual construction should be + done in onInitialize(). + */ +RadioHsWidget::RadioHsWidget(QGraphicsItem* parent, Qt::WindowFlags flags) + : HbWidget(parent, flags), + mInformationAreaBackgroundButton(NULL), + mPowerButton(NULL), + mPreviousButton(NULL), + mNextButton(NULL), + mInformationAreaTwoRowsLayout(NULL), + mInformationLonelyRowLabel(NULL), + mInformationFirstRowLabel(NULL), + mInformationSecondRowLabel(NULL), + mAnimationIcon(NULL), + mFmRadioState(FmRadio::StateUndefined), + mFavoriteStationCount(FAVORITE_STATION_COUNT_UNDEFINED), + mCurrentStationIsFavorite(false), + mProfileMonitor(NULL), + mRadioServiceClient(NULL) +{ + LOG_METHOD; +} + +/*! + Destructor + */ +RadioHsWidget::~RadioHsWidget() +{ + LOG_METHOD; +} + +/*! + Handles changes in FM Radio information. + + \param informationType Type of changed information. + \param information Actual information. + */ +void RadioHsWidget::handleRadioInformationChange(const int informationType, + const QVariant &information) +{ + LOG_METHOD; + switch (informationType) { + + case RadioServiceNotification::FavoriteCount: + LOG("FavoriteCount"); + if (information.canConvert(QVariant::Int) && + information.toInt() >= FAVORITE_STATION_COUNT_LOWER_BOUNDARY && + information.toInt() <= FAVORITE_STATION_COUNT_UPPER_BOUNDARY) { + mFavoriteStationCount = information.toInt(); + // If there are favorite stations, enable the next/previous + // buttons. + LOG_FORMAT("mFavoriteStationCount: %d", mFavoriteStationCount); + // Enable or disable buttons only if favoriteCount differs + // from 1. CurrentIsFavorite case handles situation when there + // is only one favorite station. + if (mFavoriteStationCount != FAVORITE_STATION_COUNT_ONE) { + enableStationButtons(); + } + } else { + mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED; + } + break; + + case RadioServiceNotification::CurrentIsFavorite: + LOG("CurrentIsFavorite"); + if (information.canConvert(QVariant::Bool)) { + mCurrentStationIsFavorite = information.toBool(); + LOG_FORMAT("currentIsFavorite: %d", mCurrentStationIsFavorite); + // If current station is favorite disable next/prev buttons. + // Radio sends this information only when there is only one + // favorite station set. + enableStationButtons(); + } + break; + + case RadioServiceNotification::RadioStatus: + LOG("RadioStatus"); + if (information.canConvert(QVariant::Int)) { + const int status = information.toInt(); + switch (status) { + case RadioStatus::Playing: + LOG("Playing"); + handleRadioStateChange(FmRadio::StateRunning); + break; + case RadioStatus::Muted: + LOG("Muted"); + break; + case RadioStatus::Seeking: + LEVEL2(LOG("Seeking")); + handleRadioStateChange(FmRadio::StateSeeking); + break; + case RadioStatus::NoAntenna: + LEVEL2(LOG("NoAntenna")); + handleRadioStateChange(FmRadio::StateAntennaNotConnected); + break; + case RadioStatus::PoweringOff: + LEVEL2(LOG("PoweringOff")); + handleRadioStateChange(FmRadio::StateClosing); + break; + default: + LOG("default case at case RadioStatus"); + break; + } + } + break; + + case RadioServiceNotification::Frequency: + LOG("Frequency"); + // TODO: Should information.toString() be checked for too many characters? What's the limit? + if (information.canConvert(QVariant::String)) { + LOG_FORMAT("frequency: %s", GETSTRING(information.toString())); + // TODO: Remove comment when localisation is working on device. + //frequencyString = hbTrId("txt_fmradiohswidget_rad_list_l1_mhz").arg(freqString); + bool frequencyCleared = false; + + if (mRadioInformation.contains(Frequency)) { + // Clear all infromation. + clearRadioInformation(); + frequencyCleared = true; + } + // If widget do not have any frquency information, update it. + bool frequencyUpdated = updateRadioInformation(Frequency, + information.toString()); + if (frequencyCleared || frequencyUpdated) { + // Information changed, update the UI. + changeInRadioInformation(); + mFmRadioState = FmRadio::StateRunning; + } + } + break; + + case RadioServiceNotification::Name: + LOG("Name"); + handleSimilarRadioInformation(StationName, information); + break; + + case RadioServiceNotification::Genre: + LOG("Genre"); + handleSimilarRadioInformation(Pty, information); + break; + + case RadioServiceNotification::RadioText: + LOG("RadioText"); + handleSimilarRadioInformation(RadioText, information); + break; + + case RadioServiceNotification::DynamicPS: + LOG("DynamicPS"); + handleSimilarRadioInformation(DynamicPsName, information); + break; + + default: + LOG("default case at notificationId"); + break; + } +} + +/*! + Handles changes in FM Radio state. + + \param value New state of the radio application. +*/ +void RadioHsWidget::handleRadioStateChange(const QVariant &value) +{ + LOG_METHOD; + int state; + if (value.canConvert(QVariant::Int)) { + state = value.toInt(); + } else { + return; + } + + if (state == mFmRadioState) { + // State did not change, so return. + return; + } + + switch (state) { + case FmRadio::StateUndefined: + LOG("FmRadio::StateUndefined"); + // Something went wrong. Widget should not be in this state after onInitialize(). + mFmRadioState = FmRadio::StateUndefined; + break; + case FmRadio::StateNotRunning: + LOG("FmRadio::StateNotRunning"); + mFmRadioState = FmRadio::StateNotRunning; + mRadioServiceClient->stopMonitoring(); + changePowerButtonOn(false); + mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED; + mCurrentStationIsFavorite = false; + enableStationButtons(); + clearRadioInformation(); + mInformationFirstRowLabel->setPlainText(""); + mInformationSecondRowLabel->setPlainText(""); + mInformationLonelyRowLabel->setPlainText(hbTrId("txt_fmradiohswidget_rad_list_fm_radio")); + changeInformationAreaLayout(OneRow); + break; + case FmRadio::StateStarting: + LOG("FmRadio::StateStarting"); + mFmRadioState = FmRadio::StateStarting; + changePowerButtonOn(true); + mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED; + mCurrentStationIsFavorite = false; + enableStationButtons(); + changeInformationAreaLayout(Animation); + break; + case FmRadio::StateRunning: + LOG("FmRadio::StateRunning"); + mFmRadioState = FmRadio::StateRunning; + // Stop timer if it is running because radio is now running. + mRadioServiceClient->startMonitoring( + FmRadio::VisibiltyDoNotChange); + changeInRadioInformation(); + changePowerButtonOn(true); + enableStationButtons(); + changeInformationAreaLayout(OneRow); + break; + case FmRadio::StateSeeking: + LOG("FmRadio::StateSeeking"); + mFmRadioState = FmRadio::StateSeeking; + mCurrentStationIsFavorite = false; + enableStationButtons(); + changeInformationAreaLayout(Animation); + break; + case FmRadio::StateAntennaNotConnected: + LOG("FmRadio::StateAntennaNotConnected"); + mFmRadioState = FmRadio::StateAntennaNotConnected; + mCurrentStationIsFavorite = false; + enableStationButtons(); + mInformationFirstRowLabel->setPlainText(""); + mInformationSecondRowLabel->setPlainText(""); + mInformationLonelyRowLabel->setPlainText(hbTrId( + "txt_fmradiohswidget_rad_info_connect_wired_headset")); + changeInformationAreaLayout(OneRow); + break; + case FmRadio::StateClosing: + LOG("FmRadio::StateClosing"); + mFmRadioState = FmRadio::StateClosing; + changePowerButtonOn(false); + mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED; + mCurrentStationIsFavorite = false; + enableStationButtons(); + clearRadioInformation(); + mInformationFirstRowLabel->setPlainText(""); + mInformationSecondRowLabel->setPlainText(""); + mInformationLonelyRowLabel->setPlainText(hbTrId( + "txt_fmradiohswidget_rad_list_fm_radio")); + changeInformationAreaLayout(OneRow); + break; + default: + LOG_FORMAT("default case at state. State: %d", state); + break; + } +} + +/*! + Called when widget is initialized. Constructs objects and connects them. +*/ +void RadioHsWidget::onInitialize() +{ + LOG_METHOD_ENTER; + mProfileMonitor = new RadioHsWidgetProfileReader(this); + mRadioServiceClient = new RadioHsWidgetRadioServiceClient(this); + + load(DOCML); + + // Use signal mapper to indicate button identifiers to button event + // slots. + QSignalMapper* signalMapperPressed = new QSignalMapper(this); + signalMapperPressed->setMapping(mPowerButton, Power); + signalMapperPressed->setMapping(mPreviousButton, Previous); + signalMapperPressed->setMapping(mNextButton, Next); + + // Need to use different signal mapper for pressed and released events, + // both have same mappings but they are mapped to different slots. + QSignalMapper* signalMapperReleased = new QSignalMapper(this); + signalMapperReleased->setMapping(mPowerButton, Power); + signalMapperReleased->setMapping(mPreviousButton, Previous); + signalMapperReleased->setMapping(mNextButton, Next); + + // Connect button events to signal maps. + Radio::connect(mPowerButton, SIGNAL(pressed()), signalMapperPressed, SLOT (map())); + Radio::connect(mPowerButton, SIGNAL(released()), signalMapperReleased, SLOT (map())); + Radio::connect(mPreviousButton, SIGNAL(pressed()), signalMapperPressed, SLOT (map())); + Radio::connect(mPreviousButton, SIGNAL(released()), signalMapperReleased, SLOT (map())); + Radio::connect(mNextButton, SIGNAL(pressed()), signalMapperPressed, SLOT (map())); + Radio::connect(mNextButton, SIGNAL(released()), signalMapperReleased, SLOT (map())); + + // Connect mapper signals to self implemented slots. + Radio::connect(signalMapperPressed, SIGNAL(mapped(int)), this, SLOT(changeButtonToPressed(int))); + Radio::connect(signalMapperReleased, SIGNAL(mapped(int)), this, SLOT(changeButtonToReleased(int))); + + mProfileMonitor->startMonitoringRadioRunningStatus(); +} + +/*! + Called when widget is shown in the home screen +*/ +void RadioHsWidget::onShow() +{ + LOG_METHOD_ENTER; +} + +/*! + Called when widget is hidden from the home screen +*/ +void RadioHsWidget::onHide() +{ + LOG_METHOD_ENTER; +} + +/*! + Emited from HbPushButton:pressed() signal, changes the button layout to + pressed state. + + \param hsButtonIdentifier Identifies the button which was pressed. + */ +void RadioHsWidget::changeButtonToPressed(int hsButtonIdentifier) +{ + LEVEL2(LOG_METHOD); + buttonEvent(static_cast(hsButtonIdentifier), Pressed); +} + +/*! + Emited from HbPushButton:released() signal, changes the button layout to + normal state. + + \param hsButtonIdentifier Identifies the button which was released. + */ +void RadioHsWidget::changeButtonToReleased(int hsButtonIdentifier) +{ + LEVEL2(LOG_METHOD); + buttonEvent(static_cast(hsButtonIdentifier), Normal); +} + +/*! + Slot for closing FM Radio application from power button. + */ +void RadioHsWidget::closeRadio() +{ + LOG_SLOT_CALLER; + mRadioServiceClient->commandFmRadio(RadioServiceCommand::PowerOff); +} + +/*! + Slot for previous button clicked. + */ +void RadioHsWidget::changeToPreviousStation() +{ + LOG_SLOT_CALLER; + clearRadioInformation(); + mRadioServiceClient->commandFmRadio(RadioServiceCommand::Previous); +} + +/*! + Slot for next button clicked. + */ +void RadioHsWidget::changeToNextStation() +{ + LOG_SLOT_CALLER; + clearRadioInformation(); + mRadioServiceClient->commandFmRadio(RadioServiceCommand::Next); + +} + +/*! + Slot for bringing the radio application to foreground. + */ +void RadioHsWidget::changeRadioToForeground() +{ + LOG_SLOT_CALLER; + // If radio is not running start it to foreground by monitor request. + if (mFmRadioState == FmRadio::StateNotRunning) { + bool okToStartRadio = radioStartPermission(); + if (okToStartRadio) { + handleRadioStateChange(FmRadio::StateStarting); + mRadioServiceClient->startMonitoring( + FmRadio::VisibiltyToForeground); + } + } + else { + if (mFmRadioState == FmRadio::StateClosing) { + // Radio is closing but user wants to power it up again. + mRadioServiceClient->commandFmRadio(RadioServiceCommand::PowerOn); + // Stop and start monitoring to get refresh. + mRadioServiceClient->stopMonitoring(); + mRadioServiceClient->startMonitoring( + FmRadio::VisibiltyToBackground); + handleRadioStateChange(FmRadio::StateRunning); + } + // If radio is running, bring it to the foreground. + mRadioServiceClient->commandFmRadio(RadioServiceCommand::Foreground); + } +} + +/*! + Slot for putting the radio application to the background. + */ +void RadioHsWidget::changeRadioToBackground() +{ + LOG_SLOT_CALLER; + // If radio is not running start it to background by monitor request. + if (mFmRadioState == FmRadio::StateNotRunning) { + bool okToStartRadio = radioStartPermission(); + if (okToStartRadio) { + handleRadioStateChange(FmRadio::StateStarting); + mRadioServiceClient->startMonitoring( + FmRadio::VisibiltyToBackground); + } + } + else if (mFmRadioState == FmRadio::StateStarting) { + // Do nothing if radio is starting. + } + else if (mFmRadioState == FmRadio::StateClosing) { + // Radio is closing but user wants to power it up again. + mRadioServiceClient->commandFmRadio(RadioServiceCommand::PowerOn); + // Stop and start monitoring to get refresh. + mRadioServiceClient->stopMonitoring(); + mRadioServiceClient->startMonitoring( + FmRadio::VisibiltyToBackground); + handleRadioStateChange(FmRadio::StateRunning); + } + else { + // If radio is running, put it to the background. + // This is little bit useless because the radio is in background if + // user is able to click the widget. + mRadioServiceClient->commandFmRadio(RadioServiceCommand::Background); + } +} + +/*! + Powering off or on the radio. + */ +void RadioHsWidget::toggleRadioPower() +{ + LOG_SLOT_CALLER; + // If radio is not running start it to background by monitor request. + if (mFmRadioState == FmRadio::StateNotRunning || mFmRadioState == FmRadio::StateClosing) { + LEVEL2(LOG("Power on")); + // Start radio + changeRadioToBackground(); + } else { + LEVEL2(LOG("Power off")); + // Close radio + closeRadio(); + } +} + +/*! + Loads docml file. + + \param docml Docml filename to be loaded. + */ +void RadioHsWidget::load(const QString &docml) +{ + LOG_METHOD_ENTER; + + QScopedPointer documentLoader(new HbDocumentLoader()); + bool loaded = false; + documentLoader->load(docml, &loaded); + if (loaded) { + // Find mainLayout + HbWidget *mainLayout = qobject_cast ( + documentLoader->findWidget(DOCML_OBJECT_NAME_MAIN_LAYOUT)); + + if (mainLayout) { + QGraphicsLinearLayout *widgetLayout = new QGraphicsLinearLayout( + Qt::Vertical, this); + widgetLayout->addItem(mainLayout); + setLayout(widgetLayout); + } + + // Find contentLayout + HbWidget *contentLayout = qobject_cast ( + documentLoader->findWidget(DOCML_OBJECT_NAME_CONTENT_LAYOUT)); + if (contentLayout) { + + // Find stacked layout for tuner area. + HbWidget *tunerStackedLayout = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_TUNER_STACKED_LAYOUT)); + if (tunerStackedLayout) { + + // Find stacked layout for information area. + HbWidget *tunerInformationStackedLayout = qobject_cast< + HbWidget*> (documentLoader->findWidget( + DOCML_OBJECT_NAME_TUNER_INFORMATION_STACKED_LAYOUT)); + if (tunerInformationStackedLayout) { + } + + // Find lonely label + mInformationLonelyRowLabel = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_LONELY_ROW_LABEL)); + if (mInformationLonelyRowLabel) { + // TODO: Set the color in docml when application designer supports it. + QColor color = HbColorScheme::color( + "qtc_radio_tuner_normal"); + mInformationLonelyRowLabel->setTextColor(color); + } + + // Find layout for two rows + mInformationAreaTwoRowsLayout = qobject_cast< + QGraphicsWidget *> (documentLoader->findObject( + DOCML_OBJECT_NAME_TWO_ROWS_LAYOUT)); + if (mInformationAreaTwoRowsLayout) { + // Find first row + mInformationFirstRowLabel = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_FIRST_ROW_LABEL)); + if (mInformationFirstRowLabel) { + // TODO: Set the color in docml when application designer supports it. + QColor color = HbColorScheme::color( + "qtc_radio_tuner_normal"); + mInformationFirstRowLabel->setTextColor(color); + } + + // Find second row + mInformationSecondRowLabel = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_SECOND_ROW_LABEL)); + if (mInformationSecondRowLabel) { + // TODO: Set the color in docml when application designer supports it. + QColor color = HbColorScheme::color( + "qtc_radio_tuner_normal"); + mInformationSecondRowLabel->setTextColor(color); + } + } + + mAnimationIcon = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_ANIMATION_ICON)); + if (mAnimationIcon) { + // Use animation manager to access anim loading animation. + HbIconAnimationManager *animationManager = + HbIconAnimationManager::global(); + // TODO: Axml extension can be removed after wk24 release. + animationManager->addDefinitionFile(QLatin1String( + "qtg_anim_loading.axml")); + mAnimationIcon->setIcon(HbIcon("qtg_anim_loading")); + } + } + + // Find push button for tuner area. + mInformationAreaBackgroundButton = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_TUNER_BACKGROUND_BUTTON)); + if (mInformationAreaBackgroundButton) { + // Use the frame background. + HbFrameDrawer *tunerBackgroundButtonFrameDrawer = + new HbFrameDrawer("qtg_fr_tuner", + HbFrameDrawer::ThreePiecesHorizontal); + tunerBackgroundButtonFrameDrawer->setFillWholeRect(true); + mInformationAreaBackgroundButton->setFrameBackground( + tunerBackgroundButtonFrameDrawer); + // Connect the button's clicked signal. + Radio::connect(mInformationAreaBackgroundButton, + SIGNAL(clicked()), this, SLOT(changeRadioToForeground())); + } + + // Find layout for control buttons. + HbWidget *controlButtonsLayout = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_CONTROL_BUTTONS_LAYOUT)); + if (controlButtonsLayout) { + + // Find power button. + mPowerButton + = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_POWER_BUTTON)); + if (mPowerButton) { + defineButton(*mPowerButton, + CONTROL_BUTTON_GRAPHICS_NORMAL, POWER_BUTTON_SUFFIX, + POWER_BUTTON_ICON_ON, + CONTROL_BUTTON_ICON_COLOR_NORMAL); + // Connect the button's clicked signal. + Radio::connect(mPowerButton, SIGNAL(clicked()), + this, SLOT(toggleRadioPower())); + } + + // Find previous button. + mPreviousButton = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_PREVIOUS_BUTTON)); + if (mPreviousButton) { + defineButton(*mPreviousButton, + CONTROL_BUTTON_GRAPHICS_DISABLED, + PREVIOUS_BUTTON_SUFFIX, NULL, + CONTROL_BUTTON_ICON_COLOR_DISABLED); + // Connect the button's clicked signal. + Radio::connect(mPreviousButton, SIGNAL(clicked()), + this, SLOT(changeToPreviousStation())); + } + + // Find next button. + mNextButton + = qobject_cast ( + documentLoader->findWidget( + DOCML_OBJECT_NAME_NEXT_BUTTON)); + if (mNextButton) { + defineButton(*mNextButton, + CONTROL_BUTTON_GRAPHICS_DISABLED, NEXT_BUTTON_SUFFIX, + NULL, CONTROL_BUTTON_ICON_COLOR_DISABLED); + // Connect the button's clicked signal. + Radio::connect(mNextButton, SIGNAL(clicked()), + this, SLOT(changeToNextStation())); + } + } + } + } + else { + // Docml was not succesfully loaded. UI cannot be displayed. + // Emit error to home screen framework, which removes the widget. + emit error(); + } +} + +/*! + Groups handling of similar kind of radio information (textual) to one + function. + + \param informationType Type of changed information. + \param information Actual textual information. + */ +void RadioHsWidget::handleSimilarRadioInformation( + const FmRadioInformationType informationType, const QVariant &information) +{ + LOG_METHOD_ENTER; + // TODO: Should information.toString() be checked for too many characters? What's the limit? + if (information.canConvert(QVariant::String) && updateRadioInformation( + informationType, information.toString())) { + LOG_FORMAT("informationType: %d, information: %s", informationType, GETSTRING(information.toString())); + changeInRadioInformation(); + } +} + +/*! + Check if the the radio information is changed. If it is changed, it is + also updated. + + \param informationType Type of the information. + \param information Information text. + + \returns Returns \c true, if information is updated. Returns \c false otherwise. + */ +bool RadioHsWidget::updateRadioInformation(const FmRadioInformationType informationType, + const QString &information) +{ + LOG_METHOD_RET("%d"); + // If hash contains this type of information. + if (mRadioInformation.contains(informationType)) { + // If new information is empty. + if (information.isEmpty()) { + // Remove old information from the hash. + LEVEL2(LOG_FORMAT("informationType: %s removed", GETSTRING(informationType))); + mRadioInformation.remove(informationType); + // Return true to indicate the change. + return true; + } + // If new information differs from the old one. + if (mRadioInformation[informationType].compare(information) != 0) { + // Update the information. + LEVEL2(LOG_FORMAT("informationType: %s = %s", GETSTRING(informationType), GETSTRING(information))); + mRadioInformation[informationType] = information; + // And return true to indicate the change. + return true; + } + } else { // Hash do not contain this type of information. + // If new information is not empty. + if (!information.isEmpty()) { + // Add it to the hash. + LEVEL2(LOG_FORMAT("informationType: %s = %s", GETSTRING(informationType), GETSTRING(information))); + mRadioInformation[informationType] = information; + // Return true to indicate the change. + return true; + } + } + // Return false to indicate that nothing changed. + return false; +} + +/*! + Formatting radio information texts after a change. + */ +void RadioHsWidget::changeInRadioInformation() +{ + LOG_METHOD_ENTER; + // Clear the rows. + mRadioInformationFirstRow.clear(); + mRadioInformationSecondRow.clear(); + + // First row contains station name. + if (mRadioInformation.contains(StationName)) { + mRadioInformationFirstRow.append(mRadioInformation.value(StationName)); + } + else if (mRadioInformation.contains(Frequency)) { + // Or frequency. + mRadioInformationFirstRow.append(mRadioInformation.value(Frequency)); + } LEVEL2(LOG_FORMAT("mRadioInformationFirstRow: %s", GETSTRING(mRadioInformationFirstRow))); + + // Second row of information contains radio text. + if (mRadioInformation.contains(RadioText)) { + mRadioInformationSecondRow.append(mRadioInformation.value(RadioText)); + } + else if (mRadioInformation.contains(DynamicPsName)) { + // Or Dynamic PS name. + mRadioInformationSecondRow.append(mRadioInformation.value(DynamicPsName)); + } + else if (mRadioInformation.contains(Pty)) { + // Or PTY. + mRadioInformationSecondRow.append(mRadioInformation.value(Pty)); + } + LEVEL2(LOG_FORMAT("mRadioInformationSecondRow: %s", GETSTRING(mRadioInformationSecondRow))); + + // If second row is empty. + if (mRadioInformationSecondRow.isEmpty()) { + // Show only the lonely row. + mInformationLonelyRowLabel->setPlainText(mRadioInformationFirstRow); + changeInformationAreaLayout(OneRow); + } + else { + // Else display both rows. + mInformationFirstRowLabel->setPlainText(mRadioInformationFirstRow); + mInformationSecondRowLabel->setPlainText(mRadioInformationSecondRow); + changeInformationAreaLayout(TwoRows); + } +} + +/*! + Clears the radio station information. For example, when the station is + changed, old information should be cleared. + */ +void RadioHsWidget::clearRadioInformation() +{ + LOG_METHOD_ENTER; + mRadioInformation.clear(); +} + +/*! + Changes visible widgets of information area stacked layout. + + \param layout The layout to switch visible. + */ +void RadioHsWidget::changeInformationAreaLayout(const InformationAreaLayout layout) +{ + LOG_METHOD_ENTER; + mInformationLonelyRowLabel->setVisible(layout == OneRow); + mInformationAreaTwoRowsLayout->setVisible(layout == TwoRows); + mAnimationIcon->setVisible(layout == Animation); +} + +/*! + Changes state of power button. + + \param isPowerOn \c true the power is on and \c false the power is off. + */ +void RadioHsWidget::changePowerButtonOn(const bool isPowerOn) +{ + LEVEL2(LOG_METHOD); + if (isPowerOn) { + LEVEL2(LOG("Power on")); + // TODO: Temporarily set the text to clarify the action it performs. + // Remove when graphics displays the difference. + mPowerButton->setText("Off"); + buttonEvent(Power, Latched); + } else { + LEVEL2(LOG("Power off")); + // TODO: Temporarily set the text to clarify the action it performs. + // Remove when graphics displays the difference. + mPowerButton->setText("On"); + buttonEvent(Power, Normal); + } +} + +/*! + Changes enabled state of station buttons. + */ +void RadioHsWidget::enableStationButtons() +{ + LEVEL2(LOG_METHOD_ENTER); + LOG_FORMAT("RadioHsWidget::enableStationButtons count: %d", mFavoriteStationCount); + if (mFmRadioState == FmRadio::StateAntennaNotConnected){ + changeButtonToDisabled(Next); + changeButtonToDisabled(Previous); + } + else if ((mFavoriteStationCount > 1) || (mFavoriteStationCount == 1 + && !mCurrentStationIsFavorite)) { + changeButtonToEnabled(Next); + changeButtonToEnabled(Previous); + } + else if ((mFavoriteStationCount == 1 && mCurrentStationIsFavorite) + || (mFavoriteStationCount < 1)) { + changeButtonToDisabled(Next); + changeButtonToDisabled(Previous); + } +} + +/*! + Makes homescreen specific push button based on parameters. + + \param target Target push button to modify. Must not be NULL. + \param graphicsId Defines the target button background graphics. + \param suffix Defines the suffix for the target button background graphics. + \param icon Defines the icon for the target button. + \param iconColor Defines the icon color for the target button. + */ +void RadioHsWidget::defineButton(HbPushButton &target, const QString &graphicsId, + const QStringList &suffix, const QString &icon, const QString &iconColor) +{ + LEVEL2(LOG_METHOD); + HbFrameDrawer* drawer = NULL; + + // First check if the drawer is already created for this push button + if (!target.frameBackground()) { + LEVEL2(LOG("Creating new frame background.")); + // Nope, create one now + drawer = new HbFrameDrawer(graphicsId, + HbFrameDrawer::ThreePiecesHorizontal); + target.setFrameBackground(drawer); + } + else { + // Frame drawer already created, only need to update frame graphics + drawer = target.frameBackground(); + drawer->setFrameGraphicsName(graphicsId); + } + + // Set file name suffix list, so that drawer can load correct 3-piece graphic files + drawer->setFileNameSuffixList(suffix); + + // Set the icon, if it is not NULL + if (!icon.isNull()) { + target.setIcon(HbIcon(icon)); + } + + // Update also the icon color + QColor color = HbColorScheme::color(iconColor); + target.icon().setColor(color); + + // Lastly, check if the buttton is disabled + if (iconColor == CONTROL_BUTTON_ICON_COLOR_DISABLED) { + target.setEnabled(false); + } + else { + target.setEnabled(true); + } +} + +/*! + Prepares the information needed for displaying the button correctly + reflecting its state. + + \param buttonId Identifies the button. + \param state Tells in what state the button is. + */ +void RadioHsWidget::buttonEvent(ControlButtonIdentifier buttonId, + const ControlButtonState state) +{ + LEVEL2(LOG_METHOD); + HbPushButton* target = NULL; + QStringList suffix; + QString icon; + + switch (buttonId) { + case Power: + LEVEL2(LOG("Power")); + target = mPowerButton; + icon = POWER_BUTTON_ICON_ON; + suffix = POWER_BUTTON_SUFFIX; + break; + case Previous: + LEVEL2(LOG("Previous")); + target = mPreviousButton; + suffix = PREVIOUS_BUTTON_SUFFIX; + break; + case Next: + LEVEL2(LOG("Next")); + target = mNextButton; + suffix = NEXT_BUTTON_SUFFIX; + break; + default: + LOG("default case at buttonId"); + break; + } + + QString buttonBackgroundGraphics; + QString buttonIconColors; + switch (state) { + case Normal: + LEVEL2(LOG("Normal")); + target->setProperty("state", "normal"); + buttonBackgroundGraphics = CONTROL_BUTTON_GRAPHICS_NORMAL; + buttonIconColors = CONTROL_BUTTON_ICON_COLOR_NORMAL; + break; + case Pressed: + LEVEL2(LOG("Pressed")); + target->setProperty("state", "pressed"); + buttonBackgroundGraphics = CONTROL_BUTTON_GRAPHICS_PRESSED; + buttonIconColors = CONTROL_BUTTON_ICON_COLOR_PRESSED; + break; + case Disabled: + LEVEL2(LOG("Disabled")); + target->setProperty("state", "disabled"); + buttonBackgroundGraphics = CONTROL_BUTTON_GRAPHICS_DISABLED; + buttonIconColors = CONTROL_BUTTON_ICON_COLOR_DISABLED; + break; + case Latched: + LEVEL2(LOG("Latched")); + target->setProperty("state", "latched"); + buttonBackgroundGraphics = CONTROL_BUTTON_GRAPHICS_LATCHED; + buttonIconColors = CONTROL_BUTTON_ICON_COLOR_LATCHED; + break; + default: + LOG("default case at button state"); + break; + } + + RadioHsWidget::defineButton(*target, buttonBackgroundGraphics, + suffix, icon, buttonIconColors); +} + +/*! + Disables specified push button. + + \param hsButtonIdentifier Which button is to be disabled. + */ +void RadioHsWidget::changeButtonToDisabled(int hsButtonIdentifier) +{ + LEVEL2(LOG_METHOD_ENTER); + buttonEvent(static_cast(hsButtonIdentifier), Disabled); +} + +/*! + Enabled specified push button. + + \param hsButtonIdentifier Which button is to be enabled. + */ +void RadioHsWidget::changeButtonToEnabled(int hsButtonIdentifier) +{ + LEVEL2(LOG_METHOD_ENTER); + changeButtonToReleased(hsButtonIdentifier); +} + +/*! + Checks the profile of the device. If profile is offline, user is asked a + permission to start the radio in offline profile. Dialog is shown on + behalf of the radio asking the permission. + + \returns \c true if radio can be started, \c false if device is in + offline profile and user didn't gave permission to start the radio. + */ +bool RadioHsWidget::radioStartPermission() +{ + LOG_METHOD_ENTER; + // This is true by default because we might not be in offline profile and + // starting the radio is allowed in other profiles without asking a + // permission. + bool radioStartPermssion = true; + if (mProfileMonitor->isInOfflineMode()) { + // Device is in offline profile, ask the user for permission to start + HbDeviceMessageBox box(hbTrId( + "txt_fmradiohswidget_rad_info_activate_radio_in_offline_mode_hs"), + HbMessageBox::MessageTypeQuestion); + box.setTimeout(HbPopup::NoTimeout); + box.exec(); + // radioStartPermssion is now true or false, depending what the user + // selected. If user didn't gave permission, then radio is not + // started. + radioStartPermssion = box.isAcceptAction(box.triggeredAction()); + } + return radioStartPermssion; +}