I have made the following changes intended for : CE:UX:MTF / lipstick Please review and accept or decline. BOSS has already run some checks on this request. See the "Messages from BOSS" section below.
https://build.pub.meego.com//request/show/7218 Thank You, Islam Amer [This message was auto-generated] --- Request # 7218: Messages from BOSS: State: review at 2012-10-31T12:48:03 by bossbot Reviews: accepted by bossbot : Prechecks succeeded. new for CE-maintainers : Please replace this text with a review and approve/reject the review (not the SR). BOSS will take care of the rest Changes: submit: Project:MTF:UX / lipstick -> CE:UX:MTF / lipstick changes files: -------------- --- lipstick.changes +++ lipstick.changes @@ -0,0 +1,3 @@ +* Wed Oct 31 2012 Vesa Halttunen <[email protected]> - 0.4.5 +- Support for notifications on top of all applications (from Vesa) + old: ---- lipstick-0.4.4.tar.bz2 new: ---- lipstick-0.4.5.tar.bz2 spec files: ----------- --- lipstick.spec +++ lipstick.spec @@ -9,7 +9,7 @@ # << macros Summary: QML toolkit for homescreen creation -Version: 0.4.4 +Version: 0.4.5 Release: 1 Group: System/Libraries License: LGPLv2.1 @@ -25,6 +25,8 @@ BuildRequires: pkgconfig(mlite) >= 0.0.6 BuildRequires: pkgconfig(xcomposite) BuildRequires: pkgconfig(xdamage) +BuildRequires: pkgconfig(xfixes) +BuildRequires: pkgconfig(xext) %description A QML toolkit for homescreen creation other changes: -------------- ++++++ lipstick-0.4.4.tar.bz2 -> lipstick-0.4.5.tar.bz2 --- .gitignore +++ .gitignore @@ -1,18 +0,0 @@ -Makefile -*.o -*gen_*.h -*gen_*.cpp -*gen_*.o -*moc_*.h -*moc_*.cpp -*moc_*.o -*~ -*.log -*.log.xml -*.gcno -*.gcda -*.pro.user -configure-stamp -build-stamp -.project -.cproject --- plugin/.gitignore +++ plugin/.gitignore @@ -1 +0,0 @@ -liblipstickplugin.so --- plugin/lipstickplugin.cpp +++ plugin/lipstickplugin.cpp @@ -23,6 +23,7 @@ #include <components/statusbar.h> #include <components/windowmanager.h> #include <components/windowinfo.h> +#include <notifications/notificationpreviewpresenter.h> #include <notifications/notificationlistmodel.h> #include <notifications/notification.h> @@ -41,6 +42,7 @@ qmlRegisterType<StatusBar>("org.nemomobile.lipstick", 0, 1, "StatusBar"); qmlRegisterType<NotificationListModel>("org.nemomobile.lipstick", 0, 1, "NotificationListModel"); qmlRegisterType<Notification>("org.nemomobile.lipstick", 0, 1, "Notification"); + qmlRegisterUncreatableType<NotificationPreviewPresenter>("org.nemomobile.lipstick", 0, 1, "NotificationPreviewPresenter", "This type is initialized by HomeApplication"); qmlRegisterUncreatableType<WindowInfo>("org.nemomobile.lipstick", 0, 1, "WindowInfo", "This type is initialized by SwitcherModel"); qmlRegisterUncreatableType<LauncherItem>("org.nemomobile.lipstick", 0, 1, "LauncherItem", "This type is initialized by LauncherModel"); qmlRegisterUncreatableType<WindowManager>("org.nemomobile.lipstick", 0, 1, "WindowManager", "This type should be accessed through a context property."); --- src/.gitignore +++ src/.gitignore @@ -1,2 +0,0 @@ -liblipstick.* -pkgconfig --- src/homeapplication.cpp +++ src/homeapplication.cpp @@ -33,6 +33,7 @@ #include "xtools/xwindowmanager.h" #include "xtools/homewindowmonitor.h" #include "notifications/notificationmanager.h" +#include "notifications/notificationpreviewpresenter.h" #include "components/windowmanager.h" #include "components/windowinfo.h" #include "lipsticksettings.h" @@ -73,6 +74,7 @@ // Initialize the notification manager; NotificationManager::instance(); + new NotificationPreviewPresenter(this); // Initialize the home window monitor HomeWindowMonitor::instance(); --- src/notifications/.gitignore +++ src/notifications/.gitignore @@ -1 +0,0 @@ -notificationmanageradaptor.* --- src/notifications/notificationpreviewpresenter.cpp +++ src/notifications/notificationpreviewpresenter.cpp @@ -0,0 +1,131 @@ +/*************************************************************************** +** +** Copyright (C) 2012 Jolla Ltd. +** Contact: Robin Burchell <[email protected]> +** +** This file is part of lipstick. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#include <QApplication> +#include <QDesktopWidget> +#include <QDeclarativeView> +#include <QDeclarativeContext> +#include <QX11Info> +#include <X11/extensions/shape.h> +#include "xtools/x11wrapper.h" +#include "notifications/notificationmanager.h" +#include "notificationpreviewpresenter.h" + +NotificationPreviewPresenter::NotificationPreviewPresenter(QObject *parent) : + QObject(parent), + window(0), + currentNotification(0) +{ + connect(NotificationManager::instance(), SIGNAL(notificationModified(uint)), this, SLOT(updateNotification(uint))); + connect(NotificationManager::instance(), SIGNAL(notificationRemoved(uint)), this, SLOT(removeNotification(uint))); +} + +void NotificationPreviewPresenter::showNextNotification() +{ + if (notificationQueue.isEmpty()) { + // No more notifications to show: hide the notification window if it's visible + if (window != 0 && window->isVisible()) { + window->hide(); + } + + currentNotification = 0; + emit notificationChanged(); + } else { + // A notification to show: show the notification window and the first queued notification in it + createWindowIfNecessary(); + if (!window->isVisible()) { + window->show(); + } + + currentNotification = notificationQueue.takeFirst(); + emit notificationChanged(); + } +} + +Notification *NotificationPreviewPresenter::notification() const +{ + return currentNotification; +} + +void NotificationPreviewPresenter::updateNotification(uint id) +{ + Notification *notification = NotificationManager::instance()->notification(id); + if (notificationShouldBeShown(notification)) { + // Add the notification to the queue if not already there or the current notification + if (currentNotification != notification && !notificationQueue.contains(notification)) { + notificationQueue.append(notification); + + // Show the notification if no notification currently being shown + if (currentNotification == 0) { + showNextNotification(); + } + } + } else { + removeNotification(id); + } +} + +void NotificationPreviewPresenter::removeNotification(uint id) +{ + // Remove the notification from the queue + Notification *notification = NotificationManager::instance()->notification(id); + + if (notification != 0) { + notificationQueue.removeAll(notification); + + // If the notification is currently being shown hide it - the next notification will be shown after the current one has been hidden + if (currentNotification == notification) { + currentNotification = 0; + emit notificationChanged(); + } + } +} + +void NotificationPreviewPresenter::createWindowIfNecessary() +{ + if (window != 0) { + return; + } + + window = new QDeclarativeView(); + window->setAttribute(Qt::WA_TranslucentBackground); + window->setAttribute(Qt::WA_X11DoNotAcceptFocus); + window->setAttribute(Qt::WA_X11NetWmWindowTypeNotification); + window->setWindowTitle("Notification"); + window->setResizeMode(QDeclarativeView::SizeRootObjectToView); + window->viewport()->setAutoFillBackground(false); + window->rootContext()->setContextProperty("initialSize", QApplication::desktop()->screenGeometry(window).size()); + window->rootContext()->setContextProperty("notificationPreviewPresenter", this); + window->setSource(QUrl("qrc:/qml/NotificationPreview.qml")); +} + +bool NotificationPreviewPresenter::notificationShouldBeShown(Notification *notification) +{ + return !notification->previewBody().isEmpty() && !notification->previewSummary().isEmpty(); +} + +void NotificationPreviewPresenter::setNotificationPreviewRect(qreal x1, qreal y1, qreal x2, qreal y2) +{ + Display *dpy = QX11Info::display(); + XRectangle rect; + rect.x = x1 < x2 ? x1 : x2; + rect.y = y1 < y2 ? y1 : y2; + rect.width = x1 < x2 ? (x2 - x1) : (x1 - x2); + rect.height = y1 < y2 ? (y2 - y1) : (y1 - y2); + XserverRegion shapeRegion = X11Wrapper::XFixesCreateRegion(dpy, &rect, 1); + X11Wrapper::XFixesSetWindowShapeRegion(dpy, window->winId(), ShapeInput, 0, 0, shapeRegion); + X11Wrapper::XFixesDestroyRegion(dpy, shapeRegion); + X11Wrapper::XSync(dpy, False); +} --- src/notifications/notificationpreviewpresenter.h +++ src/notifications/notificationpreviewpresenter.h @@ -0,0 +1,116 @@ +/*************************************************************************** +** +** Copyright (C) 2012 Jolla Ltd. +** Contact: Robin Burchell <[email protected]> +** +** This file is part of lipstick. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef NOTIFICATIONPREVIEWPRESENTER_H +#define NOTIFICATIONPREVIEWPRESENTER_H + +#include "lipstickglobal.h" +#include <QObject> + +class QDeclarativeView; +class Notification; + +/*! + * \class NotificationManager + * + * \brief Presents notification previews one at a time. + * + * Creates a transparent notification window which can be used to show + * notification previews. + */ +class LIPSTICK_EXPORT NotificationPreviewPresenter : public QObject +{ + Q_OBJECT + Q_PROPERTY(Notification *notification READ notification NOTIFY notificationChanged) + +public: + /*! + * Creates a notification preview presenter. + * + * \param parent the parent object + */ + explicit NotificationPreviewPresenter(QObject *parent = 0); + + /*! + * Sets the notification window's shape region according to the given + * coordinates. The coordinates should be set to match the coordinates of + * the notification preview in the window. This allows input events to be + * caught only on the notification preview area and passed through to the + * underneath window otherwise. + * + * \param x1 the X coordinate of the top left edge of the notification preview + * \param y1 the Y coordinate of the top left edge of the notification preview + * \param x2 the X coordinate of the bottom right edge of the notification preview + * \param y2 the Y coordinate of the bottom right edge of the notification preview + */ + Q_INVOKABLE void setNotificationPreviewRect(qreal x1, qreal y1, qreal x2, qreal y2); + + /*! + * Returns the notification to be currently shown or 0 if no notification + * should be shown. + * + * \return the notification to be currently shown or 0 if no notification should be shown + */ + Notification *notification() const; + +signals: + //! Sent when the notification to be shown has changed. + void notificationChanged(); + +public slots: + /*! + * Shows the next notification to be shown, if any. If the notification + * window is not yet visible, shows the window. If there is no + * notification to be shown but the window is visible, hides the window. + */ + void showNextNotification(); + +private slots: + /*! + * Updates the notification with the given ID. + * + * \param id the ID of the notification to be updated + */ + void updateNotification(uint id); + + /*! + * Removes the notification with the given ID. + * + * \param id the ID of the notification to be removed + */ + void removeNotification(uint id); + +private: + //! Creates the notification window if it has not been created yet. + void createWindowIfNecessary(); + + //! Checks whether the given notification has a preview body and a preview summary. + static bool notificationShouldBeShown(Notification *notification); + + //! The notification window + QDeclarativeView *window; + + //! Notifications to be shown + QList<Notification *> notificationQueue; + + //! Notification currently being shown + Notification *currentNotification; + +#ifdef UNIT_TEST + friend class Ut_NotificationPreviewPresenter; +#endif +}; + +#endif // NOTIFICATIONPREVIEWPRESENTER_H --- src/src.pro +++ src/src.pro @@ -2,7 +2,7 @@ TEMPLATE = lib TARGET = lipstick -VERSION = 0.4.4 +VERSION = 0.4.5 DEFINES += LIPSTICK_BUILD_LIBRARY DEBUG_NOTIFICATIONS @@ -26,7 +26,8 @@ components/windowmanager.h \ notifications/notificationmanager.h \ notifications/notification.h \ - notifications/notificationlistmodel.h + notifications/notificationlistmodel.h \ + notifications/notificationpreviewpresenter.h INSTALLS += publicheaderfiles publicheaderfiles.files = $$PUBLICHEADERS @@ -40,6 +41,7 @@ xtools/xeventlistener.h \ xtools/xatomcache.h \ xtools/xwindowmanager.h \ + xtools/x11wrapper.h \ lipstickdbusinterface.h \ lipsticksettings.h \ notifications/notificationmanager.h \ @@ -57,6 +59,7 @@ xtools/xeventlistener.cpp \ xtools/xatomcache.cpp \ xtools/xwindowmanager.cpp \ + xtools/x11wrapper.cpp \ components/windowinfo.cpp \ components/launcheritem.cpp \ components/launchermodel.cpp \ @@ -68,11 +71,12 @@ notifications/notificationmanageradaptor.cpp \ notifications/notification.cpp \ notifications/categorydefinitionstore.cpp \ - notifications/notificationlistmodel.cpp + notifications/notificationlistmodel.cpp \ + notifications/notificationpreviewpresenter.cpp CONFIG += link_pkgconfig mobility qt warn_on depend_includepath qmake_cache target_qt MOBILITY += sensors -PKGCONFIG += xcomposite mlite xdamage x11 +PKGCONFIG += xcomposite mlite xdamage x11 xfixes xext packagesExist(contentaction-0.1) { message("Using contentaction to launch applications") --- src/xtools/x11wrapper.cpp +++ src/xtools/x11wrapper.cpp @@ -0,0 +1,36 @@ +/*************************************************************************** +** +** Copyright (C) 2012 Jolla Ltd. +** Contact: Robin Burchell <[email protected]> +** +** This file is part of lipstick. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#include "x11wrapper.h" + +int X11Wrapper::XSync(Display *display, Bool discard) +{ + return ::XSync(display, discard); +} + +XserverRegion X11Wrapper::XFixesCreateRegion(Display *dpy, XRectangle *rectangles, int nrectangles) +{ + return ::XFixesCreateRegion(dpy, rectangles, nrectangles); +} + +void X11Wrapper::XFixesSetWindowShapeRegion(Display *dpy, Window win, int shape_kind, int x_off, int y_off, XserverRegion region) +{ + ::XFixesSetWindowShapeRegion(dpy, win, shape_kind, x_off, y_off, region); +} + +void X11Wrapper::XFixesDestroyRegion(Display *dpy, XserverRegion region) +{ + ::XFixesDestroyRegion(dpy, region); +} --- src/xtools/x11wrapper.h +++ src/xtools/x11wrapper.h @@ -0,0 +1,35 @@ +/*************************************************************************** +** +** Copyright (C) 2012 Jolla Ltd. +** Contact: Robin Burchell <[email protected]> +** +** This file is part of lipstick. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef X11WRAPPER_H_ +#define X11WRAPPER_H_ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xcomposite.h> +#include <X11/extensions/Xdamage.h> +#include <X11/extensions/Xfixes.h> + +class X11Wrapper +{ +public: + static int XSync(Display *display, Bool discard); + static XserverRegion XFixesCreateRegion(Display *dpy, XRectangle *rectangles, int nrectangles); + static void XFixesSetWindowShapeRegion(Display *dpy, Window win, int shape_kind, int x_off, int y_off, XserverRegion region); + static void XFixesDestroyRegion(Display *dpy, XserverRegion region); +}; + +#endif /* X11WRAPPER_H_ */ --- tests/tests.pro +++ tests/tests.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs -SUBDIRS = ut_categorydefinitionstore ut_notification ut_notificationmanager ut_notificationlistmodel ut_lipstickdbusinterface ut_lipsticksettings +SUBDIRS = ut_categorydefinitionstore ut_notification ut_notificationmanager ut_notificationlistmodel ut_lipstickdbusinterface ut_lipsticksettings ut_notificationpreviewpresenter support_files.commands += $$PWD/gen-tests-xml.sh > $$OUT_PWD/tests.xml support_files.target = support_files --- tests/ut_categorydefinitionstore/.gitignore +++ tests/ut_categorydefinitionstore/.gitignore @@ -1 +0,0 @@ -ut_categorydefinitionstore --- tests/ut_lipstickdbusinterface/.gitignore +++ tests/ut_lipstickdbusinterface/.gitignore @@ -1 +0,0 @@ -ut_lipstickdbusinterface --- tests/ut_lipsticksettings/.gitignore +++ tests/ut_lipsticksettings/.gitignore @@ -1 +0,0 @@ -ut_lipsticksettings --- tests/ut_notification/.gitignore +++ tests/ut_notification/.gitignore @@ -1 +0,0 @@ -ut_notification --- tests/ut_notificationlistmodel/.gitignore +++ tests/ut_notificationlistmodel/.gitignore @@ -1 +0,0 @@ -ut_notificationlistmodel --- tests/ut_notificationmanager/.gitignore +++ tests/ut_notificationmanager/.gitignore @@ -1 +0,0 @@ -ut_notificationmanager --- tests/ut_notificationpreviewpresenter +++ tests/ut_notificationpreviewpresenter +(directory) --- tests/ut_notificationpreviewpresenter/ut_notificationpreviewpresenter.cpp +++ tests/ut_notificationpreviewpresenter/ut_notificationpreviewpresenter.cpp @@ -0,0 +1,375 @@ +/*************************************************************************** +** +** Copyright (C) 2012 Jolla Ltd. +** Contact: Robin Burchell <[email protected]> +** +** This file is part of lipstick. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QDeclarativeView> +#include <QDeclarativeContext> +#include <QDesktopWidget> +#include "notificationmanager.h" +#include "ut_notificationpreviewpresenter.h" +#include "notificationpreviewpresenter.h" +#include "xtools/x11wrapper.h" +#include <X11/extensions/shape.h> + +Q_DECLARE_METATYPE(NotificationPreviewPresenter*) +Q_DECLARE_METATYPE(Notification*) + +QList<XRectangle> xFixesCreateRegionRectangles; +XserverRegion X11Wrapper::XFixesCreateRegion(Display *, XRectangle *rectangles, int nrectangles) +{ + for (int i = 0; i < nrectangles; i++) { + xFixesCreateRegionRectangles.append(rectangles[i]); + } + return 1; +} + +QList<Window> xFixesSetWindowShapeRegionWindow; +QList<int> xFixesSetWindowShapeRegionShapeKind; +QList<int> xFixesSetWindowShapeRegionXOff; +QList<int> xFixesSetWindowShapeRegionYOff; +QList<XserverRegion> xFixesSetWindowShapeRegionRegion; +void X11Wrapper::XFixesSetWindowShapeRegion(Display *, Window win, int shape_kind, int x_off, int y_off, XserverRegion region) +{ + xFixesSetWindowShapeRegionWindow.append(win); + xFixesSetWindowShapeRegionShapeKind.append(shape_kind); + xFixesSetWindowShapeRegionXOff.append(x_off); + xFixesSetWindowShapeRegionYOff.append(y_off); + xFixesSetWindowShapeRegionRegion.append(region); +} + +QList<XserverRegion> xFixesDestroyRegionRegion; +void X11Wrapper::XFixesDestroyRegion(Display *, XserverRegion region) +{ + xFixesDestroyRegionRegion.append(region); +} + +bool xSyncCalled = false; +int X11Wrapper::XSync(Display *, int) +{ + xSyncCalled = true; + return 0; +} + +QList<QDeclarativeView *> qDeclarativeViews; +void QDeclarativeView::setSource(const QUrl &) +{ + qDeclarativeViews.append(this); +} + +QHash<QWidget *, bool> qWidgetVisible; +void QWidget::setVisible(bool visible) +{ + setAttribute(Qt::WA_WState_Visible, visible); + qWidgetVisible[this] = visible; +} + +const char *NotificationManager::HINT_ICON = "x-nemo-icon"; +const char *NotificationManager::HINT_TIMESTAMP = "x-nemo-timestamp"; +const char *NotificationManager::HINT_PREVIEW_ICON = "x-nemo-preview-icon"; +const char *NotificationManager::HINT_PREVIEW_BODY = "x-nemo-preview-body"; +const char *NotificationManager::HINT_PREVIEW_SUMMARY = "x-nemo-preview-summary"; + +NotificationManager::NotificationManager(QObject *parent) : QObject(parent) +{ +} + +NotificationManager::~NotificationManager() +{ +} + +void NotificationManager::invokeAction(const QString &) +{ +} + +void NotificationManager::removeNotificationsWithCategory(const QString &) +{ +} + +void NotificationManager::updateNotificationsWithCategory(const QString &) +{ +} + +void NotificationManager::commit() +{ +} + +NotificationManager *notificationManagerInstance = 0; +NotificationManager *NotificationManager::instance() +{ + if (notificationManagerInstance == 0) { + notificationManagerInstance = new NotificationManager; + } + return notificationManagerInstance; +} + +QHash<uint, Notification *> notificationManagerNotification; +Notification *NotificationManager::notification(uint id) const +{ + return notificationManagerNotification.value(id); +} + +Notification *createNotification(uint id) +{ + Notification *notification = new Notification; + QVariantHash hints; + hints.insert(NotificationManager::HINT_PREVIEW_SUMMARY, "summary"); + hints.insert(NotificationManager::HINT_PREVIEW_BODY, "body"); + notification->setHints(hints); + notificationManagerNotification.insert(id, notification); + return notification; +} + +void Ut_NotificationPreviewPresenter::initTestCase() +{ + qRegisterMetaType<Notification *>(); + NotificationManager::instance()->setParent(this); +} + +void Ut_NotificationPreviewPresenter::cleanup() +{ + qDeclarativeViews.clear(); + qWidgetVisible.clear(); + qDeleteAll(notificationManagerNotification); + notificationManagerNotification.clear(); +} + +void Ut_NotificationPreviewPresenter::testSignalConnections() +{ + NotificationPreviewPresenter presenter; + QCOMPARE(disconnect(NotificationManager::instance(), SIGNAL(notificationModified(uint)), &presenter, SLOT(updateNotification(uint))), true); + QCOMPARE(disconnect(NotificationManager::instance(), SIGNAL(notificationRemoved(uint)), &presenter, SLOT(removeNotification(uint))), true); +} + +void Ut_NotificationPreviewPresenter::testAddNotificationWhenWindowNotOpen() +{ + NotificationPreviewPresenter presenter; + QSignalSpy spy(&presenter, SIGNAL(notificationChanged())); + + // Check that the window is not automatically created + QCOMPARE(qDeclarativeViews.isEmpty(), true); + + // Check that the window is created when a notification is added + Notification *notification = createNotification(1); + presenter.updateNotification(1); + QCOMPARE(qDeclarativeViews.count(), 1); + + // Check window properties + QCOMPARE(qDeclarativeViews.first()->testAttribute(Qt::WA_TranslucentBackground), true); + QCOMPARE(qDeclarativeViews.first()->testAttribute(Qt::WA_X11DoNotAcceptFocus), true); + QCOMPARE(qDeclarativeViews.first()->testAttribute(Qt::WA_X11NetWmWindowTypeNotification), true); + QCOMPARE(qDeclarativeViews.first()->windowTitle(), QString("Notification")); + QCOMPARE(qDeclarativeViews.first()->resizeMode(), QDeclarativeView::SizeRootObjectToView); + QCOMPARE(qDeclarativeViews.first()->viewport()->autoFillBackground(), false); + QCOMPARE(qDeclarativeViews.first()->rootContext()->contextProperty("initialSize").toSize(), QApplication::desktop()->screenGeometry(qDeclarativeViews.first()).size()); + QCOMPARE(qDeclarativeViews.first()->rootContext()->contextProperty("notificationPreviewPresenter"), QVariant::fromValue(static_cast<QObject *>(&presenter))); + + // Check that the window was shown + QCOMPARE(qWidgetVisible[static_cast<QWidget *>(qDeclarativeViews.first())], true); + + // Check that the expected notification is signaled onwards + QCOMPARE(spy.count(), 1); + QCOMPARE(presenter.notification(), notification); +} + +void Ut_NotificationPreviewPresenter::testAddNotificationWhenWindowAlreadyOpen() +{ + NotificationPreviewPresenter presenter; + QSignalSpy spy(&presenter, SIGNAL(notificationChanged())); + + // Create a notification: this will create a window + createNotification(1); + presenter.updateNotification(1); + + // Reset stubs to see what happens next + qDeclarativeViews.clear(); + + // Create another notification + Notification *notification = createNotification(2); + presenter.updateNotification(2); + + // The second notification should not be signaled onwards yet since the first one is being presented + QCOMPARE(spy.count(), 1); + + // Show the next notification + presenter.showNextNotification(); + + // Check that the window was not unnecessarily created again + QCOMPARE(qDeclarativeViews.isEmpty(), true); + + // Check that the expected notification is signaled onwards + QCOMPARE(spy.count(), 2); + QCOMPARE(presenter.notification(), notification); +} + +void Ut_NotificationPreviewPresenter::testUpdateNotification() +{ + NotificationPreviewPresenter presenter; + + // Create two notifications + createNotification(1); + createNotification(2); + presenter.updateNotification(1); + presenter.updateNotification(2); + + // Update both notifications + QSignalSpy spy(&presenter, SIGNAL(notificationChanged())); + presenter.updateNotification(1); + presenter.updateNotification(2); + + // Check that no signals were sent + QCOMPARE(spy.count(), 0); +} + +void Ut_NotificationPreviewPresenter::testRemoveNotification() +{ + NotificationPreviewPresenter presenter; + QSignalSpy spy(&presenter, SIGNAL(notificationChanged())); + + // Create two notifications + createNotification(1); + createNotification(2); + presenter.updateNotification(1); + presenter.updateNotification(2); + + // Remove the first one + presenter.removeNotification(1); + + // Check that an empty notification is signaled onwards + QCOMPARE(spy.count(), 2); + QCOMPARE(presenter.notification(), (Notification *)0); + + // Show and remove the second one + presenter.showNextNotification(); + presenter.removeNotification(2); + + // Check that an empty notification is signaled onwards + QCOMPARE(spy.count(), 4); + QCOMPARE(presenter.notification(), (Notification *)0); + + // Check that the window is not yet hidden + QCOMPARE(qWidgetVisible[static_cast<QWidget *>(qDeclarativeViews.first())], true); + + // Check that the window is hidden when it's time to show the next notification (which doesn't exist) + presenter.showNextNotification(); + QCOMPARE(qWidgetVisible[static_cast<QWidget *>(qDeclarativeViews.first())], false); +} + +void Ut_NotificationPreviewPresenter::testWindowMasking_data() +{ + QTest::addColumn<int>("x1"); + QTest::addColumn<int>("y1"); + QTest::addColumn<int>("x2"); + QTest::addColumn<int>("y2"); + QTest::addColumn<int>("x"); + QTest::addColumn<int>("y"); + QTest::addColumn<int>("width"); + QTest::addColumn<int>("height"); + QTest::newRow("x1 < x2, y1 < y2") << 10 << 10 << 50 << 50 << 10 << 10 << 40 << 40; + QTest::newRow("x1 >= x2, y1 < y2") << 50 << 10 << 10 << 50 << 10 << 10 << 40 << 40; + QTest::newRow("x1 < x2, y1 >= y2") << 10 << 50 << 50 << 10 << 10 << 10 << 40 << 40; + QTest::newRow("x1 >= x2, y1 >= y2") << 50 << 50 << 10 << 10 << 10 << 10 << 40 << 40; +} + +void Ut_NotificationPreviewPresenter::testWindowMasking() +{ + QFETCH(int, x1); + QFETCH(int, y1); + QFETCH(int, x2); + QFETCH(int, y2); + QFETCH(int, x); + QFETCH(int, y); + QFETCH(int, width); + QFETCH(int, height); + NotificationPreviewPresenter presenter; + + // Check that the window is created when a notification is added + createNotification(1); + presenter.updateNotification(1); + presenter.setNotificationPreviewRect(x1, y1, x2, y2); + + QRect rect(x, y, width, height); + QCOMPARE(xFixesCreateRegionRectangles.isEmpty(), false); + QCOMPARE(xFixesCreateRegionRectangles.last().x, (short)rect.x()); + QCOMPARE(xFixesCreateRegionRectangles.last().y, (short)rect.y()); + QCOMPARE(xFixesCreateRegionRectangles.last().width, (unsigned short)rect.width()); + QCOMPARE(xFixesCreateRegionRectangles.last().height, (unsigned short)rect.height()); + QCOMPARE(xFixesSetWindowShapeRegionWindow.isEmpty(), false); + QCOMPARE(xFixesSetWindowShapeRegionWindow.last(), qDeclarativeViews.first()->winId()); + QCOMPARE(xFixesSetWindowShapeRegionShapeKind.last(), ShapeInput); + QCOMPARE(xFixesSetWindowShapeRegionXOff.last(), 0); + QCOMPARE(xFixesSetWindowShapeRegionYOff.last(), 0); + QCOMPARE(xFixesSetWindowShapeRegionRegion.last(), (XserverRegion)1); + QCOMPARE(xFixesDestroyRegionRegion.isEmpty(), false); + QCOMPARE(xFixesDestroyRegionRegion.last(), (XserverRegion)1); + QCOMPARE(xSyncCalled, true); +} + +void Ut_NotificationPreviewPresenter::testNotificationNotShownIfNoSummaryOrBody_data() +{ + QTest::addColumn<QString>("previewSummary"); + QTest::addColumn<QString>("previewBody"); + QTest::addColumn<int>("signalCount"); + QTest::addColumn<bool>("windowVisible"); + QTest::newRow("No summary, no body") << "" << "" << 0 << false; + QTest::newRow("Summary, no body") << "summary" << "" << 0 << false; + QTest::newRow("No summary, body") << "" << "body" << 0 << false; + QTest::newRow("Summary, body") << "summary" << "body" << 1 << true; +} + +void Ut_NotificationPreviewPresenter::testNotificationNotShownIfNoSummaryOrBody() +{ + QFETCH(QString, previewSummary); + QFETCH(QString, previewBody); + QFETCH(int, signalCount); + QFETCH(bool, windowVisible); + + NotificationPreviewPresenter presenter; + QSignalSpy spy(&presenter, SIGNAL(notificationChanged())); + + // Create notification + Notification *notification = new Notification; + QVariantHash hints; + hints.insert(NotificationManager::HINT_PREVIEW_SUMMARY, previewSummary); + hints.insert(NotificationManager::HINT_PREVIEW_BODY, previewBody); + notification->setHints(hints); + notificationManagerNotification.insert(1, notification); + presenter.updateNotification(1); + + // Check whether the expected notification is signaled onwards + QCOMPARE(spy.count(), signalCount); + + // Check whether the window was shown + QCOMPARE(qWidgetVisible[static_cast<QWidget *>(qDeclarativeViews.first())], windowVisible); +} + +void Ut_NotificationPreviewPresenter::testUpdateNotificationRemovesNotificationIfNoSummaryOrBody() +{ + NotificationPreviewPresenter presenter; + + // Create a notification + Notification *notification = createNotification(1); + presenter.updateNotification(1); + + // Update the notification to have no summary or body + QSignalSpy spy(&presenter, SIGNAL(notificationChanged())); + notification->setHints(QVariantHash()); + presenter.updateNotification(1); + + // Check that an empty notification is signaled onwards + QCOMPARE(spy.count(), 1); + QCOMPARE(presenter.notification(), (Notification *)0); +} + +QTEST_MAIN(Ut_NotificationPreviewPresenter) --- tests/ut_notificationpreviewpresenter/ut_notificationpreviewpresenter.h +++ tests/ut_notificationpreviewpresenter/ut_notificationpreviewpresenter.h @@ -0,0 +1,40 @@ +/*************************************************************************** +** +** Copyright (C) 2012 Jolla Ltd. +** Contact: Robin Burchell <[email protected]> +** +** This file is part of lipstick. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef UT_NOTIFICATIONPREVIEWPRESENTER_H +#define UT_NOTIFICATIONPREVIEWPRESENTER_H + +#include <QObject> + +class Ut_NotificationPreviewPresenter : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanup(); + void testSignalConnections(); + void testAddNotificationWhenWindowNotOpen(); + void testAddNotificationWhenWindowAlreadyOpen(); + void testUpdateNotification(); + void testRemoveNotification(); + void testWindowMasking_data(); + void testWindowMasking(); + void testNotificationNotShownIfNoSummaryOrBody_data(); + void testNotificationNotShownIfNoSummaryOrBody(); + void testUpdateNotificationRemovesNotificationIfNoSummaryOrBody(); +}; + +#endif --- tests/ut_notificationpreviewpresenter/ut_notificationpreviewpresenter.pro +++ tests/ut_notificationpreviewpresenter/ut_notificationpreviewpresenter.pro @@ -0,0 +1,17 @@ +include(../common.pri) +TARGET = ut_notificationpreviewpresenter +INCLUDEPATH += $$SRCDIR $$NOTIFICATIONSRCDIR +QT += declarative dbus + +# unit test and unit +SOURCES += \ + ut_notificationpreviewpresenter.cpp \ + $$NOTIFICATIONSRCDIR/notificationpreviewpresenter.cpp \ + $$NOTIFICATIONSRCDIR/notification.cpp + +# unit test and unit +HEADERS += \ + ut_notificationpreviewpresenter.h \ + $$NOTIFICATIONSRCDIR/notificationpreviewpresenter.h \ + $$NOTIFICATIONSRCDIR/notificationmanager.h \ + $$NOTIFICATIONSRCDIR/notification.h --- tools/notificationtool/.gitignore +++ tools/notificationtool/.gitignore @@ -1,2 +0,0 @@ -notificationmanagerproxy.* -notificationtool ++++++ lipstick.yaml --- lipstick.yaml +++ lipstick.yaml @@ -1,6 +1,6 @@ Name: lipstick Summary: QML toolkit for homescreen creation -Version: 0.4.4 +Version: 0.4.5 Release: 1 Group: System/Libraries License: LGPLv2.1 @@ -17,6 +17,8 @@ - mlite >= 0.0.6 - xcomposite - xdamage + - xfixes + - xext Files: - "%{_libdir}/liblipstick.so.*" - "%{_libdir}/qt4/imports/org/nemomobile/lipstick/liblipstickplugin.so"
