homescreenapp/stateplugins/hshomescreenstateplugin/src/hsidlewidget.cpp
changeset 35 f9ce957a272c
child 36 cdae8c6c3876
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/homescreenapp/stateplugins/hshomescreenstateplugin/src/hsidlewidget.cpp	Fri Mar 19 09:27:44 2010 +0200
@@ -0,0 +1,426 @@
+/*
+* 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 <QGraphicsSceneMouseEvent>
+#include <QGraphicsLinearLayout>
+#include <QDir>
+
+#include <HbMainWindow>
+#include <HbInputMethod>
+
+#include "hsidlewidget.h"
+#include "hsscene.h"
+#include "hspage.h"
+#include "hswidgethost.h"
+#include "hswallpaper.h"
+#include "hstrashbinwidget.h"
+#include "hspageindicator.h"
+#include "hsdocumentloader.h"
+
+namespace
+{
+    const char CONTROL_LAYER_DOCML_FILE[] = "controllayer.docml";
+    const char CONTROL_LAYER[] = "controlLayer";
+    const char TRASH_BIN[] = "trashBin";
+    const char PAGE_INDICATOR[] = "pageIndicator";
+}
+
+/*!
+    \class HsIdleWidget
+    \ingroup group_hshomescreenstateplugin
+    \brief View part of the home screen idle state.
+
+    Maintains the idle view ui layers and takes care of 
+    receiving user input and communicating it to the idle 
+    state for further processing.
+*/
+
+/*!
+    Constructs a new idle widget with the given \a parent.
+*/
+HsIdleWidget::HsIdleWidget(QGraphicsItem *parent)
+  : HbWidget(parent),
+    mControlLayer(0), mPageLayer(0), mSceneLayer(0),
+    mDelayedPressEvent(0),
+    mTrashBin(0), mPageIndicator(0)
+{
+    setFlag(ItemHasNoContents);
+    
+    loadControlLayer();
+
+    QGraphicsLinearLayout *linearLayout = 0;
+
+    linearLayout = new QGraphicsLinearLayout(Qt::Horizontal);
+    linearLayout->setContentsMargins(0, 0, 0, 0);
+    linearLayout->setSpacing(0);
+    mPageLayer = new HbWidget(this);
+    mPageLayer->setLayout(linearLayout);
+    mPageLayer->setZValue(1);
+    
+    linearLayout = new QGraphicsLinearLayout(Qt::Horizontal);
+    linearLayout->setContentsMargins(0, 0, 0, 0);
+    linearLayout->setSpacing(0);
+    mSceneLayer = new HbWidget(this);
+    mSceneLayer->setLayout(linearLayout);
+    mSceneLayer->setZValue(0);
+}
+
+/*!
+    Destroys this idle widget.
+*/
+HsIdleWidget::~HsIdleWidget()
+{
+    clearDelayedPress();
+
+    QList<HsPage *> pages = HsScene::instance()->pages();
+    foreach (HsPage *page, pages) {
+        page->setParentItem(0);
+        if (page->scene()) {
+            page->scene()->removeItem(page);
+        }
+    }
+
+    HsWallpaper *wallpaper = HsScene::instance()->wallpaper();
+    wallpaper->setParentItem(0);
+    if (wallpaper->scene()) {
+        wallpaper->scene()->removeItem(wallpaper);
+    }
+}
+
+/*!
+    Layouts the ui layers according to the given \a rect.
+*/
+void HsIdleWidget::setGeometry(const QRectF &rect)
+{
+    int n = HsScene::instance()->pages().count();
+    mControlLayer->resize(rect.size());
+    mPageLayer->resize(n * rect.width(), rect.height());
+    mSceneLayer->resize(2 * rect.width(), rect.height());
+    HbWidget::setGeometry(rect);
+}
+
+/*!
+    Stores the given mouse press \a event.
+*/
+void HsIdleWidget::captureDelayedPress(QGraphicsSceneMouseEvent *event)
+{
+    if (event) {
+        mDelayedPressEvent = new QMouseEvent(QEvent::MouseButtonPress,
+            event->scenePos().toPoint(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+        mDelayedPressEvent->setAccepted(false);
+    }
+}
+
+/*!
+    Sends the stored mouse press event.
+*/
+void HsIdleWidget::sendDelayedPress()
+{
+    if (mDelayedPressEvent) {
+        QApplication::sendEvent(HsScene::mainWindow()->viewport(), mDelayedPressEvent);
+        clearDelayedPress();     
+    }
+}
+
+/*!
+    Deletes the stored mouse press event.
+*/
+void HsIdleWidget::clearDelayedPress()
+{    
+    if (mDelayedPressEvent) {
+        delete mDelayedPressEvent;
+        mDelayedPressEvent = 0;
+    }
+}
+
+/*!
+    Sets the active page \a index to the page 
+    indicator.
+*/
+void HsIdleWidget::setActivePage(int index)
+{
+    mPageIndicator->setCurrentIndex(index);
+}
+
+/*!
+    Inserts the given \a page at index position
+    \a index in the page layer.
+*/
+void HsIdleWidget::insertPage(int index, HsPage *page)
+{
+    QGraphicsLinearLayout *layout = 
+        static_cast<QGraphicsLinearLayout *>(mPageLayer->layout());
+    layout->insertItem(index, page);
+    mPageLayer->resize(
+        layout->count() * size().width(), size().height());
+}
+
+/*!
+    Removes the page at index position
+    \a index in the page layer.
+*/
+void HsIdleWidget::removePage(int index)
+{
+    QGraphicsLinearLayout *layout = 
+        static_cast<QGraphicsLinearLayout *>(mPageLayer->layout());
+    layout->removeAt(index);
+    mPageLayer->resize(
+        layout->count() * size().width(), size().height());
+}
+
+/*!
+    \fn HsIdleWidget::controlLayer() const
+
+    Returns the control layer.
+*/
+
+/*!
+    \fn HsIdleWidget::pageLayer() const
+
+    Returns the page layer.
+*/
+
+/*!
+    \fn HsIdleWidget::sceneLayer() const
+
+    Returns the scene layer.
+*/
+
+/*!
+    \fn HsIdleWidget::trashBin() const
+
+    Returns the trashbin widget.
+*/
+
+/*!
+    \fn HsIdleWidget::pageIndicator() const
+
+    Returns the page indicator widget.
+*/
+
+/*!
+    \fn HsIdleWidget::mousePressed(QGraphicsItem *, QGraphicsSceneMouseEvent *, bool &)
+
+    The idle state connects to this signal for handling mouse
+    press events. It filters events for the item \a watched. 
+    \a event is the filtered event. Sets the \a filtered true 
+    if the event was filtered by this handler.
+*/
+
+/*!
+    \fn HsIdleWidget::mouseMoved(QGraphicsItem *, QGraphicsSceneMouseEvent *, bool &)
+
+    The idle state connects to this signal for handling mouse
+    move events. It filters events for the item \a watched. 
+    \a event is the filtered event. Sets the \a filtered true 
+    if the event was filtered by this handler.
+*/
+
+/*!
+    \fn HsIdleWidget::mouseReleased(QGraphicsItem *, QGraphicsSceneMouseEvent *, bool &)
+
+    The idle state connects to this signal for handling mouse
+    release events. It filters events for the item \a watched. 
+    \a event is the filtered event. Sets the \a filtered true 
+    if the event was filtered by this handler.
+*/
+
+/*!
+    Sets the trashbin visible and hides the page indicator.
+*/
+void HsIdleWidget::showTrashBin()
+{
+    mPageIndicator->hide();
+    mTrashBin->show();
+}
+ 
+/*!
+    Sets the page indicator visible and hides the trashbin.
+*/
+void HsIdleWidget::showPageIndicator()
+{
+    mTrashBin->hide();
+    mTrashBin->deactivate();
+    mPageIndicator->setVisible(1 < mPageIndicator->itemCount());
+}
+
+/*!
+    Filters the main window's graphics scene (\a object) \a event.
+*/
+bool HsIdleWidget::eventFilter(QObject *object, QEvent *event)
+{
+    Q_UNUSED(object)
+
+    if (HbInputMethod::activeInputMethod() &&
+        HbInputMethod::activeInputMethod()->focusObject()) {
+        setFiltersChildEvents(false);
+        return false;
+    }
+
+    bool filtered = false;
+
+    switch (event->type()) {
+    case QEvent::GraphicsSceneMousePress:
+        if (mDelayedPressEvent &&
+            scene()->mouseGrabberItem()) {
+            scene()->mouseGrabberItem()->ungrabMouse();
+        }
+        setFiltersChildEvents(!mDelayedPressEvent);
+        break;
+    case QEvent::GraphicsSceneMouseMove:
+        emit mouseMoved(0, static_cast<QGraphicsSceneMouseEvent *>(event), filtered);
+        break;
+    case QEvent::GraphicsSceneMouseRelease:
+        setItemsFocusable();
+        emit mouseReleased(0, static_cast<QGraphicsSceneMouseEvent *>(event), filtered);
+        if (filtered && scene()->mouseGrabberItem()) {
+            scene()->mouseGrabberItem()->ungrabMouse();
+        }        
+        break;
+    default:
+        break;
+    }
+
+    return filtered;
+}
+
+/*!
+    Filters events for the item \a watched. \a event is the filtered event.
+*/
+bool HsIdleWidget::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
+{
+    bool filtered = false;
+
+    switch (event->type()) {
+    case QEvent::GraphicsSceneMousePress:
+        emit mousePressed(watched, static_cast<QGraphicsSceneMouseEvent *>(event), filtered);
+        if (filtered) {
+            setItemsUnfocusable(static_cast<QGraphicsSceneMouseEvent *>(event));
+        }
+        break;    
+    default:
+        break;
+    }
+
+    return filtered;
+}
+
+/*!
+    Reimplements QGraphicsWidget::polishEvent().
+*/
+void HsIdleWidget::polishEvent()
+{
+    HsScene *scene = HsScene::instance();
+    Q_ASSERT(scene);
+
+    QGraphicsLinearLayout *layout = 
+        static_cast<QGraphicsLinearLayout *>(mPageLayer->layout());
+    QList<HsPage *> pages = scene->pages();
+    foreach (HsPage *page, pages) {
+        layout->addItem(page);
+    }
+
+    layout = static_cast<QGraphicsLinearLayout *>(mSceneLayer->layout());
+    HsWallpaper *wallpaper = HsScene::instance()->wallpaper();
+    layout->addItem(wallpaper);
+           
+    mPageIndicator->setItemCount(pages.count());
+    setActivePage(scene->activePageIndex());
+    showPageIndicator();
+
+    HsScene::mainWindow()->scene()->installEventFilter(this);
+}
+
+/*!
+    Loads the control layer declared in a docml file.
+*/
+void HsIdleWidget::loadControlLayer()
+{
+    HsDocumentLoader loader;
+    bool loaded = false;
+
+#ifndef Q_OS_SYMBIAN
+    QString path = QDir::currentPath();
+#else
+    QString path = "c:";
+#endif
+
+    QString file = path + "/hsresources/" + CONTROL_LAYER_DOCML_FILE;
+    QString fallbackPath = QString(":/") + CONTROL_LAYER_DOCML_FILE;
+
+    if (QFile::exists(file)) {
+        loader.load(file, &loaded);
+        if (!loaded) {
+            loader.load(fallbackPath, &loaded);
+        }
+    } else {
+        loader.load(fallbackPath, &loaded);       
+    }
+
+    if (loaded) {
+        mControlLayer = qobject_cast<HbWidget *>(loader.findWidget(CONTROL_LAYER));
+        mControlLayer->setZValue(2);
+        mControlLayer->setParentItem(this);
+
+        mTrashBin = qobject_cast<HsTrashBinWidget *>(loader.findWidget(TRASH_BIN));
+        mTrashBin->setZValue(1e6);
+
+        mPageIndicator = qobject_cast<HsPageIndicator *>(loader.findWidget(PAGE_INDICATOR));
+        mPageIndicator->setZValue(1e6);
+    } else {
+        // TODO: Handle error.
+    }
+}
+
+/*!
+    Sets the items under the given mouse \a event scene position 
+    unfocusable and stores the items.
+*/
+void HsIdleWidget::setItemsUnfocusable(QGraphicsSceneMouseEvent *event)
+{
+    mFocusableItems.clear();
+    QList<QGraphicsItem *> items = 
+        HsScene::mainWindow()->scene()->items(event->scenePos());
+    int i = 0;
+    while (!mPageLayer->isAncestorOf(items[i++])) {}
+    HsPage *page = HsScene::instance()->activePage();
+    QList<HsWidgetHost *> widgets = page->widgets();
+    for (; i < items.count(); ++i) {
+        QGraphicsItem *item = items.at(i);
+        if (page->isAncestorOf(item)) {
+            foreach (HsWidgetHost *widget, widgets) {
+                if ((item == widget || widget->isAncestorOf(item))&& item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) {
+                    if (!item->isWidget() || static_cast<QGraphicsWidget*>(item)->focusPolicy() & Qt::ClickFocus) {
+                        item->setFlag(QGraphicsItem::ItemIsFocusable, false);
+                        mFocusableItems.append(item);
+                    }
+                }
+            }
+        }
+    }
+}
+ 
+/*!
+    Sets the stored items focusable.
+*/
+void HsIdleWidget::setItemsFocusable()
+{
+    foreach (QGraphicsItem *item, mFocusableItems) {
+        item->setFlag(QGraphicsItem::ItemIsFocusable);
+    }
+    mFocusableItems.clear();
+}