Merge lp:~unity-team/unity-notifications/extended-snap-decisions into lp:unity-notifications

Proposed by Michael Zanetti
Status: Work in progress
Proposed branch: lp:~unity-team/unity-notifications/extended-snap-decisions
Merge into: lp:unity-notifications
Diff against target: 1420 lines (+952/-20)
23 files modified
CMakeLists.txt (+5/-1)
cmake/FindGIO.cmake (+71/-0)
com.canonical.snapdecisions.feedback.xml (+9/-0)
create-feedback-dbus-interface-sources.sh (+7/-0)
examples/export-model.py (+91/-0)
examples/render-model.qml (+137/-0)
examples/sd-example-incoming-call.py (+4/-3)
examples/test-system-dialog-hint.py (+60/-0)
include/Feedback.h (+24/-0)
include/FeedbackInterface.h (+56/-0)
include/FeedbackInterfaceAdaptor.h (+51/-0)
include/Notification.h (+12/-2)
include/NotificationModel.h (+6/-3)
include/NotificationServer.h (+17/-1)
include/notify-backend.h.in (+9/-1)
src/CMakeLists.txt (+10/-0)
src/Feedback.cpp (+32/-0)
src/FeedbackInterface.cpp (+26/-0)
src/FeedbackInterfaceAdaptor.cpp (+43/-0)
src/Notification.cpp (+32/-0)
src/NotificationClient.cpp (+1/-1)
src/NotificationModel.cpp (+54/-0)
src/NotificationServer.cpp (+195/-8)
To merge this branch: bzr merge lp:~unity-team/unity-notifications/extended-snap-decisions
Reviewer Review Type Date Requested Status
Unity API Team Pending
Review via email: mp+183921@code.launchpad.net
To post a comment you must log in.

Unmerged revisions

185. By Michael Zanetti

merge trunk

184. By Mirco Müller

Add some helping debug-printf()s, make menu-model teardown more robust, change system-dialog-hint example to use a timeout for demo-purposes

183. By Mirco Müller

Improved the tear-down of menu-models used by extended snap-decisions.

182. By Mirco Müller

Make DBus-method collect() more robust

181. By Mirco Müller

Trying to get passing data from frontend to backend working.

180. By Mirco Müller

Made creation and teardown of menu-model better... act on-demand.

179. By Mirco Müller

Stripped old code from system-dialog example.

178. By Mirco Müller

Got linking to gio working... system-dialog hint now exports menu-model via DBus

177. By Mirco Müller

Make compiling and linking against gio work

176. By Mirco Müller

Added stand-alone example pulling/rendering menu-model

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-07-02 16:18:31 +0000
3+++ CMakeLists.txt 2013-09-04 16:15:41 +0000
4@@ -9,13 +9,15 @@
5 message(FATAL_ERROR "In-tree build attempt detected, aborting. Set your build dir outside your source dir, delete CMakeCache.txt from source root and try again.")
6 endif()
7
8+
9 option(basic_warnings "Basic compiler warnings." ON)
10 option(build_tools "Build developer tools." OFF)
11 option(private_dbus "Use private dbus namespace to prevent clashes during development." OFF)
12
13 include(cmake/coverage.cmake)
14+include(cmake/FindGIO.cmake)
15 include(FindPkgConfig)
16-include (GNUInstallDirs)
17+include(GNUInstallDirs)
18
19 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++0x")
20 add_definitions(-DQT_NO_KEYWORDS)
21@@ -32,6 +34,8 @@
22 # Workaround for https://bugreports.qt-project.org/browse/QTBUG-29987
23 set(QT_IMPORTS_DIR "${CMAKE_INSTALL_LIBDIR}/qt5/qml")
24
25+include_directories(${GIO_INCLUDE_DIR})
26+
27 include_directories(include)
28 include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
29 add_subdirectory(include)
30
31=== added file 'cmake/FindGIO.cmake'
32--- cmake/FindGIO.cmake 1970-01-01 00:00:00 +0000
33+++ cmake/FindGIO.cmake 2013-09-04 16:15:41 +0000
34@@ -0,0 +1,71 @@
35+# - Try to find the GIO libraries
36+# Once done this will define
37+#
38+# GIO_FOUND - system has GIO
39+# GIO_INCLUDE_DIR - the GIO include directory
40+# GIO_LIBRARIES - GIO library
41+#
42+# Copyright (c) 2010 Dario Freddi <drf@kde.org>
43+#
44+# Redistribution and use is allowed according to the terms of the BSD license.
45+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
46+
47+if(GIO_INCLUDE_DIR AND GIO_LIBRARIES)
48+ # Already in cache, be silent
49+ set(GIO_FIND_QUIETLY TRUE)
50+endif(GIO_INCLUDE_DIR AND GIO_LIBRARIES)
51+
52+if (NOT WIN32)
53+ include(UsePkgConfig)
54+ pkgconfig(gio-2.0 _LibGIOIncDir _LibGIOLinkDir _LibGIOLinkFlags _LibGIOCflags)
55+endif(NOT WIN32)
56+
57+MESSAGE(STATUS "gio include dir: ${_LibGIOIncDir}")
58+
59+# first try without default paths to respect PKG_CONFIG_PATH
60+
61+find_path(GIO_MAIN_INCLUDE_DIR glib.h
62+ PATH_SUFFIXES glib-2.0
63+ PATHS ${_LibGIOIncDir}
64+ NO_DEFAULT_PATH)
65+
66+find_path(GIO_MAIN_INCLUDE_DIR glib.h
67+ PATH_SUFFIXES glib-2.0
68+ PATHS ${_LibGIOIncDir} )
69+
70+MESSAGE(STATUS "found gio main include dir: ${GIO_MAIN_INCLUDE_DIR}")
71+
72+# search the glibconfig.h include dir under the same root where the library is found
73+find_library(GIO_LIBRARIES
74+ NAMES gio-2.0
75+ PATHS ${_LibGIOLinkDir}
76+ NO_DEFAULT_PATH)
77+
78+find_library(GIO_LIBRARIES
79+ NAMES gio-2.0
80+ PATHS ${_LibGIOLinkDir})
81+
82+
83+get_filename_component(GIOLibDir "${GIO_LIBRARIES}" PATH)
84+
85+find_path(GIO_INTERNAL_INCLUDE_DIR glibconfig.h
86+ PATH_SUFFIXES glib-2.0/include
87+ PATHS ${_LibGIOIncDir} "${GIOLibDir}" ${CMAKE_SYSTEM_LIBRARY_PATH}
88+ NO_DEFAULT_PATH)
89+
90+find_path(GIO_INTERNAL_INCLUDE_DIR glibconfig.h
91+ PATH_SUFFIXES glib-2.0/include
92+ PATHS ${_LibGIOIncDir} "${GIOLibDir}" ${CMAKE_SYSTEM_LIBRARY_PATH})
93+
94+set(GIO_INCLUDE_DIR "${GIO_MAIN_INCLUDE_DIR}")
95+
96+# not sure if this include dir is optional or required
97+# for now it is optional
98+if(GIO_INTERNAL_INCLUDE_DIR)
99+ set(GIO_INCLUDE_DIR ${GIO_INCLUDE_DIR} "${GIO_INTERNAL_INCLUDE_DIR}")
100+endif(GIO_INTERNAL_INCLUDE_DIR)
101+
102+include(FindPackageHandleStandardArgs)
103+find_package_handle_standard_args(GIO DEFAULT_MSG GIO_LIBRARIES GIO_MAIN_INCLUDE_DIR)
104+
105+mark_as_advanced(GIO_INCLUDE_DIR GIO_LIBRARIES)
106
107=== added file 'com.canonical.snapdecisions.feedback.xml'
108--- com.canonical.snapdecisions.feedback.xml 1970-01-01 00:00:00 +0000
109+++ com.canonical.snapdecisions.feedback.xml 2013-09-04 16:15:41 +0000
110@@ -0,0 +1,9 @@
111+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
112+<node>
113+ <interface name="com.canonical.snapdecisions.feedback">
114+ <method name="collect">
115+ <arg type="as" direction="out"/>
116+ <arg name="id" type="u" direction="in"/>
117+ </method>
118+ </interface>
119+</node>
120
121=== added file 'create-feedback-dbus-interface-sources.sh'
122--- create-feedback-dbus-interface-sources.sh 1970-01-01 00:00:00 +0000
123+++ create-feedback-dbus-interface-sources.sh 2013-09-04 16:15:41 +0000
124@@ -0,0 +1,7 @@
125+#!/bin/sh
126+
127+XML_FILE=com.canonical.snapdecisions.feedback.xml
128+
129+qdbuscpp2xml -M -s include/Feedback.h -o $XML_FILE
130+qdbusxml2cpp -v -c FeedbackInterface -p include/FeedbackInterface.h:src/FeedbackInterface.cpp $XML_FILE
131+qdbusxml2cpp -c FeedbackInterfaceAdaptor -a include/FeedbackInterfaceAdaptor.h:src/FeedbackInterfaceAdaptor.cpp $XML_FILE
132
133=== added file 'examples/export-model.py'
134--- examples/export-model.py 1970-01-01 00:00:00 +0000
135+++ examples/export-model.py 2013-09-04 16:15:41 +0000
136@@ -0,0 +1,91 @@
137+#!/usr/bin/env python3
138+
139+import sys
140+
141+from gi.repository import Gio, GLib, Notify
142+
143+BUS_NAME = 'com.canonical.snapdecisions.systemdialog'
144+BUS_OBJECT_PATH = '/com/canonical/snapdecisions/systemdialog'
145+
146+def activate_cancel(action, data):
147+ print('Called cancel (%s)' % action.get_name())
148+
149+def activate_connect(action, data):
150+ print('Called connect (%s)' % action.get_name())
151+ print('passed: %s' % data)
152+
153+def bus_acquired(bus, name):
154+ menu = Gio.Menu()
155+
156+ item = Gio.MenuItem.new('Connect to \"Calamari\"', None)
157+ item.set_attribute_value('x-canonical-type', GLib.Variant.new_string('com.canonical.snapdecision.title'))
158+ menu.append_item(item)
159+
160+ item2 = Gio.MenuItem.new('Login name:', None)
161+ item2.set_attribute_value('x-canonical-type', GLib.Variant.new_string('com.canonical.snapdecision.textfield'))
162+ item2.set_attribute_value('x-echo-mode-password', GLib.Variant.new_boolean(False))
163+ menu.append_item(item2)
164+
165+ item3 = Gio.MenuItem.new('Password:', None)
166+ item3.set_attribute_value('x-canonical-type', GLib.Variant.new_string('com.canonical.snapdecision.textfield'))
167+ item3.set_attribute_value('x-echo-mode-password', GLib.Variant.new_boolean(True))
168+ menu.append_item(item3)
169+
170+ item4 = Gio.MenuItem.new('Cancel', None)
171+ item4.set_attribute_value('x-canonical-type', GLib.Variant.new_string('com.canonical.snapdecision.button'))
172+ item4.set_attribute_value('x-tint-button', GLib.Variant.new_boolean(False))
173+ menu.append_item(item4)
174+
175+ item5 = Gio.MenuItem.new('Connect', None)
176+ item5.set_attribute_value('x-canonical-type', GLib.Variant.new_string('com.canonical.snapdecision.button'))
177+ item5.set_attribute_value('x-tint-button', GLib.Variant.new_boolean(True))
178+ menu.append_item(item5)
179+
180+ actions = Gio.SimpleActionGroup.new()
181+ cancel = Gio.SimpleAction.new("cancel", None)
182+ actions.insert(cancel)
183+ cancel.connect('activate', activate_cancel)
184+ connect = Gio.SimpleAction.new("connect", None) #GLib.VariantType.new("ss"))
185+ actions.insert(connect)
186+ connect.connect('activate', activate_connect)
187+ bus.export_action_group(BUS_OBJECT_PATH, actions)
188+
189+ bus.export_menu_model(BUS_OBJECT_PATH, menu)
190+
191+def quit_callback(notification):
192+ GLib.MainLoop().quit()
193+
194+def connect_callback(notification, action, data):
195+ if action == "connect_id":
196+ print("Triggering Connect")
197+ else:
198+ print("That should not have happened (connect_id)!")
199+
200+def cancel_callback(notification, action, data):
201+ if action == "cancel_id":
202+ print("Triggering Cancel")
203+ else:
204+ print("That should not have happened (cancel_id)!")
205+
206+def pushNotification ():
207+ n = Notify.Notification.new("Connect to \"Calamari\"", "dummy", "totem");
208+ n.add_action ("connect_id", "Connect", connect_callback, None, None)
209+ n.add_action ("cancel_id", "Cancel", cancel_callback, None, None)
210+ n.set_hint_string ("x-canonical-snap-decisions", "true")
211+ n.set_hint_string ("x-canonical-private-button-tint", "true")
212+ variant_password = GLib.Variant('as', ["Login name:", "Password:"])
213+ variant_listview = GLib.Variant('as', ["wifi-medium", "BTOpenZone", "sec-wep", "wifi-low", "Calamari", "sec-wpa"])
214+ #variant_feedback = GLib.Variant('as', [DBUS_NAME, DBUS_PATH, DBUS_METHOD])
215+ #n.set_hint ("x-canonical-private-system-dialog-password", variant_password)
216+ #n.set_hint ("x-canonical-private-system-dialog-listview", variant_listview)
217+ #n.set_hint ("x-canonical-private-system-dialog-feedback", variant_feedback)
218+ n.set_hint_string ("x-canonical-private-system-dialog", "user-auth")
219+ return n
220+
221+if __name__ == '__main__':
222+ Gio.bus_own_name(Gio.BusType.SESSION, BUS_NAME, 0, bus_acquired, None, None)
223+ #Notify.init("password-dialog-test")
224+ #n = pushNotification()
225+ #n.connect('closed', quit_callback)
226+ #n.show ()
227+ GLib.MainLoop().run()
228
229=== added file 'examples/render-model.qml'
230--- examples/render-model.qml 1970-01-01 00:00:00 +0000
231+++ examples/render-model.qml 2013-09-04 16:15:41 +0000
232@@ -0,0 +1,137 @@
233+import QtQuick 2.0
234+import QMenuModel 0.1
235+import Ubuntu.Components 0.1
236+
237+Rectangle {
238+ id: root
239+
240+ width: units.gu(40)
241+ height: units.gu(71)
242+
243+ Image {
244+ id: background
245+
246+ source: "/home/mirco/Desktop/Bilder/Fotos/wheelie-kurve.jpg"
247+ fillMode: Image.PreserveAspectCrop
248+ }
249+
250+ UnityMenuModel {
251+ id: menu
252+
253+ busName: "com.canonical.snapdecisions.systemdialog"
254+ actions: { "connect": "/com/canonical/snapdecision/systemdialog" }
255+ menuObjectPath: "/com/canonical/snapdecisions/systemdialog"
256+ }
257+
258+ UbuntuShape {
259+ color: Qt.rgba(0, 0, 0, 0.85)
260+
261+ anchors {
262+ left: parent.left
263+ right: parent.right
264+ top: parent.top
265+ bottom: parent.bottom
266+ margins: units.gu(2)
267+ }
268+
269+ ListView {
270+ id: listview
271+
272+ spacing: units.gu(2)
273+
274+ property string login
275+ property string passwd
276+
277+ anchors {
278+ fill: parent
279+ margins: units.gu(2)
280+ }
281+
282+ model: menu
283+
284+ delegate: Loader {
285+ sourceComponent: {
286+ if (type == "com.canonical.snapdecision.title") {
287+ return title
288+ }
289+ else if (type == "com.canonical.snapdecision.textfield") {
290+ listview.model.loadExtendedAttributes(index, {'x-echo-mode-password': 'bool'});
291+ return textfield
292+ }
293+ else if (type == "com.canonical.snapdecision.button") {
294+ listview.model.loadExtendedAttributes(index, {'x-tint-button': 'bool'});
295+ return button
296+ }
297+ }
298+
299+ Component {
300+ id: title
301+
302+ Label {
303+ id: titleLabel
304+
305+ anchors.horizontalCenter: parent.horizontalCenter
306+ fontSize: "medium"
307+ font.bold: true
308+ color: "white"
309+ text: label
310+ }
311+ }
312+
313+ Component {
314+ id: textfield
315+
316+ Column {
317+ spacing: units.gu(.5)
318+ anchors {
319+ left: parent.left
320+ right: parent.right
321+ }
322+
323+ Label {
324+ anchors.left: parent.left
325+
326+ fontSize: "medium"
327+ color: "white"
328+ text: label
329+ }
330+
331+ TextField {
332+ echoMode: ext.xEchoModePassword ? TextInput.Password : TextInput.Normal
333+ onAccepted: {
334+ if(echoMode == TextInput.Password) {
335+ listview.passwd = text
336+ } else {
337+ listview.login = text
338+ }
339+ }
340+ }
341+ }
342+ }
343+
344+ Component {
345+ id: button
346+
347+ Button {
348+ text: label
349+ gradient: ext.xTintButton ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient
350+ onClicked: {
351+ print("Clicked on \"",label,"\"")
352+ print("Login:", listview.login)
353+ print("Password:", listview.passwd)
354+ print("")
355+ model.action.activate()
356+ //if(model.action.name == "button.cancel") {
357+ // model.action.activate(index)
358+ //}
359+ //if(model.action.name == "button.connect") {
360+ // model.target = listview.login
361+ // model.action.activate()
362+ //}
363+ }
364+ }
365+ }
366+ }
367+ }
368+ }
369+}
370
371=== modified file 'examples/sd-example-incoming-call.py'
372--- examples/sd-example-incoming-call.py 2013-05-17 14:57:48 +0000
373+++ examples/sd-example-incoming-call.py 2013-09-04 16:15:41 +0000
374@@ -74,12 +74,13 @@
375 # always comes first!
376 n.add_action ("action_accept", "Accept", action_accept);
377 n.add_action ("action_decline_1", "Decline", action_decline_1);
378- #n.add_action ("action_decline_2", "\"Can't talk now, what's up?\"", action_decline_2);
379- #n.add_action ("action_decline_3", "\"I call you back.\"", action_decline_3);
380- #n.add_action ("action_decline_4", "Send custom message...", action_decline_4);
381+ n.add_action ("action_decline_2", "\"Can't talk now, what's up?\"", action_decline_2);
382+ n.add_action ("action_decline_3", "\"I call you back.\"", action_decline_3);
383+ n.add_action ("action_decline_4", "Send custom message...", action_decline_4);
384
385 # indicate to the notification-daemon, that we want to use snap-decisions
386 n.set_hint_string ("x-canonical-snap-decisions", "true");
387+ n.set_hint_string ("x-canonical-private-button-tint", "true");
388 n.set_hint_string ("x-canonical-secondary-icon", os.getcwd() + "/assets/icon_phone.png");
389
390 n.show ()
391
392=== added file 'examples/test-system-dialog-hint.py'
393--- examples/test-system-dialog-hint.py 1970-01-01 00:00:00 +0000
394+++ examples/test-system-dialog-hint.py 2013-09-04 16:15:41 +0000
395@@ -0,0 +1,60 @@
396+#!/usr/bin/python
397+
398+import os
399+import sys
400+from gi.repository import Gio, GLib, Notify
401+import dbus
402+import dbus.service
403+
404+DBUS_NAME="com.canonical.snapdecisions.feedback"
405+DBUS_PATH="/com/canonical/snapdecisions/feedback"
406+DBUS_METHOD="collect"
407+
408+def collect_feedback(id):
409+ print "collect_feedback() called"
410+ interface = dbus.Interface(dbus.SessionBus().get_object(DBUS_NAME, DBUS_PATH), DBUS_NAME)
411+ result = interface.collect(id)
412+ if len(result) != 0:
413+ print "Got reply: "
414+ for index in range(len(result)):
415+ print "\t%s" % result[index]
416+ #return False
417+ else:
418+ print "result was empty"
419+ return True
420+
421+def quit_callback(notification):
422+ print "quit_callback() called"
423+ loop.quit()
424+
425+def connect_callback(notification, action, data):
426+ print "connect_callback() called"
427+ if action == "connect_id":
428+ print "Triggering Connect"
429+ #collect_feedback(notification.get_property("id"))
430+ else:
431+ print "That should not have happened (connect_id)!"
432+
433+def cancel_callback(notification, action, data):
434+ if action == "cancel_id":
435+ print "Triggering Cancel"
436+ else:
437+ print "That should not have happened (cancel_id)!"
438+
439+def pushNotification ():
440+ n = Notify.Notification.new("Connect to \"Calamari\"", "dummy", "totem");
441+ n.add_action ("connect_id", "Connect", connect_callback, None, None)
442+ n.add_action ("cancel_id", "Cancel", cancel_callback, None, None)
443+ n.set_hint_string ("x-canonical-snap-decisions", "true")
444+ n.set_hint_string ("x-canonical-private-button-tint", "true")
445+ #n.set_hint_string ("x-canonical-private-system-dialog", "user-auth")
446+ n.set_hint_string ("x-canonical-private-system-dialog", "wifi-auth")
447+ return n
448+
449+loop = GLib.MainLoop.new(None, False)
450+Notify.init("password-dialog-test")
451+n = pushNotification()
452+n.connect('closed', quit_callback)
453+n.show ()
454+GLib.timeout_add(1000, collect_feedback, n.get_property("id"))
455+loop.run()
456
457=== added file 'include/Feedback.h'
458--- include/Feedback.h 1970-01-01 00:00:00 +0000
459+++ include/Feedback.h 2013-09-04 16:15:41 +0000
460@@ -0,0 +1,24 @@
461+#include <QString>
462+#include <QObject>
463+#include <QtDBus>
464+
465+#define FEEDBACK_DBUS_NAME "com.canonical.snapdecisions.feedback"
466+#define FEEDBACK_DBUS_PATH "/com/canonical/snapdecisions/feedback"
467+#define FEEDBACK_DBUS_METHOD "collect"
468+
469+class NotificationModel;
470+
471+class Feedback : public QObject
472+{
473+ Q_OBJECT
474+ Q_CLASSINFO("D-Bus Interface", FEEDBACK_DBUS_NAME)
475+
476+ public:
477+ Feedback(NotificationModel& m, QObject* parent = 0);
478+
479+ public Q_SLOTS:
480+ QStringList collect(const unsigned int id);
481+
482+ private:
483+ NotificationModel& model;
484+};
485
486=== added file 'include/FeedbackInterface.h'
487--- include/FeedbackInterface.h 1970-01-01 00:00:00 +0000
488+++ include/FeedbackInterface.h 2013-09-04 16:15:41 +0000
489@@ -0,0 +1,56 @@
490+/*
491+ * This file was generated by qdbusxml2cpp version 0.8
492+ * Command line was: qdbusxml2cpp -v -c FeedbackInterface -p include/FeedbackInterface.h:src/FeedbackInterface.cpp com.canonical.snapdecisions.feedback.xml
493+ *
494+ * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
495+ *
496+ * This is an auto-generated file.
497+ * Do not edit! All changes made to it will be lost.
498+ */
499+
500+#ifndef FEEDBACKINTERFACE_H_1376659323
501+#define FEEDBACKINTERFACE_H_1376659323
502+
503+#include <QtCore/QObject>
504+#include <QtCore/QByteArray>
505+#include <QtCore/QList>
506+#include <QtCore/QMap>
507+#include <QtCore/QString>
508+#include <QtCore/QStringList>
509+#include <QtCore/QVariant>
510+#include <QtDBus/QtDBus>
511+
512+/*
513+ * Proxy class for interface com.canonical.snapdecisions.feedback
514+ */
515+class FeedbackInterface: public QDBusAbstractInterface
516+{
517+ Q_OBJECT
518+public:
519+ static inline const char *staticInterfaceName()
520+ { return "com.canonical.snapdecisions.feedback"; }
521+
522+public:
523+ FeedbackInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
524+
525+ ~FeedbackInterface();
526+
527+public Q_SLOTS: // METHODS
528+ inline QDBusPendingReply<QStringList> collect(uint id)
529+ {
530+ QList<QVariant> argumentList;
531+ argumentList << QVariant::fromValue(id);
532+ return asyncCallWithArgumentList(QLatin1String("collect"), argumentList);
533+ }
534+
535+Q_SIGNALS: // SIGNALS
536+};
537+
538+namespace com {
539+ namespace canonical {
540+ namespace snapdecisions {
541+ typedef ::FeedbackInterface feedback;
542+ }
543+ }
544+}
545+#endif
546
547=== added file 'include/FeedbackInterfaceAdaptor.h'
548--- include/FeedbackInterfaceAdaptor.h 1970-01-01 00:00:00 +0000
549+++ include/FeedbackInterfaceAdaptor.h 2013-09-04 16:15:41 +0000
550@@ -0,0 +1,51 @@
551+/*
552+ * This file was generated by qdbusxml2cpp version 0.8
553+ * Command line was: qdbusxml2cpp -c FeedbackInterfaceAdaptor -a include/FeedbackInterfaceAdaptor.h:src/FeedbackInterfaceAdaptor.cpp com.canonical.snapdecisions.feedback.xml
554+ *
555+ * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
556+ *
557+ * This is an auto-generated file.
558+ * This file may have been hand-edited. Look for HAND-EDIT comments
559+ * before re-generating it.
560+ */
561+
562+#ifndef FEEDBACKINTERFACEADAPTOR_H_1376659323
563+#define FEEDBACKINTERFACEADAPTOR_H_1376659323
564+
565+#include <QtCore/QObject>
566+#include <QtDBus/QtDBus>
567+QT_BEGIN_NAMESPACE
568+class QByteArray;
569+template<class T> class QList;
570+template<class Key, class Value> class QMap;
571+class QString;
572+class QStringList;
573+class QVariant;
574+QT_END_NAMESPACE
575+
576+/*
577+ * Adaptor class for interface com.canonical.snapdecisions.feedback
578+ */
579+class FeedbackInterfaceAdaptor: public QDBusAbstractAdaptor
580+{
581+ Q_OBJECT
582+ Q_CLASSINFO("D-Bus Interface", "com.canonical.snapdecisions.feedback")
583+ Q_CLASSINFO("D-Bus Introspection", ""
584+" <interface name=\"com.canonical.snapdecisions.feedback\">\n"
585+" <method name=\"collect\">\n"
586+" <arg direction=\"out\" type=\"as\"/>\n"
587+" <arg direction=\"in\" type=\"u\" name=\"id\"/>\n"
588+" </method>\n"
589+" </interface>\n"
590+ "")
591+public:
592+ FeedbackInterfaceAdaptor(QObject *parent);
593+ virtual ~FeedbackInterfaceAdaptor();
594+
595+public: // PROPERTIES
596+public Q_SLOTS: // METHODS
597+ QStringList collect(uint id);
598+Q_SIGNALS: // SIGNALS
599+};
600+
601+#endif
602
603=== modified file 'include/Notification.h'
604--- include/Notification.h 2013-09-03 12:41:34 +0000
605+++ include/Notification.h 2013-09-04 16:15:41 +0000
606@@ -37,6 +37,7 @@
607 Q_ENUMS(Urgency)
608 Q_ENUMS(Type)
609 Q_ENUMS(Hint)
610+ Q_ENUMS(SystemDialog)
611 Q_PROPERTY(QString summary READ getSummary WRITE setSummary NOTIFY summaryChanged)
612 Q_PROPERTY(QString body READ getBody WRITE setBody NOTIFY bodyChanged)
613 Q_PROPERTY(NotificationID id READ getID)
614@@ -46,6 +47,8 @@
615 Q_PROPERTY(Urgency urgency READ getUrgency WRITE setUrgency NOTIFY urgencyChanged)
616 Q_PROPERTY(Type type READ getType WRITE setType NOTIFY typeChanged)
617 Q_PROPERTY(ActionModel* actions READ getActions NOTIFY actionsChanged)
618+ Q_PROPERTY(QStringList entries READ getEntries WRITE setEntries NOTIFY entriesChanged)
619+ Q_PROPERTY(SystemDialog systemDialog READ getSystemDialog NOTIFY systemDialogChanged)
620 Q_PROPERTY(int hints READ getHints WRITE setHints NOTIFY hintsChanged)
621
622 private:
623@@ -53,8 +56,9 @@
624
625 public:
626 enum Urgency { Low, Normal, Critical };
627- enum Type { Confirmation, Ephemeral, Interactive, SnapDecision, PlaceHolder };
628- enum Hint { None = 0, ButtonTint = 1 << 1, IconOnly = 1 << 2 };
629+ enum Type { Confirmation, Ephemeral, Interactive, SnapDecision, Dialog, PlaceHolder };
630+ enum Hint { None = 0, ButtonTint = 1 << 1, IconOnly = 1 << 2, Truncation = 1 << 3, Sync = 1 << 4 };
631+ enum SystemDialog { WifiSelect, WifiAuth, UserAuth };
632
633 Q_SIGNALS:
634 void bodyChanged(QString text);
635@@ -64,6 +68,8 @@
636 void valueChanged(int value);
637 void urgencyChanged(Urgency urg);
638 void typeChanged(Type type);
639+ void entriesChanged(QStringList entries);
640+ void systemDialogChanged(SystemDialog systemDialog);
641 void actionsChanged(QStringList actions);
642 void hintsChanged(int hints);
643
644@@ -109,8 +115,12 @@
645 void setUrgency(Urgency urg);
646 Type getType() const;
647 void setType(Type type);
648+ QStringList getEntries() const;
649+ void setEntries(QStringList entries);
650 ActionModel* getActions() const;
651 void setActions(QStringList actions);
652+ SystemDialog getSystemDialog() const;
653+ void setSystemDialog(SystemDialog systemDialog);
654
655 int getHints() const;
656 void setHints(int hints);
657
658=== modified file 'include/NotificationModel.h'
659--- include/NotificationModel.h 2013-09-03 12:41:34 +0000
660+++ include/NotificationModel.h 2013-09-04 16:15:41 +0000
661@@ -39,9 +39,11 @@
662 RoleValue = Qt::UserRole + 6,
663 RoleIcon = Qt::UserRole + 7,
664 RoleSecondaryIcon = Qt::UserRole + 8,
665- RoleActions = Qt::UserRole + 9,
666- RoleHints = Qt::UserRole + 10,
667- RoleNotification = Qt::UserRole + 11
668+ RoleEntries = Qt::UserRole + 9,
669+ RoleActions = Qt::UserRole + 10,
670+ RoleHints = Qt::UserRole + 11,
671+ RoleNotification = Qt::UserRole + 12,
672+ RoleSystemDialog = Qt::UserRole + 13
673 };
674
675 class NotificationModel : public QAbstractListModel {
676@@ -96,6 +98,7 @@
677 void insertEphemeral(QSharedPointer<Notification> n);
678 void insertConfirmation(QSharedPointer<Notification> n);
679 void insertInteractive(QSharedPointer<Notification> n);
680+ void insertDialog(QSharedPointer<Notification> n);
681 void insertSnap(QSharedPointer<Notification> n);
682 void insertToVisible(QSharedPointer<Notification> n, int location=-1);
683 void deleteFromVisible(int loc);
684
685=== modified file 'include/NotificationServer.h'
686--- include/NotificationServer.h 2013-09-03 12:41:34 +0000
687+++ include/NotificationServer.h 2013-09-04 16:15:41 +0000
688@@ -20,6 +20,8 @@
689 #ifndef NOTIFICATIONSERVER_H
690 #define NOTIFICATIONSERVER_H
691
692+#include <gio/gio.h>
693+
694 #include "notify-backend.h"
695
696 /* http://www.galago-project.org/specs/notification/0.9/x408.html#commands
697@@ -72,11 +74,25 @@
698 void ActionInvoked(unsigned int id, QString action_key);
699 void dataChanged(unsigned int id);
700
701+public:
702+ GDBusConnection* wifiAuthConnection;
703+ unsigned int wifiAuthBusName;
704+ unsigned int wifiAuthModel;
705+ GDBusConnection* wifiSelectConnection;
706+ unsigned int wifiSelectBusName;
707+ unsigned int wifiSelectModel;
708+ GDBusConnection* userAuthConnection;
709+ unsigned int userAuthBusName;
710+ unsigned int userAuthModel;
711+
712 private:
713+ void exportWifiAuthModel();
714+ void exportWifiSelectModel();
715+ void exportUserAuthModel();
716+ void teardownMenuModels();
717 Notification* buildNotification(NotificationID id, const Hints &hints);
718 NotificationModel &model;
719 unsigned int idCounter;
720-
721 };
722
723 #endif
724
725=== modified file 'include/notify-backend.h.in'
726--- include/notify-backend.h.in 2013-09-03 12:41:34 +0000
727+++ include/notify-backend.h.in 2013-09-04 16:15:41 +0000
728@@ -55,9 +55,17 @@
729 #define DBUS_PATH "/org/freedesktop/Notifications"
730 #endif
731
732+#define SYSTEM_DIALOG_TYPE_WIFI_AUTH "wifi-auth"
733+#define SYSTEM_DIALOG_TYPE_WIFI_SELECT "wifi-select"
734+#define SYSTEM_DIALOG_TYPE_USER_AUTH "user-auth"
735+
736 #define URGENCY_HINT "urgency"
737-#define SYNCH_HINT "x-canonical-private-synchronous"
738+#define SYNC_HINT "x-canonical-private-synchronous"
739 #define SNAP_HINT "x-canonical-snap-decisions"
740+#define DIALOG_HINT "x-canonical-private-system-dialog"
741+#define DIALOG_PASSWORD_HINT "x-canonical-private-system-dialog-password"
742+#define DIALOG_LISTVIEW_HINT "x-canonical-private-system-dialog-listview"
743+#define DIALOG_FEEDBACK_HINT "x-canonical-private-system-dialog-feedback"
744 #define INTERACTIVE_HINT "x-canonical-switch-to-application"
745 #define SECONDARY_ICON_HINT "x-canonical-secondary-icon"
746 #define ICON_ONLY_HINT "x-canonical-private-icon-only"
747
748=== modified file 'src/CMakeLists.txt'
749--- src/CMakeLists.txt 2013-06-18 08:36:08 +0000
750+++ src/CMakeLists.txt 2013-09-04 16:15:41 +0000
751@@ -9,6 +9,12 @@
752 ../include/NotificationServer.h
753 NotificationClient.cpp
754 ../include/NotificationClient.h
755+Feedback.cpp
756+../include/Feedback.h
757+FeedbackInterface.cpp
758+../include/FeedbackInterface.h
759+FeedbackInterfaceAdaptor.cpp
760+../include/FeedbackInterfaceAdaptor.h
761 )
762
763 # Build everything twice. Since we have only a few
764@@ -20,12 +26,16 @@
765 ${CORE_SRCS}
766 )
767
768+target_link_libraries(notifybackend ${GIO_LIBRARIES})
769+
770 add_library(notifyplugin MODULE
771 ${CORE_SRCS}
772 NotificationPlugin.cpp
773 ../include/NotificationPlugin.h
774 )
775
776+target_link_libraries(notifyplugin ${GIO_LIBRARIES})
777+
778 set_target_properties(notifyplugin PROPERTIES
779 SOVERSION ${SONAME}
780 VERSION ${SOVERSION}
781
782=== added file 'src/Feedback.cpp'
783--- src/Feedback.cpp 1970-01-01 00:00:00 +0000
784+++ src/Feedback.cpp 2013-09-04 16:15:41 +0000
785@@ -0,0 +1,32 @@
786+#include <QString>
787+#include <QObject>
788+#include <QtDBus>
789+#include <QSharedPointer>
790+
791+#include "Feedback.h"
792+#include "FeedbackInterfaceAdaptor.h"
793+#include "NotificationModel.h"
794+#include "Notification.h"
795+
796+Feedback::Feedback(NotificationModel& m, QObject *parent) : QObject(parent), model(m) {
797+ new FeedbackInterfaceAdaptor(this);
798+ QDBusConnection connection = QDBusConnection::sessionBus();
799+ connection.registerObject(FEEDBACK_DBUS_PATH, this);
800+ connection.registerService(FEEDBACK_DBUS_NAME);
801+}
802+
803+QStringList Feedback::collect(const unsigned int id) {
804+ fprintf(stderr, "Feedback::collect()\n");
805+ QStringList list;
806+ QSharedPointer<Notification> notification;
807+
808+ notification = model.getNotification(id);
809+ if(!notification.isNull()) {
810+ list = notification->getEntries();
811+ }
812+ else {
813+ fprintf(stderr, "Feedback::collect() - could not get notification");
814+ }
815+
816+ return list;
817+}
818
819=== added file 'src/FeedbackInterface.cpp'
820--- src/FeedbackInterface.cpp 1970-01-01 00:00:00 +0000
821+++ src/FeedbackInterface.cpp 2013-09-04 16:15:41 +0000
822@@ -0,0 +1,26 @@
823+/*
824+ * This file was generated by qdbusxml2cpp version 0.8
825+ * Command line was: qdbusxml2cpp -v -c FeedbackInterface -p include/FeedbackInterface.h:src/FeedbackInterface.cpp com.canonical.snapdecisions.feedback.xml
826+ *
827+ * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
828+ *
829+ * This is an auto-generated file.
830+ * This file may have been hand-edited. Look for HAND-EDIT comments
831+ * before re-generating it.
832+ */
833+
834+#include "FeedbackInterface.h"
835+
836+/*
837+ * Implementation of interface class FeedbackInterface
838+ */
839+
840+FeedbackInterface::FeedbackInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
841+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
842+{
843+}
844+
845+FeedbackInterface::~FeedbackInterface()
846+{
847+}
848+
849
850=== added file 'src/FeedbackInterfaceAdaptor.cpp'
851--- src/FeedbackInterfaceAdaptor.cpp 1970-01-01 00:00:00 +0000
852+++ src/FeedbackInterfaceAdaptor.cpp 2013-09-04 16:15:41 +0000
853@@ -0,0 +1,43 @@
854+/*
855+ * This file was generated by qdbusxml2cpp version 0.8
856+ * Command line was: qdbusxml2cpp -c FeedbackInterfaceAdaptor -a include/FeedbackInterfaceAdaptor.h:src/FeedbackInterfaceAdaptor.cpp com.canonical.snapdecisions.feedback.xml
857+ *
858+ * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
859+ *
860+ * This is an auto-generated file.
861+ * Do not edit! All changes made to it will be lost.
862+ */
863+
864+#include "FeedbackInterfaceAdaptor.h"
865+#include <QtCore/QMetaObject>
866+#include <QtCore/QByteArray>
867+#include <QtCore/QList>
868+#include <QtCore/QMap>
869+#include <QtCore/QString>
870+#include <QtCore/QStringList>
871+#include <QtCore/QVariant>
872+
873+/*
874+ * Implementation of adaptor class FeedbackInterfaceAdaptor
875+ */
876+
877+FeedbackInterfaceAdaptor::FeedbackInterfaceAdaptor(QObject *parent)
878+ : QDBusAbstractAdaptor(parent)
879+{
880+ // constructor
881+ setAutoRelaySignals(true);
882+}
883+
884+FeedbackInterfaceAdaptor::~FeedbackInterfaceAdaptor()
885+{
886+ // destructor
887+}
888+
889+QStringList FeedbackInterfaceAdaptor::collect(uint id)
890+{
891+ // handle method call com.canonical.snapdecisions.feedback.collect
892+ QStringList out0;
893+ QMetaObject::invokeMethod(parent(), "collect", Q_RETURN_ARG(QStringList, out0), Q_ARG(uint, id));
894+ return out0;
895+}
896+
897
898=== modified file 'src/Notification.cpp'
899--- src/Notification.cpp 2013-09-03 12:41:34 +0000
900+++ src/Notification.cpp 2013-09-04 16:15:41 +0000
901@@ -35,6 +35,8 @@
902 QString icon;
903 QString secondaryIcon;
904 QStringList actions;
905+ QStringList entries;
906+ Notification::SystemDialog systemDialog;
907 ActionModel* actionsModel;
908 int hints;
909 int displayTime;
910@@ -174,6 +176,7 @@
911 if(p->urg != urg) {
912 p->urg = urg;
913 Q_EMIT urgencyChanged(p->urg);
914+ Q_EMIT dataChanged(p->id);
915 }
916 }
917
918@@ -181,6 +184,32 @@
919 if(p->type != p->type) {
920 p->type = type;
921 Q_EMIT typeChanged(p->type);
922+ Q_EMIT dataChanged(p->id);
923+ }
924+}
925+
926+QStringList Notification::getEntries() const {
927+ fprintf(stderr, "Notification::getEntries()\n");
928+ return p->entries;
929+}
930+
931+void Notification::setEntries(QStringList entries) {
932+ if(p->entries != entries) {
933+ p->entries = entries;
934+ Q_EMIT entriesChanged(p->entries);
935+ Q_EMIT dataChanged(p->id);
936+ }
937+}
938+
939+Notification::SystemDialog Notification::getSystemDialog() const {
940+ return p->systemDialog;
941+}
942+
943+void Notification::setSystemDialog(SystemDialog systemDialog) {
944+ if (p->systemDialog != systemDialog) {
945+ p->systemDialog = systemDialog;
946+ Q_EMIT systemDialogChanged(p->systemDialog);
947+ Q_EMIT dataChanged(p->id);
948 }
949 }
950
951@@ -192,6 +221,7 @@
952 if(p->actions != actions) {
953 p->actions = actions;
954 Q_EMIT actionsChanged(p->actions);
955+ Q_EMIT dataChanged(p->id);
956
957 for (int i = 0; i < p->actions.size(); i += 2) {
958 p->actionsModel->insertAction(p->actions[i], p->actions[i+1]);
959@@ -206,6 +236,7 @@
960 void Notification::setHints(int hints) {
961 p->hints = hints;
962 Q_EMIT hintsChanged(p->hints);
963+ Q_EMIT dataChanged(p->id);
964 }
965
966 void Notification::onHovered() {
967@@ -217,6 +248,7 @@
968 }
969
970 void Notification::invokeAction(const QString action) {
971+ fprintf(stderr, "Notification::invokeAction()\n");
972 for(int i=0; i<p->actions.size(); i++) {
973 if(p->actions[i] == action) {
974 p->server->invokeAction(p->id, action);
975
976=== modified file 'src/NotificationClient.cpp'
977--- src/NotificationClient.cpp 2013-09-03 12:41:34 +0000
978+++ src/NotificationClient.cpp 2013-09-04 16:15:41 +0000
979@@ -40,7 +40,7 @@
980 hints["urgency"] = (char)urg;
981
982 if(ntype == Notification::Type::Confirmation) {
983- hints[SYNCH_HINT] = "yes";
984+ hints[SYNC_HINT] = "yes";
985 }
986 if(ntype == Notification::Type::SnapDecision) {
987 QStringList snaps;
988
989=== modified file 'src/NotificationModel.cpp'
990--- src/NotificationModel.cpp 2013-09-03 12:41:34 +0000
991+++ src/NotificationModel.cpp 2013-09-04 16:15:41 +0000
992@@ -32,6 +32,7 @@
993 QVector<QSharedPointer<Notification> > ephemeralQueue;
994 QVector<QSharedPointer<Notification> > interactiveQueue;
995 QVector<QSharedPointer<Notification> > snapQueue;
996+ QVector<QSharedPointer<Notification> > dialogQueue;
997 QMap<NotificationID, int> displayTimes;
998 };
999
1000@@ -82,6 +83,9 @@
1001 case RoleSecondaryIcon:
1002 return QVariant(p->displayedNotifications[index.row()]->getSecondaryIcon());
1003
1004+ case RoleEntries:
1005+ return QVariant::fromValue(p->displayedNotifications[index.row()]->getEntries());
1006+
1007 case RoleActions:
1008 return QVariant::fromValue(p->displayedNotifications[index.row()]->getActions());
1009
1010@@ -91,6 +95,9 @@
1011 case RoleNotification:
1012 return QVariant(p->displayedNotifications[index.row()]);
1013
1014+ case RoleSystemDialog:
1015+ return QVariant(p->displayedNotifications[index.row()]->getSystemDialog());
1016+
1017 default:
1018 return QVariant();
1019 }
1020@@ -108,6 +115,7 @@
1021 case Notification::Type::Confirmation : insertConfirmation(n); break;
1022 case Notification::Type::Interactive : insertInteractive(n); break;
1023 case Notification::Type::SnapDecision : insertSnap(n); break;
1024+ case Notification::Type::Dialog : insertDialog(n); break;
1025 default:
1026 printf("Unknown notification type, I should probably throw an exception here.\n");
1027 break;
1028@@ -119,6 +127,7 @@
1029 }
1030
1031 QSharedPointer<Notification> NotificationModel::getNotification(NotificationID id) const {
1032+ fprintf(stderr, "NotificationModel::getNotification()\n");
1033 for(int i=0; i<p->ephemeralQueue.size(); i++) {
1034 if(p->ephemeralQueue[i]->getID() == id) {
1035 return p->ephemeralQueue[i];
1036@@ -134,6 +143,11 @@
1037 return p->snapQueue[i];
1038 }
1039 }
1040+ for(int i=0; i<p->dialogQueue.size(); i++) {
1041+ if(p->dialogQueue[i]->getID() == id) {
1042+ return p->dialogQueue[i];
1043+ }
1044+ }
1045 for(int i=0; i<p->displayedNotifications.size(); i++) {
1046 if(p->displayedNotifications[i]->getID() == id) {
1047 return p->displayedNotifications[i];
1048@@ -175,6 +189,7 @@
1049 }
1050
1051 void NotificationModel::removeNotification(const NotificationID id) {
1052+ fprintf(stderr, "NotificationModel::removeNotification()\n");
1053 for(int i=0; i<p->ephemeralQueue.size(); i++) {
1054 if(p->ephemeralQueue[i]->getID() == id) {
1055 p->ephemeralQueue.erase(p->ephemeralQueue.begin() + i);
1056@@ -191,6 +206,14 @@
1057 }
1058 }
1059
1060+ for(int i=0; i<p->dialogQueue.size(); i++) {
1061+ if(p->dialogQueue[i]->getID() == id) {
1062+ p->dialogQueue.erase(p->dialogQueue.begin() + i);
1063+ Q_EMIT queueSizeChanged(queued());
1064+ return;
1065+ }
1066+ }
1067+
1068 for(int i=0; i<p->interactiveQueue.size(); i++) {
1069 if(p->interactiveQueue[i]->getID() == id) {
1070 p->interactiveQueue.erase(p->interactiveQueue.begin() + i);
1071@@ -292,6 +315,7 @@
1072 for(int i=p->displayedNotifications.size()-1; i>=0; i--) {
1073 QSharedPointer<Notification> n = p->displayedNotifications[i];
1074 switch(n->getType()) {
1075+ case Notification::Type::Dialog : break;
1076 case Notification::Type::SnapDecision : break;
1077 case Notification::Type::Confirmation : deleteFromVisible(i); break;
1078 case Notification::Type::Ephemeral : deleteFromVisible(i); p->ephemeralQueue.push_front(n); queueSizeChanged(queued()); break;
1079@@ -409,6 +433,34 @@
1080 }
1081 }
1082
1083+void NotificationModel::insertDialog(QSharedPointer<Notification> n) {
1084+ Q_ASSERT(n->getType() == Notification::Type::Dialog);
1085+ removeNonSnap();
1086+ int showing = countShowing(n->getType());
1087+ if(showing >= maxSnapsShown) {
1088+ int loc = findFirst(Notification::Type::SnapDecision);
1089+ bool replaced = false;
1090+ for(int i=0; i<showing; i++) {
1091+ if(p->displayedNotifications[loc+i]->getUrgency() < n->getUrgency()) {
1092+ QSharedPointer<Notification> lastShowing = p->displayedNotifications[loc+showing-1];
1093+ deleteFromVisible(loc+showing-1);
1094+ insertToVisible(n, loc+i);
1095+ p->dialogQueue.push_front(lastShowing);
1096+ replaced = true;
1097+ break;
1098+ }
1099+ }
1100+ if(!replaced) {
1101+ p->dialogQueue.push_back(n);
1102+ }
1103+ qStableSort(p->dialogQueue.begin(), p->dialogQueue.end(), notificationCompare);
1104+ Q_EMIT queueSizeChanged(queued());
1105+ } else {
1106+ int loc = insertionPoint(n);
1107+ insertToVisible(n, loc);
1108+ }
1109+}
1110+
1111 int NotificationModel::insertionPoint(const QSharedPointer<Notification> n) const {
1112 int i=0;
1113 if(n->getType() == Notification::Type::SnapDecision) {
1114@@ -514,9 +566,11 @@
1115 roles.insert(RoleValue, "value");
1116 roles.insert(RoleIcon, "icon");
1117 roles.insert(RoleSecondaryIcon, "secondaryIcon");
1118+ roles.insert(RoleEntries, "entries");
1119 roles.insert(RoleActions, "actions");
1120 roles.insert(RoleHints, "hints");
1121 roles.insert(RoleNotification, "notification");
1122+ roles.insert(RoleSystemDialog, "systemDialog");
1123
1124 return roles;
1125 }
1126
1127=== modified file 'src/NotificationServer.cpp'
1128--- src/NotificationServer.cpp 2013-09-03 12:41:34 +0000
1129+++ src/NotificationServer.cpp 2013-09-04 16:15:41 +0000
1130@@ -20,30 +20,62 @@
1131 #include "NotificationModel.h"
1132 #include "NotificationServer.h"
1133 #include "Notification.h"
1134+#include "Feedback.h"
1135+
1136 #include <QDBusMetaType>
1137 #include <QSharedPointer>
1138
1139+#define DIALOG_MODEL_DBUS_NAME "com.canonical.snapdecisions.systemdialog"
1140+#define DIALOG_MODEL_DBUS_OBJECTPATH "/com/canonical/snapdecisions/systemdialog"
1141+
1142 NotificationServer::NotificationServer(NotificationModel &m, QObject *parent) :
1143 QDBusAbstractAdaptor(parent), model(m), idCounter(1) {
1144 qDBusRegisterMetaType<Hints>();
1145
1146 connect(this, SIGNAL(dataChanged(unsigned int)), &m, SLOT(onDataChanged(unsigned int)));
1147+ Feedback* feedback = new Feedback(m);
1148+
1149+ wifiAuthConnection = NULL;
1150+ wifiAuthBusName = 0;
1151+ wifiAuthModel = 0;
1152+
1153+ wifiSelectConnection = NULL;
1154+ wifiSelectBusName = 0;
1155+ wifiSelectModel = 0;
1156+
1157+ userAuthConnection = NULL;
1158+ userAuthBusName = 0;
1159+ userAuthModel = 0;
1160+}
1161+
1162+void NotificationServer::teardownMenuModels() {
1163+ if(wifiAuthBusName > 0) {
1164+ g_bus_unown_name(wifiAuthBusName);
1165+ g_dbus_connection_unexport_menu_model(wifiAuthConnection, wifiAuthModel);
1166+ }
1167+
1168+ if(wifiSelectBusName > 0) {
1169+ g_bus_unown_name(wifiSelectBusName);
1170+ g_dbus_connection_unexport_menu_model(wifiSelectConnection, wifiSelectModel);
1171+ }
1172+
1173+ if(userAuthBusName)
1174+ {
1175+ g_bus_unown_name(userAuthBusName);
1176+ g_dbus_connection_unexport_menu_model(userAuthConnection, userAuthModel);
1177+ }
1178 }
1179
1180 NotificationServer::~NotificationServer() {
1181-
1182 }
1183
1184 void NotificationServer::invokeAction(unsigned int id, QString action) {
1185+ fprintf(stderr, "NotificationServer::invokeAction()\n");
1186 Q_EMIT ActionInvoked(id, action);
1187 }
1188
1189-
1190 #define INTERACTIVE_HINT "x-canonical-switch-to-application"
1191
1192-
1193-
1194-
1195 QStringList NotificationServer::GetCapabilities() const {
1196 QStringList capabilities;
1197 capabilities.push_back("actions");
1198@@ -52,12 +84,16 @@
1199 capabilities.push_back("icon-static");
1200 capabilities.push_back("image/svg+xml");
1201 capabilities.push_back(URGENCY_HINT);
1202- capabilities.push_back(SYNCH_HINT);
1203+ capabilities.push_back(SYNC_HINT);
1204 capabilities.push_back(APPEND_HINT);
1205 capabilities.push_back(ICON_ONLY_HINT);
1206 capabilities.push_back(BUTTON_TINT_HINT);
1207 capabilities.push_back(TRUNCATION_HINT);
1208 capabilities.push_back(SNAP_HINT);
1209+ capabilities.push_back(DIALOG_HINT);
1210+ capabilities.push_back(DIALOG_PASSWORD_HINT);
1211+ capabilities.push_back(DIALOG_LISTVIEW_HINT);
1212+ capabilities.push_back(DIALOG_FEEDBACK_HINT);
1213 capabilities.push_back(SECONDARY_ICON_HINT);
1214
1215 return capabilities;
1216@@ -76,7 +112,7 @@
1217 }
1218 Notification::Type ntype = Notification::Type::Ephemeral;
1219 expireTimeout = 5000;
1220- if(hints.find(SYNCH_HINT) != hints.end()) {
1221+ if(hints.find(SYNC_HINT) != hints.end()) {
1222 expireTimeout = 3000;
1223 ntype = Notification::Type::Confirmation;
1224 } else if (hints.find(SNAP_HINT) != hints.end()) {
1225@@ -87,6 +123,20 @@
1226 expireTimeout = 5000;
1227 }
1228
1229+ if(hints.find(DIALOG_HINT) != hints.end()) {
1230+ expireTimeout = 60000;
1231+ ntype = Notification::Type::Dialog;
1232+ }
1233+
1234+ // only allow the combination DIALOG_PASSWORD_HINT + DIALOG_FEEDBACK_HINT or
1235+ // DIALOG_LISTVIEW_HINT + DIALOG_FEEDBACK_HINT
1236+ /*if((hints.find(DIALOG_PASSWORD_HINT) != hints.end() ||
1237+ hints.find(DIALOG_LISTVIEW_HINT) != hints.end()) &&
1238+ hints.find(DIALOG_FEEDBACK_HINT) != hints.end()) {
1239+ expireTimeout = 60000;
1240+ ntype = Notification::Type::Dialog;
1241+ }*/
1242+
1243 Notification* n = new Notification(id, expireTimeout, urg, ntype, this);
1244 connect(n, SIGNAL(dataChanged(unsigned int)), this, SLOT(onDataChanged(unsigned int)));
1245 connect(n, SIGNAL(completed(unsigned int)), this, SLOT(onCompleted(unsigned int)));
1246@@ -100,7 +150,6 @@
1247 const unsigned int FAILURE = 0; // Is this correct?
1248 const int minActions = 4;
1249 const int maxActions = 12;
1250- //QImage icon(app_icon);
1251 int currentId = idCounter;
1252 QSharedPointer<Notification> notification;
1253 if(replaces_id != 0) {
1254@@ -148,6 +197,30 @@
1255 idCounter = 1;
1256 }
1257
1258+ if(hints.find(SYNC_HINT) != hints.end()) {
1259+ int hints = notification->getHints();
1260+ hints |= Notification::Hint::Sync;
1261+ notification->setHints(hints);
1262+ }
1263+
1264+ if(hints.find(ICON_ONLY_HINT) != hints.end()) {
1265+ int hints = notification->getHints();
1266+ hints |= Notification::Hint::IconOnly;
1267+ notification->setHints(hints);
1268+ }
1269+
1270+ if(hints.find(BUTTON_TINT_HINT) != hints.end()) {
1271+ int hints = notification->getHints();
1272+ hints |= Notification::Hint::ButtonTint;
1273+ notification->setHints(hints);
1274+ }
1275+
1276+ if(hints.find(TRUNCATION_HINT) != hints.end()) {
1277+ int hints = notification->getHints();
1278+ hints |= Notification::Hint::Truncation;
1279+ notification->setHints(hints);
1280+ }
1281+
1282 if(notification->getType() == Notification::Type::Interactive) {
1283 int numActions = actions.size();
1284 if(numActions != 2) {
1285@@ -157,6 +230,32 @@
1286 notification->setActions(actions);
1287 }
1288
1289+ if(notification->getType() == Notification::Type::Dialog) {
1290+ int numActions = actions.size();
1291+ if(numActions != 4) {
1292+ fprintf(stderr, "Wrong number of actions for an system-dialog notification. Has %d, requires %d.\n", numActions, 4);
1293+ return FAILURE;
1294+ }
1295+ notification->setActions(actions);
1296+
1297+ if(hints.find(DIALOG_HINT) != hints.end()) {
1298+ QVariant variant = hints[DIALOG_HINT].variant();
1299+ if(variant.canConvert<QString>()) {
1300+ QString type = variant.toString();
1301+ if(type == SYSTEM_DIALOG_TYPE_WIFI_AUTH) {
1302+ notification->setSystemDialog(Notification::SystemDialog::WifiAuth);
1303+ exportWifiAuthModel();
1304+ } else if (type == SYSTEM_DIALOG_TYPE_WIFI_SELECT) {
1305+ notification->setSystemDialog(Notification::SystemDialog::WifiSelect);
1306+ exportWifiSelectModel();
1307+ } else if (type == SYSTEM_DIALOG_TYPE_USER_AUTH) {
1308+ notification->setSystemDialog(Notification::SystemDialog::UserAuth);
1309+ exportUserAuthModel();
1310+ }
1311+ }
1312+ }
1313+ }
1314+
1315 // Do this first because it can fail. In case we are updating an
1316 // existing notification exiting now means all old state is
1317 // preserved.
1318@@ -190,8 +289,10 @@
1319 }
1320
1321 void NotificationServer::CloseNotification (unsigned int id) {
1322+ fprintf(stderr, "NotificationServer::CloseNotification()\n");
1323 Q_EMIT NotificationClosed(id, 1);
1324 model.removeNotification(id);
1325+ teardownMenuModels();
1326 }
1327
1328 void NotificationServer::GetServerInformation (QString &name, QString &vendor, QString &version, QString &specVersion) const {
1329@@ -206,5 +307,91 @@
1330 }
1331
1332 void NotificationServer::onCompleted(unsigned int id) {
1333+ fprintf(stderr, "NotificationServer::onCompleted()\n");
1334 CloseNotification(id);
1335 }
1336+
1337+void busAcquiredWifiAuthModel(GDBusConnection* connection,
1338+ const gchar* name,
1339+ gpointer data) {
1340+ NotificationServer* self = (NotificationServer*) data;
1341+ GMenu* menu = g_menu_new();
1342+ GMenuItem* item = g_menu_item_new("Password:", NULL);
1343+ g_menu_item_set_attribute_value(item, "x-canonical-type",
1344+ g_variant_new_string("com.canonical.snapdecision.textfield"));
1345+ g_menu_item_set_attribute_value(item, "x-echo-mode-password",
1346+ g_variant_new_boolean(true));
1347+ g_menu_append_item(menu, item);
1348+
1349+ self->wifiAuthConnection = connection;
1350+ self->wifiAuthModel = g_dbus_connection_export_menu_model(connection,
1351+ DIALOG_MODEL_DBUS_OBJECTPATH,
1352+ (GMenuModel*) menu,
1353+ NULL);
1354+}
1355+
1356+void busAcquiredWifiSelectModel(GDBusConnection* connection,
1357+ const gchar* name,
1358+ gpointer data) {
1359+ NotificationServer* self = (NotificationServer*) data;
1360+ self->wifiSelectConnection = connection;
1361+}
1362+
1363+void busAcquiredUserAuthModel(GDBusConnection* connection,
1364+ const gchar* name,
1365+ gpointer data) {
1366+ NotificationServer* self = (NotificationServer*) data;
1367+ GMenu* menu = g_menu_new();
1368+ GMenuItem* item1 = g_menu_item_new("Login name:", NULL);
1369+ g_menu_item_set_attribute_value(item1, "x-canonical-type",
1370+ g_variant_new_string("com.canonical.snapdecision.textfield"));
1371+ g_menu_item_set_attribute_value(item1, "x-echo-mode-password",
1372+ g_variant_new_boolean(false));
1373+ g_menu_append_item(menu, item1);
1374+
1375+ GMenuItem* item2 = g_menu_item_new("Password:", NULL);
1376+ g_menu_item_set_attribute_value(item2, "x-canonical-type",
1377+ g_variant_new_string("com.canonical.snapdecision.textfield"));
1378+ g_menu_item_set_attribute_value(item2, "x-echo-mode-password",
1379+ g_variant_new_boolean(true));
1380+ g_menu_append_item(menu, item2);
1381+
1382+ self->userAuthConnection = connection;
1383+ self->userAuthModel = g_dbus_connection_export_menu_model(connection,
1384+ DIALOG_MODEL_DBUS_OBJECTPATH,
1385+ (GMenuModel*) menu,
1386+ NULL);
1387+}
1388+
1389+void NotificationServer::exportWifiAuthModel() {
1390+ wifiAuthBusName = g_bus_own_name(G_BUS_TYPE_SESSION,
1391+ DIALOG_MODEL_DBUS_NAME,
1392+ (GBusNameOwnerFlags) 0,
1393+ busAcquiredWifiAuthModel,
1394+ NULL,
1395+ NULL,
1396+ this,
1397+ NULL);
1398+}
1399+
1400+void NotificationServer::exportWifiSelectModel() {
1401+ wifiSelectBusName = g_bus_own_name(G_BUS_TYPE_SESSION,
1402+ DIALOG_MODEL_DBUS_NAME,
1403+ (GBusNameOwnerFlags) 0,
1404+ busAcquiredWifiSelectModel,
1405+ NULL,
1406+ NULL,
1407+ this,
1408+ NULL);
1409+}
1410+
1411+void NotificationServer::exportUserAuthModel() {
1412+ userAuthBusName = g_bus_own_name(G_BUS_TYPE_SESSION,
1413+ DIALOG_MODEL_DBUS_NAME,
1414+ (GBusNameOwnerFlags) 0,
1415+ busAcquiredUserAuthModel,
1416+ NULL,
1417+ NULL,
1418+ this,
1419+ NULL);
1420+}

Subscribers

People subscribed via source and target branches

to all changes: