Merge lp:~nick-dedekind/libdbusmenu-qt/qpaexporter into lp:libdbusmenu-qt

Proposed by Nick Dedekind on 2015-03-18
Status: Work in progress
Proposed branch: lp:~nick-dedekind/libdbusmenu-qt/qpaexporter
Merge into: lp:libdbusmenu-qt
Prerequisite: lp:~nick-dedekind/libdbusmenu-qt/Qt5-tests
Diff against target: 2985 lines (+2413/-149)
31 files modified
CMakeLists.txt (+12/-2)
Doxyfile.in (+1/-1)
debian/changelog (+7/-0)
src/CMakeLists.txt (+35/-28)
src/dbusmenuexporter.cpp (+5/-31)
src/dbusmenuexporterdbus_p.cpp (+4/-36)
src/dbusmenuexporterdbus_p.h (+10/-34)
src/dbusmenuexporterdbusinterface_p.cpp (+67/-0)
src/dbusmenuexporterdbusinterface_p.h (+80/-0)
src/dbusmenuexporterprivate_p.h (+1/-1)
src/dbusmenuimporter.cpp (+2/-2)
src/dbusmenuinterface.cpp (+63/-0)
src/dbusmenuinterface.h (+154/-0)
src/dbusmenuproperty.h (+78/-0)
src/dbusmenushortcut_p.cpp (+2/-0)
src/dbusmenutypes.cpp (+142/-1)
src/dbusmenutypes.h (+20/-5)
src/qpa/exportedplatformmenubar.cpp (+377/-0)
src/qpa/exportedplatformmenubar.h (+136/-0)
src/qpa/exportedplatformmenubar_p.cpp (+129/-0)
src/qpa/exportedplatformmenubar_p.h (+111/-0)
src/qpa/logging_p.h (+38/-0)
src/qpa/qpadbusmenuexporter_p.cpp (+357/-0)
src/qpa/qpadbusmenuexporter_p.h (+94/-0)
src/utils.cpp (+36/-1)
src/utils_p.h (+15/-5)
tests/CMakeLists.txt (+13/-0)
tests/dbusmenuexportertest.cpp (+2/-1)
tests/exportedplatformmenutest.cpp (+366/-0)
tests/exportedplatformmenutest.h (+55/-0)
tests/testutils.h (+1/-1)
To merge this branch: bzr merge lp:~nick-dedekind/libdbusmenu-qt/qpaexporter
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing on 2015-03-18
DBus Menu Team 2015-03-18 Pending
Review via email: mp+253334@code.launchpad.net

This proposal supersedes a proposal from 2015-03-05.

Description of the change

Added exporter support for Qt platform menus.
Exported dbus interface for com.canonical.dbusmenu for use in unity8.

To post a comment you must log in.
276. By Nick Dedekind on 2015-03-18

reverted dbus xml

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Unmerged revisions

276. By Nick Dedekind on 2015-03-18

reverted dbus xml

275. By Nick Dedekind on 2015-03-18

fixed addMenu

274. By Nick Dedekind on 2015-03-18

added exported platformmenu test

273. By Nick Dedekind on 2015-03-05

merged with test branch

272. By Nick Dedekind on 2015-03-05

parent of exporter

271. By Nick Dedekind on 2015-03-05

logging & version bump

270. By Nick Dedekind on 2015-03-04

added dbusmenuinterface + reworked dbus properties

269. By Nick Dedekind on 2015-02-23

more qpa exporter

268. By Nick Dedekind on 2015-02-10

app menu qpa exporter

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 2015-03-18 11:19:06 +0000
3+++ CMakeLists.txt 2015-03-18 11:19:06 +0000
4@@ -34,12 +34,22 @@
5 endif()
6 endif()
7
8+find_package(PkgConfig)
9 # Detect for which Qt version we're building
10 if (USE_QT5)
11+ find_package(Qt5Core REQUIRED)
12 find_package(Qt5Widgets REQUIRED)
13 find_package(Qt5DBus REQUIRED)
14- include_directories(${Qt5Widgets_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS})
15- find_package(Qt5Core REQUIRED)
16+ find_package(Qt5Gui REQUIRED)
17+ pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED)
18+
19+ include_directories(
20+ ${Qt5Widgets_INCLUDE_DIRS}
21+ ${Qt5DBus_INCLUDE_DIRS}
22+ ${Qt5DBus_PRIVATE_INCLUDE_DIRS}
23+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
24+ ${DBUS_CPP_INCLUDE_DIRS}
25+ )
26 set(CMAKE_AUTOMOC ON)
27 set(CMAKE_AUTOMOC_RELAXED_MODE ON)
28 set(CMAKE_POSITION_INDEPENDENT_CODE ON)
29
30=== modified file 'Doxyfile.in'
31--- Doxyfile.in 2011-03-24 15:04:52 +0000
32+++ Doxyfile.in 2015-03-18 11:19:06 +0000
33@@ -232,7 +232,7 @@
34 SEARCH_INCLUDES = YES
35 INCLUDE_PATH =
36 INCLUDE_FILE_PATTERNS =
37-PREDEFINED =
38+PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS
39 EXPAND_AS_DEFINED =
40 SKIP_FUNCTION_MACROS = YES
41 #---------------------------------------------------------------------------
42
43=== modified file 'debian/changelog'
44--- debian/changelog 2014-06-19 09:07:18 +0000
45+++ debian/changelog 2015-03-18 11:19:06 +0000
46@@ -1,3 +1,10 @@
47+libdbusmenu-qt (0.9.4) UNRELEASED; urgency=medium
48+
49+ [ Nick Dedekind ]
50+ * Added exported qpa platform menu & dbusmenu interface
51+
52+ -- Nick Dedekind <nick.dedekind@canonical.com> Thu, 05 Mar 2015 13:39:12 +0000
53+
54 libdbusmenu-qt (0.9.3+14.10.20140619-0ubuntu1) utopic; urgency=low
55
56 [ Aurélien Gâteau ]
57
58=== modified file 'src/CMakeLists.txt'
59--- src/CMakeLists.txt 2015-03-18 11:19:06 +0000
60+++ src/CMakeLists.txt 2015-03-18 11:19:06 +0000
61@@ -1,34 +1,20 @@
62 include(CheckCXXSourceCompiles)
63
64-check_cxx_compiler_flag(-Wall __DBUSMENU_HAVE_W_ALL)
65-if (__DBUSMENU_HAVE_W_ALL)
66- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
67-endif (__DBUSMENU_HAVE_W_ALL)
68-
69 # Check some compiler flags
70-check_cxx_compiler_flag(-fvisibility=hidden __DBUSMENU_HAVE_GCC_VISIBILITY)
71-if (__DBUSMENU_HAVE_GCC_VISIBILITY AND NOT WIN32)
72- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
73-endif (__DBUSMENU_HAVE_GCC_VISIBILITY AND NOT WIN32)
74-
75-check_cxx_compiler_flag(-Woverloaded-virtual __DBUSMENU_HAVE_W_OVERLOADED_VIRTUAL)
76-if (__DBUSMENU_HAVE_W_OVERLOADED_VIRTUAL)
77- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
78-endif (__DBUSMENU_HAVE_W_OVERLOADED_VIRTUAL)
79-
80 check_cxx_compiler_flag(-Wall __DBUSMENU_HAVE_W_ALL)
81 if (__DBUSMENU_HAVE_W_ALL)
82 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
83 endif (__DBUSMENU_HAVE_W_ALL)
84
85-check_cxx_compiler_flag(-std=c++11 __DBUSMENU_HAVE_CXX11)
86-if (__DBUSMENU_HAVE_CXX11)
87- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
88-endif (__DBUSMENU_HAVE_CXX11)
89+# Find the dbusxml2cpp tool
90+if(DEFINED ENV{DEB_BUILD_MULTIARCH})
91+ set(QDBUSXML2CPP_EXECUTABLE "/usr/lib/$ENV{DEB_BUILD_MULTIARCH}/qt5/bin/qdbusxml2cpp")
92+else()
93+ FIND_PROGRAM(QDBUSXML2CPP_EXECUTABLE qdbusxml2cpp)
94+endif()
95
96 # Check whether QIcon::name() exists. It was added in late Qt 4.7 cycle, and is
97 # not present in betas.
98-
99 if (NOT USE_QT5)
100 set(CMAKE_REQUIRED_INCLUDES "${QT_INCLUDE_DIR}")
101 set(CMAKE_REQUIRED_LIBRARIES "${QT_QTGUI_LIBRARIES};${QT_QTCORE_LIBRARIES}")
102@@ -49,34 +35,55 @@
103 endif()
104 configure_file(dbusmenu_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/dbusmenu_config.h @ONLY)
105
106+include_directories(
107+ ${CMAKE_SOURCE_DIR}/src
108+ ${CMAKE_BINARY_DIR}/src
109+ )
110+
111 set(dbusmenu_qt_SRCS
112 dbusmenu_p.cpp
113 dbusmenuexporter.cpp
114 dbusmenuexporterdbus_p.cpp
115+ dbusmenuexporterdbusinterface_p.cpp
116 dbusmenuimporter.cpp
117- dbusmenutypes_p.cpp
118+ dbusmenuinterface.cpp
119+ dbusmenutypes.cpp
120 dbusmenushortcut_p.cpp
121 utils.cpp
122- )
123-
124-include_directories(
125- ${CMAKE_SOURCE_DIR}/src
126- ${CMAKE_BINARY_DIR}/src
127+ dbusmenuproperty.h
128+ ${CMAKE_BINARY_DIR}/src/dbusmenuinterface_p.cpp
129 )
130
131 if (NOT USE_QT5)
132 qt4_automoc(${dbusmenu_qt_SRCS})
133 qt4_add_dbus_adaptor(dbusmenu_qt_SRCS
134 ${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.dbusmenu.xml
135- ${CMAKE_CURRENT_SOURCE_DIR}/dbusmenuexporterdbus_p.h DBusMenuExporterDBus
136+ ${CMAKE_CURRENT_SOURCE_DIR}/dbusmenuexporterdbusinterface_p.h DBusMenuExporterDBusInterface
137 )
138 else()
139+ set(dbusmenu_qt_SRCS
140+ ${dbusmenu_qt_SRCS}
141+ qpa/exportedplatformmenubar.cpp
142+ qpa/exportedplatformmenubar_p.cpp
143+ qpa/qpadbusmenuexporter_p.cpp
144+ )
145+
146 qt5_add_dbus_adaptor(dbusmenu_qt_SRCS
147 ${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.dbusmenu.xml
148- ${CMAKE_CURRENT_SOURCE_DIR}/dbusmenuexporterdbus_p.h DBusMenuExporterDBus
149+ ${CMAKE_CURRENT_SOURCE_DIR}/dbusmenuexporterdbusinterface_p.h DBusMenuExporterDBusInterface
150 )
151 endif()
152
153+if(${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.dbusmenu.xml IS_NEWER_THAN ${CMAKE_CURRENT_BINARY_DIR}/dbusmenuinterface.h)
154+ execute_process(COMMAND ${QDBUSXML2CPP_EXECUTABLE}
155+ -c DbusMenuInterfacePrivate
156+ -p ${CMAKE_CURRENT_BINARY_DIR}/dbusmenuinterface_p
157+ -i "${CMAKE_SOURCE_DIR}/src/dbusmenutypes.h"
158+ ${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.dbusmenu.xml
159+ com.canonical.dbusmenu
160+ )
161+endif()
162+
163 configure_file(dbusmenu_version.h.in
164 ${CMAKE_CURRENT_BINARY_DIR}/dbusmenu_version.h
165 )
166
167=== modified file 'src/dbusmenuexporter.cpp'
168--- src/dbusmenuexporter.cpp 2012-10-24 14:43:10 +0000
169+++ src/dbusmenuexporter.cpp 2015-03-18 11:19:06 +0000
170@@ -35,7 +35,7 @@
171 #include "dbusmenu_p.h"
172 #include "dbusmenuexporterdbus_p.h"
173 #include "dbusmenuexporterprivate_p.h"
174-#include "dbusmenutypes_p.h"
175+#include "dbusmenutypes.h"
176 #include "dbusmenushortcut_p.h"
177 #include "debug_p.h"
178 #include "utils_p.h"
179@@ -94,7 +94,7 @@
180 QAction *action = button->defaultAction();
181 DMRETURN_VALUE_IF_FAIL(action, map);
182
183- map.insert("label", swapMnemonicChar(action->text(), '&', '_'));
184+ map.insert("label", Utils::swapMnemonicChar(action->text(), '&', '_'));
185 insertIconProperty(&map, action);
186 if (!action->isVisible()) {
187 map.insert("visible", false);
188@@ -115,7 +115,7 @@
189 QVariantMap DBusMenuExporterPrivate::propertiesForStandardAction(QAction *action) const
190 {
191 QVariantMap map;
192- map.insert("label", swapMnemonicChar(action->text(), '&', '_'));
193+ map.insert("label", Utils::swapMnemonicChar(action->text(), '&', '_'));
194 if (!action->isEnabled()) {
195 map.insert("enabled", false);
196 }
197@@ -338,7 +338,7 @@
198 d->m_emittedLayoutUpdatedOnce = false;
199 d->m_itemUpdatedTimer = new QTimer(this);
200 d->m_layoutUpdatedTimer = new QTimer(this);
201- d->m_dbusObject = new DBusMenuExporterDBus(this);
202+ d->m_dbusObject = new DBusMenuExporterDBus(objectPath, this);
203
204 d->addMenu(d->m_rootMenu, 0);
205
206@@ -379,33 +379,7 @@
207 QVariantMap updatedProperties;
208 QStringList removedProperties;
209
210- // Find updated and removed properties
211- QVariantMap::ConstIterator newEnd = newProperties.constEnd();
212-
213- QVariantMap::ConstIterator
214- oldIt = oldProperties.constBegin(),
215- oldEnd = oldProperties.constEnd();
216- for(; oldIt != oldEnd; ++oldIt) {
217- QString key = oldIt.key();
218- QVariantMap::ConstIterator newIt = newProperties.constFind(key);
219- if (newIt != newEnd) {
220- if (newIt.value() != oldIt.value()) {
221- updatedProperties.insert(key, newIt.value());
222- }
223- } else {
224- removedProperties << key;
225- }
226- }
227-
228- // Find new properties (treat them as updated properties)
229- QVariantMap::ConstIterator newIt = newProperties.constBegin();
230- for (; newIt != newEnd; ++newIt) {
231- QString key = newIt.key();
232- oldIt = oldProperties.constFind(key);
233- if (oldIt == oldEnd) {
234- updatedProperties.insert(key, newIt.value());
235- }
236- }
237+ Utils::parsePropertyChanges(oldProperties, newProperties, updatedProperties, removedProperties);
238
239 // Update our data (oldProperties is a reference)
240 oldProperties = newProperties;
241
242=== modified file 'src/dbusmenuexporterdbus_p.cpp'
243--- src/dbusmenuexporterdbus_p.cpp 2011-08-29 14:51:01 +0000
244+++ src/dbusmenuexporterdbus_p.cpp 2015-03-18 11:19:06 +0000
245@@ -21,26 +21,19 @@
246 #include "dbusmenuexporterdbus_p.h"
247
248 // Qt
249-#include <QDBusMessage>
250+#include <QEvent>
251 #include <QMenu>
252 #include <QVariant>
253
254 // Local
255-#include "dbusmenuadaptor.h"
256 #include "dbusmenuexporterprivate_p.h"
257 #include "dbusmenushortcut_p.h"
258 #include "debug_p.h"
259
260-static const char *DBUSMENU_INTERFACE = "com.canonical.dbusmenu";
261-static const char *FDO_PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
262-
263-DBusMenuExporterDBus::DBusMenuExporterDBus(DBusMenuExporter *exporter)
264-: QObject(exporter)
265-, m_exporter(exporter)
266-, m_status("normal")
267+DBusMenuExporterDBus::DBusMenuExporterDBus(const QString& objectPath, DBusMenuExporter *exporter)
268+ : DBusMenuExporterDBusInterface(objectPath, exporter)
269+ , m_exporter(exporter)
270 {
271- DBusMenuTypes_register();
272- new DbusmenuAdaptor(this);
273 }
274
275 uint DBusMenuExporterDBus::GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item)
276@@ -157,30 +150,5 @@
277 return filter.mChanged;
278 }
279
280-void DBusMenuExporterDBus::setStatus(const QString& status)
281-{
282- if (m_status == status) {
283- return;
284- }
285- m_status = status;
286-
287- QVariantMap map;
288- map.insert("Status", QVariant(status));
289-
290- QDBusMessage msg = QDBusMessage::createSignal(m_exporter->d->m_objectPath, FDO_PROPERTIES_INTERFACE, "PropertiesChanged");
291- QVariantList args = QVariantList()
292- << DBUSMENU_INTERFACE
293- << map
294- << QStringList() // New properties: none
295- ;
296- msg.setArguments(args);
297- QDBusConnection::sessionBus().send(msg);
298-}
299-
300-QString DBusMenuExporterDBus::status() const
301-{
302- return m_status;
303-}
304-
305
306 #include "dbusmenuexporterdbus_p.moc"
307
308=== modified file 'src/dbusmenuexporterdbus_p.h'
309--- src/dbusmenuexporterdbus_p.h 2011-08-29 14:51:01 +0000
310+++ src/dbusmenuexporterdbus_p.h 2015-03-18 11:19:06 +0000
311@@ -22,50 +22,26 @@
312 #define DBUSMENUEXPORTERDBUS_P_H
313
314 // Local
315-#include <dbusmenutypes_p.h>
316-
317-// Qt
318-#include <QtCore/QObject>
319-#include <QtCore/QVariant>
320-#include <QtDBus/QDBusAbstractAdaptor>
321-#include <QtDBus/QDBusVariant>
322+#include "dbusmenuexporterdbusinterface_p.h"
323
324 class DBusMenuExporter;
325
326-/**
327- * Internal class implementing the DBus side of DBusMenuExporter
328- * This avoid exposing the implementation of the DBusMenu spec to the outside
329- * world.
330- */
331-class DBusMenuExporterDBus : public QObject
332+class DBusMenuExporterDBus : public DBusMenuExporterDBusInterface
333 {
334 Q_OBJECT
335 Q_CLASSINFO("D-Bus Interface", "com.canonical.dbusmenu")
336- Q_PROPERTY(uint Version READ Version)
337- Q_PROPERTY(QString Status READ status)
338 public:
339- DBusMenuExporterDBus(DBusMenuExporter *m_exporter);
340-
341- uint Version() const { return 2; }
342-
343- QString status() const;
344- void setStatus(const QString &status);
345-
346-public Q_SLOTS:
347- Q_NOREPLY void Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp);
348- QDBusVariant GetProperty(int id, const QString &property);
349- uint GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item);
350- DBusMenuItemList GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames);
351- bool AboutToShow(int id);
352-
353-Q_SIGNALS:
354- void ItemsPropertiesUpdated(DBusMenuItemList, DBusMenuItemKeysList);
355- void LayoutUpdated(uint revision, int parentId);
356- void ItemActivationRequested(int id, uint timeStamp);
357+ DBusMenuExporterDBus(const QString& objectPath, DBusMenuExporter *m_exporter);
358+
359+public: // overrides
360+ void Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp) override;
361+ QDBusVariant GetProperty(int id, const QString &property) override;
362+ uint GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item) override;
363+ DBusMenuItemList GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames) override;
364+ bool AboutToShow(int id) override;
365
366 private:
367 DBusMenuExporter *m_exporter;
368- QString m_status;
369
370 friend class DBusMenuExporter;
371 friend class DBusMenuExporterPrivate;
372
373=== added file 'src/dbusmenuexporterdbusinterface_p.cpp'
374--- src/dbusmenuexporterdbusinterface_p.cpp 1970-01-01 00:00:00 +0000
375+++ src/dbusmenuexporterdbusinterface_p.cpp 2015-03-18 11:19:06 +0000
376@@ -0,0 +1,67 @@
377+/* This file is part of the dbusmenu-qt library
378+ Copyright 2015 Canonical
379+ Author: Nick Dedekind <nick.dedekind@canonical.com>
380+
381+ This library is free software; you can redistribute it and/or
382+ modify it under the terms of the GNU Library General Public
383+ License (LGPL) as published by the Free Software Foundation;
384+ either version 2 of the License, or (at your option) any later
385+ version.
386+
387+ This library is distributed in the hope that it will be useful,
388+ but WITHOUT ANY WARRANTY; without even the implied warranty of
389+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
390+ Library General Public License for more details.
391+
392+ You should have received a copy of the GNU Library General Public License
393+ along with this library; see the file COPYING.LIB. If not, write to
394+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
395+ Boston, MA 02110-1301, USA.
396+*/
397+
398+#include "dbusmenuexporterdbusinterface_p.h"
399+#include "dbusmenuadaptor.h"
400+
401+// Qt
402+#include <QDBusMessage>
403+#include <QEvent>
404+
405+static const char *DBUSMENU_INTERFACE = "com.canonical.dbusmenu";
406+static const char *FDO_PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
407+
408+DBusMenuExporterDBusInterface::DBusMenuExporterDBusInterface(const QString& objectPath, QObject *parent)
409+ : QObject(parent)
410+ , m_objectPath(objectPath)
411+ , m_status("normal")
412+{
413+ DBusMenuTypes_register();
414+
415+ new DbusmenuAdaptor(this);
416+ QDBusConnection::sessionBus().registerObject(objectPath, this, QDBusConnection::ExportAllContents);
417+}
418+
419+QString DBusMenuExporterDBusInterface::status() const
420+{
421+ return m_status;
422+}
423+
424+void DBusMenuExporterDBusInterface::setStatus(const QString& status)
425+{
426+ if (m_status == status) {
427+ return;
428+ }
429+ m_status = status;
430+
431+ QVariantMap map;
432+ map.insert("Status", QVariant(status));
433+
434+ QDBusMessage msg = QDBusMessage::createSignal(m_objectPath, FDO_PROPERTIES_INTERFACE, "PropertiesChanged");
435+ QVariantList args = QVariantList()
436+ << DBUSMENU_INTERFACE
437+ << map
438+ << QStringList() // New properties: none
439+ ;
440+ msg.setArguments(args);
441+ QDBusConnection::sessionBus().send(msg);
442+}
443+
444
445=== added file 'src/dbusmenuexporterdbusinterface_p.h'
446--- src/dbusmenuexporterdbusinterface_p.h 1970-01-01 00:00:00 +0000
447+++ src/dbusmenuexporterdbusinterface_p.h 2015-03-18 11:19:06 +0000
448@@ -0,0 +1,80 @@
449+/* This file is part of the dbusmenu-qt library
450+ Copyright 2015 Canonical
451+ Author: Nick Dedekind <nick.dedekind@canonical.com>
452+
453+ This library is free software; you can redistribute it and/or
454+ modify it under the terms of the GNU Library General Public
455+ License (LGPL) as published by the Free Software Foundation;
456+ either version 2 of the License, or (at your option) any later
457+ version.
458+
459+ This library is distributed in the hope that it will be useful,
460+ but WITHOUT ANY WARRANTY; without even the implied warranty of
461+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
462+ Library General Public License for more details.
463+
464+ You should have received a copy of the GNU Library General Public License
465+ along with this library; see the file COPYING.LIB. If not, write to
466+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
467+ Boston, MA 02110-1301, USA.
468+*/
469+#ifndef DBUSMENUEXPORTERDBUSINTERFACE_P_H
470+#define DBUSMENUEXPORTERDBUSINTERFACE_P_H
471+
472+// Local
473+#include <dbusmenutypes.h>
474+
475+// Qt
476+#include <QtCore/QObject>
477+#include <QtCore/QVariant>
478+#include <QtDBus/QDBusAbstractAdaptor>
479+#include <QtDBus/QDBusVariant>
480+
481+/**
482+ * Internal class implementing the DBus side of DBusMenuExporter
483+ * This avoid exposing the implementation of the DBusMenu spec to the outside
484+ * world.
485+ */
486+class DBusMenuExporterDBusInterface : public QObject
487+{
488+ Q_OBJECT
489+ Q_CLASSINFO("D-Bus Interface", "com.canonical.dbusmenu")
490+ Q_PROPERTY(uint Version READ Version)
491+ Q_PROPERTY(QString Status READ status)
492+public:
493+ DBusMenuExporterDBusInterface(const QString& objectPath, QObject* parent = nullptr);
494+ uint Version() const { return 2; }
495+
496+ /**
497+ * The status of the menu. Can be one of "normal" or "notice". This can be
498+ * used to notify the other side the menu should be made more visible.
499+ * For example, appmenu uses it to tell Unity panel to show/hide the menubar
500+ * when the Alt modifier is pressed/released.
501+ */
502+ QString status() const;
503+
504+ /**
505+ * Returns the status of the menu.
506+ * @ref setStatus
507+ */
508+ void setStatus(const QString &status);
509+
510+public Q_SLOTS:
511+ virtual Q_NOREPLY void Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp) = 0;
512+ virtual QDBusVariant GetProperty(int id, const QString &property) = 0;
513+ virtual uint GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item) = 0;
514+ virtual DBusMenuItemList GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames) = 0;
515+ virtual bool AboutToShow(int id) = 0;
516+
517+Q_SIGNALS:
518+ void ItemsPropertiesUpdated(DBusMenuItemList, DBusMenuItemKeysList);
519+ void LayoutUpdated(uint revision, int parentId);
520+ void ItemActivationRequested(int id, uint timeStamp);
521+
522+private:
523+ QString m_objectPath;
524+ QString m_status;
525+};
526+
527+
528+#endif // DBUSMENUEXPORTERDBUSINTERFACE_P_H
529
530=== modified file 'src/dbusmenuexporterprivate_p.h'
531--- src/dbusmenuexporterprivate_p.h 2012-03-29 14:23:32 +0000
532+++ src/dbusmenuexporterprivate_p.h 2015-03-18 11:19:06 +0000
533@@ -23,7 +23,7 @@
534
535 // Local
536 #include "dbusmenuexporter.h"
537-#include "dbusmenutypes_p.h"
538+#include "dbusmenutypes.h"
539
540 // Qt
541 #include <QtCore/QHash>
542
543=== modified file 'src/dbusmenuimporter.cpp'
544--- src/dbusmenuimporter.cpp 2014-03-05 09:53:39 +0000
545+++ src/dbusmenuimporter.cpp 2015-03-18 11:19:06 +0000
546@@ -36,7 +36,7 @@
547 #include <QWidgetAction>
548
549 // Local
550-#include "dbusmenutypes_p.h"
551+#include "dbusmenutypes.h"
552 #include "dbusmenushortcut_p.h"
553 #include "debug_p.h"
554 #include "utils_p.h"
555@@ -199,7 +199,7 @@
556
557 void updateActionLabel(QAction *action, const QVariant &value)
558 {
559- QString text = swapMnemonicChar(value.toString(), '_', '&');
560+ QString text = Utils::swapMnemonicChar(value.toString(), '_', '&');
561 action->setText(text);
562 }
563
564
565=== added file 'src/dbusmenuinterface.cpp'
566--- src/dbusmenuinterface.cpp 1970-01-01 00:00:00 +0000
567+++ src/dbusmenuinterface.cpp 2015-03-18 11:19:06 +0000
568@@ -0,0 +1,63 @@
569+#include "dbusmenuinterface.h"
570+#include "dbusmenuinterface_p.h"
571+
572+DBusMenuInterface::DBusMenuInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
573+ : d(new DbusMenuInterfacePrivate(service, path, connection, this))
574+{
575+ DBusMenuTypes_register();
576+}
577+
578+uint DBusMenuInterface::version() const
579+{
580+ return d->version();
581+}
582+
583+QString DBusMenuInterface::status() const
584+{
585+ return d->status();
586+}
587+
588+bool DBusMenuInterface::isValid() const
589+{
590+ return d->isValid();
591+}
592+
593+QString DBusMenuInterface::service() const
594+{
595+ return d->service();
596+}
597+
598+QString DBusMenuInterface::path() const
599+{
600+ return d->path();
601+}
602+
603+QDBusPendingReply<bool> DBusMenuInterface::AboutToShow(int id)
604+{
605+ return d->AboutToShow(id);
606+}
607+
608+QDBusPendingReply<> DBusMenuInterface::Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp)
609+{
610+ return d->Event(id, eventId, data, timestamp);
611+}
612+
613+QDBusPendingReply<DBusMenuItemList> DBusMenuInterface::GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames)
614+{
615+ return d->GetGroupProperties(ids, propertyNames);
616+}
617+
618+QDBusPendingReply<QDBusVariant> DBusMenuInterface::GetProperty(int id, const QString &name)
619+{
620+ return d->GetProperty(id, name);
621+}
622+
623+QDBusPendingReply<uint, DBusMenuLayoutItem> DBusMenuInterface::GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames)
624+{
625+ return d->GetLayout(parentId, recursionDepth, propertyNames);
626+}
627+
628+QDBusReply<uint> DBusMenuInterface::GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &layout)
629+{
630+ return d->GetLayout(parentId, recursionDepth, propertyNames, layout);
631+}
632
633=== added file 'src/dbusmenuinterface.h'
634--- src/dbusmenuinterface.h 1970-01-01 00:00:00 +0000
635+++ src/dbusmenuinterface.h 2015-03-18 11:19:06 +0000
636@@ -0,0 +1,154 @@
637+/* This file is part of the dbusmenu-qt library
638+ Copyright 2015 Canonical
639+ Author: Nick Dedekind <nick.dedekind@canonical.com>
640+
641+ This library is free software; you can redistribute it and/or
642+ modify it under the terms of the GNU Library General Public
643+ License (LGPL) as published by the Free Software Foundation;
644+ either version 2 of the License, or (at your option) any later
645+ version.
646+
647+ This library is distributed in the hope that it will be useful,
648+ but WITHOUT ANY WARRANTY; without even the implied warranty of
649+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
650+ Library General Public License for more details.
651+
652+ You should have received a copy of the GNU Library General Public License
653+ along with this library; see the file COPYING.LIB. If not, write to
654+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
655+ Boston, MA 02110-1301, USA.
656+*/
657+#ifndef DBUSMENUINTERFACE_H
658+#define DBUSMENUINTERFACE_H
659+
660+// Local
661+#include <dbusmenutypes.h>
662+class DbusMenuInterfacePrivate;
663+
664+// Qt
665+#include <QtCore/QObject>
666+#include <QtDBus/QtDBus>
667+
668+/**
669+ * Internal class implementing the DBus side of DBusMenuExporter
670+ * This avoid exposing the implementation of the DBusMenu spec to the outside
671+ * world.
672+ */
673+class DBUSMENU_EXPORT DBusMenuInterface : public QObject
674+{
675+ Q_OBJECT
676+
677+ /**
678+ * Version of the menu interface.
679+ */
680+ Q_PROPERTY(uint Version READ version)
681+
682+ /**
683+ * Status of the menu.
684+ */
685+ Q_PROPERTY(QString Status READ status)
686+public:
687+ /**
688+ * Creates a DBusMenuInterface on specified service, path & connection
689+ */
690+ DBusMenuInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject* parent = nullptr);
691+
692+ /**
693+ * Returns the version of the menu interface.
694+ */
695+ uint version() const;
696+
697+ /**
698+ * The status of the menu. Can be one of "normal" or "notice". This can be
699+ * used to notify the other side the menu should be made more visible.
700+ * For example, appmenu uses it to tell Unity panel to show/hide the menubar
701+ * when the Alt modifier is pressed/released.
702+ */
703+ QString status() const;
704+
705+ /**
706+ * Returns true if this is a valid reference to a remote object.
707+ * It returns false if there was an error during the creation of the interface
708+ */
709+ bool isValid() const;
710+
711+ /**
712+ * Returns the name of the service this interface is associated with.
713+ */
714+ QString service() const;
715+
716+ /**
717+ * Returns the object path that this interface is associated with.
718+ */
719+ QString path() const;
720+
721+public Q_SLOTS:
722+ /**
723+ * This is called to notify the application that it is about
724+ * to show the menu under the specified item.
725+ */
726+ QDBusPendingReply<bool> AboutToShow(int id);
727+
728+ /**
729+ * This is called by the applet to notify the application an event happened on a
730+ * menu item.
731+ */
732+ QDBusPendingReply<> Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp);
733+
734+ /**
735+ * Returns the list of items which are children of @p parentId.
736+ */
737+ QDBusPendingReply<DBusMenuItemList> GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames);
738+
739+ /**
740+ * Get a signal property on a single item. This is not useful if you're
741+ * going to implement this interface, it should only be used if you're
742+ * debugging via a commandline tool.
743+ */
744+ QDBusPendingReply<QDBusVariant> GetProperty(int id, const QString &name);
745+
746+ /**
747+ * Provides the layout and propertiers that are attached to the entries
748+ * that are in the layout. It only gives the items that are children
749+ * of the item that is specified in @p parentId. It will return all of the
750+ * properties or specific ones depending of the value in @p propertyNames.
751+ */
752+ QDBusPendingReply<uint, DBusMenuLayoutItem> GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames);
753+
754+ /**
755+ * Provides the layout and propertiers that are attached to the entries
756+ * that are in the layout. It only gives the items that are children
757+ * of the item that is specified in @p parentId. It will return all of the
758+ * properties or specific ones depending of the value @p propertyNames.
759+ */
760+ QDBusReply<uint> GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &layout);
761+
762+Q_SIGNALS: // SIGNALS
763+ /**
764+ * The server is requesting that all clients displaying this
765+ * menu open it to the user. This would be for things like
766+ * hotkeys that when the user presses them the menu should
767+ * open and display itself to the user.
768+ */
769+ void ItemActivationRequested(int id, uint timestamp);
770+
771+ /**
772+ * Triggered when there are lots of property updates across many items
773+ * so they all get grouped into a single dbus message. The format is
774+ * the ID of the item with a hashtable of names and values for those
775+ * properties.
776+ */
777+ void ItemsPropertiesUpdated(DBusMenuItemList updatedProps, DBusMenuItemKeysList removedProps);
778+
779+ /**
780+ * Triggered by the application to notify display of a layout update, up to
781+ * revision
782+ */
783+ void LayoutUpdated(uint revision, int parent);
784+
785+private:
786+ DbusMenuInterfacePrivate* d;
787+};
788+
789+
790+#endif // DBUSMENUINTERFACE_H
791
792=== added file 'src/dbusmenuproperty.h'
793--- src/dbusmenuproperty.h 1970-01-01 00:00:00 +0000
794+++ src/dbusmenuproperty.h 2015-03-18 11:19:06 +0000
795@@ -0,0 +1,78 @@
796+#ifndef DBUSMENUPROPERTY_H
797+#define DBUSMENUPROPERTY_H
798+
799+#ifndef DOXYGEN_SHOULD_SKIP_THIS
800+
801+// Qt
802+#include <QtCore/QVariantMap>
803+
804+// Local
805+#include <dbusmenu_export.h>
806+
807+class QKeySequence;
808+class QByteArray;
809+class QString;
810+
811+//// DBusMenuProperty
812+/**
813+ * Structure which contains the names of the common properties
814+ * for a menu item.
815+ */
816+struct DBUSMENU_EXPORT DBusMenuProperty
817+{
818+ static const char* Type;
819+ static const char* Label;
820+ static const char* Enabled;
821+ static const char* Visible;
822+ static const char* IconName;
823+ static const char* IconData;
824+ static const char* Shortcut;
825+ static const char* ToggleType;
826+ static const char* ToggleState;
827+ static const char* ChildrenDisplay;
828+};
829+
830+//// DBusMenuProperties
831+/**
832+ * A map of properties for the dbus with easy accessors for
833+ * the common properties
834+ */
835+struct DBUSMENU_EXPORT DBusMenuProperties: public QVariantMap
836+{
837+ QString type() const;
838+ void setType(const QString&);
839+
840+ QString label() const;
841+ void setLabel(const QString&);
842+
843+ bool enabled() const;
844+ void setEnabled(bool);
845+
846+ bool visible() const;
847+ void setVisible(bool);
848+
849+ QString iconName() const;
850+ void setIconName(const QString&);
851+
852+ QByteArray iconData() const;
853+ void setIconData(const QByteArray&);
854+
855+ QKeySequence shortcut() const;
856+ void setShortcut(const QKeySequence&);
857+
858+ QString toggleType() const;
859+ void setToggleType(const QString&);
860+
861+ int toggleState() const;
862+ void setToggleState(int);
863+
864+ bool childrenDisplay() const;
865+ void setChildrenDisplay(bool);
866+
867+ DBusMenuProperties& operator=(const QVariantMap& rhs);
868+};
869+
870+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
871+
872+
873+#endif // DBUSMENUPROPERTY_H
874
875=== modified file 'src/dbusmenushortcut_p.cpp'
876--- src/dbusmenushortcut_p.cpp 2011-04-12 09:12:18 +0000
877+++ src/dbusmenushortcut_p.cpp 2015-03-18 11:19:06 +0000
878@@ -44,6 +44,8 @@
879 // cf https://bugs.launchpad.net/libdbusmenu-qt/+bug/712565
880 {"+", "plus"},
881 {"-", "minus"},
882+ {"+", "KP_Add"},
883+ {"-", "KP_Subtract"},
884 {0, 0}
885 };
886
887
888=== renamed file 'src/dbusmenutypes_p.cpp' => 'src/dbusmenutypes.cpp'
889--- src/dbusmenutypes_p.cpp 2011-02-23 13:23:56 +0000
890+++ src/dbusmenutypes.cpp 2015-03-18 11:19:06 +0000
891@@ -18,7 +18,7 @@
892 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
893 Boston, MA 02110-1301, USA.
894 */
895-#include "dbusmenutypes_p.h"
896+#include "dbusmenutypes.h"
897
898 // Local
899 #include <dbusmenushortcut_p.h>
900@@ -27,6 +27,18 @@
901 // Qt
902 #include <QDBusArgument>
903 #include <QDBusMetaType>
904+#include <QKeySequence>
905+
906+const char* DBusMenuProperty::Type = "type";
907+const char* DBusMenuProperty::Label = "label";
908+const char* DBusMenuProperty::Enabled = "enabled";
909+const char* DBusMenuProperty::Visible = "visible";
910+const char* DBusMenuProperty::IconName = "icon-name";
911+const char* DBusMenuProperty::IconData = "icon-data";
912+const char* DBusMenuProperty::Shortcut = "shortcut";
913+const char* DBusMenuProperty::ToggleType = "toggle-type";
914+const char* DBusMenuProperty::ToggleState = "toggle-state";
915+const char* DBusMenuProperty::ChildrenDisplay = "children-display";
916
917 //// DBusMenuItem
918 QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItem &obj)
919@@ -95,6 +107,16 @@
920 return argument;
921 }
922
923+bool operator==(const DBusMenuLayoutItem& lhs, const DBusMenuLayoutItem& rhs)
924+{
925+ return lhs.id == rhs.id && lhs.properties == rhs.properties && lhs.children == rhs.children;
926+}
927+
928+bool operator!=(const DBusMenuLayoutItem& lhs, const DBusMenuLayoutItem& rhs)
929+{
930+ return !(lhs == rhs);
931+}
932+
933 void DBusMenuTypes_register()
934 {
935 static bool registered = false;
936@@ -110,3 +132,122 @@
937 qDBusRegisterMetaType<DBusMenuShortcut>();
938 registered = true;
939 }
940+
941+QString DBusMenuProperties::type() const
942+{
943+ return value(DBusMenuProperty::Type, "standard").toString();
944+}
945+
946+void DBusMenuProperties::setType(const QString &type)
947+{
948+ insert(DBusMenuProperty::Type, type);
949+}
950+
951+QString DBusMenuProperties::label() const
952+{
953+ return value(DBusMenuProperty::Label, "").toString();
954+}
955+
956+void DBusMenuProperties::setLabel(const QString &label)
957+{
958+ insert(DBusMenuProperty::Label, label);
959+}
960+
961+bool DBusMenuProperties::enabled() const
962+{
963+ return value(DBusMenuProperty::Enabled, true).toBool();
964+}
965+
966+void DBusMenuProperties::setEnabled(bool enabled)
967+{
968+ insert(DBusMenuProperty::Enabled, enabled);
969+}
970+
971+bool DBusMenuProperties::visible() const
972+{
973+ return value(DBusMenuProperty::Visible, true).toBool();
974+}
975+
976+void DBusMenuProperties::setVisible(bool enabled)
977+{
978+ insert(DBusMenuProperty::Visible, enabled);
979+}
980+
981+QString DBusMenuProperties::iconName() const
982+{
983+ return value(DBusMenuProperty::IconName, "").toString();
984+}
985+
986+void DBusMenuProperties::setIconName(const QString &iconName)
987+{
988+ insert(DBusMenuProperty::IconName, iconName);
989+}
990+
991+QByteArray DBusMenuProperties::iconData() const
992+{
993+ return value(DBusMenuProperty::IconData, QVariant()).toByteArray();
994+}
995+
996+void DBusMenuProperties::setIconData(const QByteArray &iconData)
997+{
998+ insert(DBusMenuProperty::IconData, iconData);
999+}
1000+
1001+QKeySequence DBusMenuProperties::shortcut() const
1002+{
1003+ QKeySequence seq;
1004+
1005+ QVariant var = value(DBusMenuProperty::Shortcut, QVariant());
1006+
1007+ if (var.userType() == qMetaTypeId<QDBusArgument>()) {
1008+ QDBusArgument arg = var.value<QDBusArgument>();
1009+
1010+ DBusMenuShortcut shortcut;
1011+ arg >> shortcut;
1012+
1013+ return shortcut.toKeySequence();
1014+ }
1015+ return seq;
1016+}
1017+
1018+void DBusMenuProperties::setShortcut(const QKeySequence &keySequence)
1019+{
1020+ insert(DBusMenuProperty::Shortcut, keySequence);
1021+}
1022+
1023+QString DBusMenuProperties::toggleType() const
1024+{
1025+ return value(DBusMenuProperty::ToggleType, "").toString();
1026+}
1027+
1028+void DBusMenuProperties::setToggleType(const QString &toggleType)
1029+{
1030+ insert(DBusMenuProperty::ToggleType, toggleType);
1031+}
1032+
1033+int DBusMenuProperties::toggleState() const
1034+{
1035+ return value(DBusMenuProperty::ToggleState, -1).toInt();
1036+}
1037+
1038+void DBusMenuProperties::setToggleState(int toggleType)
1039+{
1040+ insert(DBusMenuProperty::ToggleState, toggleType);
1041+}
1042+
1043+bool DBusMenuProperties::childrenDisplay() const
1044+{
1045+ return value(DBusMenuProperty::ChildrenDisplay, false).toBool();
1046+}
1047+
1048+void DBusMenuProperties::setChildrenDisplay(bool childrenDisplay)
1049+{
1050+ insert(DBusMenuProperty::ChildrenDisplay, childrenDisplay);
1051+
1052+}
1053+
1054+DBusMenuProperties &DBusMenuProperties::operator=(const QVariantMap &rhs)
1055+{
1056+ QVariantMap::operator=(rhs);
1057+ return *this;
1058+}
1059
1060=== renamed file 'src/dbusmenutypes_p.h' => 'src/dbusmenutypes.h'
1061--- src/dbusmenutypes_p.h 2011-02-23 13:23:56 +0000
1062+++ src/dbusmenutypes.h 2015-03-18 11:19:06 +0000
1063@@ -18,8 +18,8 @@
1064 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1065 Boston, MA 02110-1301, USA.
1066 */
1067-#ifndef DBUSMENUTYPES_P_H
1068-#define DBUSMENUTYPES_P_H
1069+#ifndef DBUSMENUTYPES_H
1070+#define DBUSMENUTYPES_H
1071
1072 // Qt
1073 #include <QtCore/QList>
1074@@ -28,6 +28,7 @@
1075
1076 // Local
1077 #include <dbusmenu_export.h>
1078+#include <dbusmenuproperty.h>
1079
1080 class QDBusArgument;
1081
1082@@ -37,8 +38,11 @@
1083 */
1084 struct DBUSMENU_EXPORT DBusMenuItem
1085 {
1086+ /// Id of the menu item
1087 int id;
1088- QVariantMap properties;
1089+
1090+ /// Properties for the menu item
1091+ DBusMenuProperties properties;
1092 };
1093
1094 Q_DECLARE_METATYPE(DBusMenuItem)
1095@@ -57,7 +61,10 @@
1096 */
1097 struct DBUSMENU_EXPORT DBusMenuItemKeys
1098 {
1099+ /// Id of the menu item
1100 int id;
1101+
1102+ /// Properties for the menu item
1103 QStringList properties;
1104 };
1105
1106@@ -75,11 +82,15 @@
1107 * Represents an item with its children. GetLayout() returns a
1108 * DBusMenuLayoutItemList.
1109 */
1110-struct DBusMenuLayoutItem;
1111 struct DBUSMENU_EXPORT DBusMenuLayoutItem
1112 {
1113+ /// Id of the menu item
1114 int id;
1115- QVariantMap properties;
1116+
1117+ /// Id of the menu item
1118+ DBusMenuProperties properties;
1119+
1120+ /// Children of the menu item
1121 QList<DBusMenuLayoutItem> children;
1122 };
1123
1124@@ -88,9 +99,13 @@
1125 DBUSMENU_EXPORT QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuLayoutItem &);
1126 DBUSMENU_EXPORT const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuLayoutItem &);
1127
1128+DBUSMENU_EXPORT bool operator==(const DBusMenuLayoutItem& lhs, const DBusMenuLayoutItem& rhs);
1129+DBUSMENU_EXPORT bool operator!=(const DBusMenuLayoutItem& lhs, const DBusMenuLayoutItem& rhs);
1130+
1131 typedef QList<DBusMenuLayoutItem> DBusMenuLayoutItemList;
1132
1133 Q_DECLARE_METATYPE(DBusMenuLayoutItemList)
1134
1135 void DBusMenuTypes_register();
1136+
1137 #endif /* DBUSMENUTYPES_P_H */
1138
1139=== added directory 'src/qpa'
1140=== added file 'src/qpa/exportedplatformmenubar.cpp'
1141--- src/qpa/exportedplatformmenubar.cpp 1970-01-01 00:00:00 +0000
1142+++ src/qpa/exportedplatformmenubar.cpp 2015-03-18 11:19:06 +0000
1143@@ -0,0 +1,377 @@
1144+/* This file is part of the dbusmenu-qt library
1145+ Copyright 2015 Canonical
1146+ Author: Nick Dedekind <nick.dedekind@canonical.com>
1147+
1148+ This library is free software; you can redistribute it and/or
1149+ modify it under the terms of the GNU Library General Public
1150+ License (LGPL) as published by the Free Software Foundation;
1151+ either version 2 of the License, or (at your option) any later
1152+ version.
1153+
1154+ This library is distributed in the hope that it will be useful,
1155+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1156+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1157+ Library General Public License for more details.
1158+
1159+ You should have received a copy of the GNU Library General Public License
1160+ along with this library; see the file COPYING.LIB. If not, write to
1161+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1162+ Boston, MA 02110-1301, USA.
1163+*/
1164+
1165+// Local
1166+#include "exportedplatformmenubar.h"
1167+#include "exportedplatformmenubar_p.h"
1168+#include "qpadbusmenuexporter_p.h"
1169+#include "logging_p.h"
1170+
1171+// Qt
1172+#include <QWindow>
1173+#include <QWidget>
1174+
1175+#define MENU_ID(x) (qobject_cast<ExportedPlatformMenu*>(x) ? qobject_cast<ExportedPlatformMenu*>(x)->id() : -1)
1176+#define MENU_ITEM_ID(x) (qobject_cast<ExportedPlatformMenuItem*>(x) ? qobject_cast<ExportedPlatformMenuItem*>(x)->id() : -1)
1177+
1178+ExportedPlatformMenuBar::ExportedPlatformMenuBar(const QString& exportPath)
1179+ : d(new ExportedPlatformMenuBarPrivate)
1180+{
1181+ LOG;
1182+
1183+ d->m_objectPath = exportPath;
1184+ new QPADBusMenuExporter(exportPath, this);
1185+}
1186+
1187+ExportedPlatformMenuBar::~ExportedPlatformMenuBar()
1188+{
1189+ LOG;
1190+}
1191+
1192+QString ExportedPlatformMenuBar::exportedPath() const
1193+{
1194+ return d->m_objectPath;
1195+}
1196+
1197+void
1198+ExportedPlatformMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *before)
1199+{
1200+ LOG << MENU_ID(menu) << " before:" << before;
1201+
1202+ if (!before) {
1203+ d->m_menus.push_back(menu);
1204+ } else {
1205+ for (auto iter = d->m_menus.begin(); iter != d->m_menus.end(); ++iter) {
1206+ if (*iter == before) {
1207+ d->m_menus.insert(iter, menu);
1208+ break;
1209+ }
1210+ }
1211+ }
1212+
1213+ Q_EMIT menuInserted(menu);
1214+}
1215+
1216+void
1217+ExportedPlatformMenuBar::removeMenu(QPlatformMenu *menu)
1218+{
1219+ LOG << menu;
1220+
1221+ for (auto iter = d->m_menus.begin(); iter != d->m_menus.end(); ++iter) {
1222+ if (*iter == menu) {
1223+ iter = d->m_menus.erase(iter);
1224+ }
1225+ }
1226+
1227+ Q_EMIT menuRemoved(menu);
1228+}
1229+
1230+void
1231+ExportedPlatformMenuBar::syncMenu(QPlatformMenu *menu)
1232+{
1233+ LOG_VAR(menu);
1234+ QMetaObject::invokeMethod(menu, "propertyUpdated");
1235+}
1236+
1237+void
1238+ExportedPlatformMenuBar::handleReparent(QWindow *newParentWindow)
1239+{
1240+ LOG_VAR(newParentWindow);
1241+}
1242+
1243+QPlatformMenu *
1244+ExportedPlatformMenuBar::menuForTag(quintptr tag) const
1245+{
1246+ for (auto iter = d->m_menus.begin(); iter != d->m_menus.end(); ++iter) {
1247+ if ((*iter)->tag() == tag) {
1248+ return *iter;
1249+ }
1250+ }
1251+ return nullptr;
1252+}
1253+
1254+QPlatformMenu *
1255+ExportedPlatformMenuBar::menuAt(int position) const
1256+{
1257+ if (position < 0 || position >= d->m_menus.count()) return nullptr;
1258+ return d->m_menus.at(position);
1259+}
1260+
1261+uint ExportedPlatformMenuBar::menuCount()
1262+{
1263+ return d->m_menus.count();
1264+}
1265+
1266+//////////////////////////////////////////////////////////////
1267+
1268+ExportedPlatformMenu::ExportedPlatformMenu()
1269+ : QPlatformMenu()
1270+ , d(new ExportedPlatformMenuPrivate)
1271+{
1272+ LOG << id();
1273+}
1274+
1275+ExportedPlatformMenu::~ExportedPlatformMenu()
1276+{
1277+ LOG << id();
1278+}
1279+
1280+void ExportedPlatformMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
1281+{
1282+ LOG << MENU_ITEM_ID(menuItem) << " before:" << before << " on: " << id();
1283+
1284+ if (!before) {
1285+ d->m_menuItems.push_back(menuItem);
1286+ } else {
1287+ for (auto iter = d->m_menuItems.begin(); iter != d->m_menuItems.end(); ++iter) {
1288+ if (*iter == before) {
1289+ d->m_menuItems.insert(iter, menuItem);
1290+ break;
1291+ }
1292+ }
1293+ }
1294+
1295+ Q_EMIT menuItemInserted(menuItem);
1296+}
1297+
1298+void ExportedPlatformMenu::removeMenuItem(QPlatformMenuItem *menuItem)
1299+{
1300+ LOG_VAR(menuItem) << " on: " << id();
1301+
1302+ QMutableListIterator<QPlatformMenuItem*> iter(d->m_menuItems);
1303+ while (iter.hasNext()) {
1304+ if (iter.next() == menuItem) {
1305+ iter.remove();
1306+ }
1307+ }
1308+
1309+ Q_EMIT menuItemRemoved(menuItem);
1310+}
1311+
1312+void ExportedPlatformMenu::syncMenuItem(QPlatformMenuItem *menuItem)
1313+{
1314+ LOG_VAR(menuItem) << " from: " << id();
1315+ QMetaObject::invokeMethod(menuItem, "propertyUpdated");
1316+}
1317+
1318+void ExportedPlatformMenu::syncSeparatorsCollapsible(bool enable)
1319+{
1320+ LOG_VAR(enable) << " on: " << id();
1321+ Q_EMIT propertyUpdated();
1322+}
1323+
1324+void ExportedPlatformMenu::setTag(quintptr tag)
1325+{
1326+ LOG_VAR(tag) << " on: " << id();
1327+ d->m_tag = tag;
1328+}
1329+
1330+quintptr ExportedPlatformMenu::tag() const
1331+{
1332+ return d->m_tag;
1333+}
1334+
1335+void ExportedPlatformMenu::setText(const QString &text)
1336+{
1337+ LOG_VAR(text) << " on: " << id();
1338+ ExportedPlatformMenuPrivate::set_text(this, text);
1339+ Q_EMIT propertyUpdated();
1340+}
1341+
1342+void ExportedPlatformMenu::setIcon(const QIcon &icon)
1343+{
1344+ LOG_VAR(icon) << " on: " << id();
1345+ ExportedPlatformMenuPrivate::set_icon(this, icon);
1346+ Q_EMIT propertyUpdated();
1347+}
1348+
1349+void ExportedPlatformMenu::setEnabled(bool isEnabled)
1350+{
1351+ LOG_VAR(isEnabled) << " on: " << id();
1352+ ExportedPlatformMenuPrivate::set_enabled(this, isEnabled);
1353+ Q_EMIT propertyUpdated();
1354+}
1355+
1356+void ExportedPlatformMenu::setVisible(bool isVisible)
1357+{
1358+ LOG_VAR(isVisible) << " on: " << id();
1359+ ExportedPlatformMenuPrivate::set_visible(this, isVisible);
1360+ Q_EMIT propertyUpdated();
1361+}
1362+
1363+void ExportedPlatformMenu::setMinimumWidth(int width)
1364+{
1365+ LOG_VAR(width) << " on: " << id();
1366+ Q_EMIT propertyUpdated();
1367+}
1368+
1369+void ExportedPlatformMenu::setFont(const QFont &font)
1370+{
1371+ LOG_VAR(font) << " on: " << id();
1372+ Q_EMIT propertyUpdated();
1373+}
1374+
1375+QPlatformMenuItem *ExportedPlatformMenu::menuItemAt(int position) const
1376+{
1377+ if (position < 0 || position >= d->m_menuItems.count()) return nullptr;
1378+ return d->m_menuItems.at(position);
1379+}
1380+
1381+QPlatformMenuItem *ExportedPlatformMenu::menuItemForTag(quintptr tag) const
1382+{
1383+ for (auto iter = d->m_menuItems.begin(); iter != d->m_menuItems.end(); ++iter) {
1384+ if ((*iter)->tag() == tag) {
1385+ return *iter;
1386+ }
1387+ }
1388+ return nullptr;
1389+}
1390+
1391+uint ExportedPlatformMenu::menuItemCount()
1392+{
1393+ return d->m_menuItems.count();
1394+}
1395+
1396+QPlatformMenuItem *ExportedPlatformMenu::createMenuItem() const
1397+{
1398+ return new ExportedPlatformMenuItem();
1399+}
1400+
1401+int ExportedPlatformMenu::id() const
1402+{
1403+ return d->m_id;
1404+}
1405+
1406+//////////////////////////////////////////////////////////////
1407+
1408+ExportedPlatformMenuItem::ExportedPlatformMenuItem()
1409+ : d(new ExportedPlatformMenuItemPrivate)
1410+{
1411+ LOG << id();
1412+}
1413+
1414+ExportedPlatformMenuItem::~ExportedPlatformMenuItem()
1415+{
1416+ LOG << id();
1417+}
1418+
1419+void ExportedPlatformMenuItem::setTag(quintptr tag)
1420+{
1421+ LOG_VAR(tag) << " on: " << id();
1422+ d->m_tag = tag;
1423+}
1424+
1425+quintptr ExportedPlatformMenuItem::tag() const
1426+{
1427+ return d->m_tag;
1428+}
1429+
1430+void ExportedPlatformMenuItem::setText(const QString &text)
1431+{
1432+ LOG_VAR(text) << " on: " << id();
1433+ ExportedPlatformMenuItemPrivate::set_text(this, text);
1434+ Q_EMIT propertyUpdated();
1435+}
1436+
1437+void ExportedPlatformMenuItem::setIcon(const QIcon &icon)
1438+{
1439+ LOG_VAR(icon) << " on: " << id();
1440+ ExportedPlatformMenuItemPrivate::set_icon(this, icon);
1441+ Q_EMIT propertyUpdated();
1442+}
1443+
1444+void ExportedPlatformMenuItem::setMenu(QPlatformMenu *menu)
1445+{
1446+ LOG << MENU_ID(menu) << " on: " << id();
1447+ d->m_menu = menu;
1448+ Q_EMIT propertyUpdated();
1449+}
1450+
1451+void ExportedPlatformMenuItem::setVisible(bool isVisible)
1452+{
1453+ LOG_VAR(isVisible) << " on: " << id();
1454+ ExportedPlatformMenuItemPrivate::set_visible(this, isVisible);
1455+ Q_EMIT propertyUpdated();
1456+}
1457+
1458+void ExportedPlatformMenuItem::setIsSeparator(bool isSeparator)
1459+{
1460+ LOG_VAR(isSeparator) << " on: " << id();
1461+ ExportedPlatformMenuItemPrivate::set_separator(this, isSeparator);
1462+ Q_EMIT propertyUpdated();
1463+}
1464+
1465+void ExportedPlatformMenuItem::setFont(const QFont &font)
1466+{
1467+ LOG_VAR(font) << " on: " << id();
1468+ Q_EMIT propertyUpdated();
1469+}
1470+
1471+void ExportedPlatformMenuItem::setRole(QPlatformMenuItem::MenuRole role)
1472+{
1473+ LOG_VAR(role) << " on: " << id();
1474+ Q_EMIT propertyUpdated();
1475+}
1476+
1477+void ExportedPlatformMenuItem::setCheckable(bool checkable)
1478+{
1479+ LOG_VAR(checkable) << " on: " << id();
1480+ ExportedPlatformMenuItemPrivate::set_checkable(this, checkable);
1481+ Q_EMIT propertyUpdated();
1482+}
1483+
1484+void ExportedPlatformMenuItem::setChecked(bool isChecked)
1485+{
1486+ LOG_VAR(isChecked) << " on: " << id();
1487+ ExportedPlatformMenuItemPrivate::set_checked(this, isChecked);
1488+ Q_EMIT propertyUpdated();
1489+}
1490+
1491+void ExportedPlatformMenuItem::setShortcut(const QKeySequence &shortcut)
1492+{
1493+ LOG_VAR(shortcut) << " on: " << id();
1494+ ExportedPlatformMenuItemPrivate::set_shortcut(this, shortcut);
1495+ Q_EMIT propertyUpdated();
1496+}
1497+
1498+void ExportedPlatformMenuItem::setEnabled(bool enabled)
1499+{
1500+ LOG_VAR(enabled) << " on: " << id();
1501+ ExportedPlatformMenuItemPrivate::set_enabled(this, enabled);
1502+ Q_EMIT propertyUpdated();
1503+}
1504+
1505+void ExportedPlatformMenuItem::setIconSize(int size)
1506+{
1507+ LOG_VAR(size) << " on: " << id();
1508+ ExportedPlatformMenuItemPrivate::set_iconSize(this, size);
1509+ Q_EMIT propertyUpdated();
1510+}
1511+
1512+int ExportedPlatformMenuItem::id() const
1513+{
1514+ return d->m_id;
1515+}
1516+
1517+QPlatformMenu *ExportedPlatformMenuItem::menu() const
1518+{
1519+ return d->m_menu;
1520+}
1521
1522=== added file 'src/qpa/exportedplatformmenubar.h'
1523--- src/qpa/exportedplatformmenubar.h 1970-01-01 00:00:00 +0000
1524+++ src/qpa/exportedplatformmenubar.h 2015-03-18 11:19:06 +0000
1525@@ -0,0 +1,136 @@
1526+/* This file is part of the dbusmenu-qt library
1527+ Copyright 2015 Canonical
1528+ Author: Nick Dedekind <nick.dedekind@canonical.com>
1529+
1530+ This library is free software; you can redistribute it and/or
1531+ modify it under the terms of the GNU Library General Public
1532+ License (LGPL) as published by the Free Software Foundation;
1533+ either version 2 of the License, or (at your option) any later
1534+ version.
1535+
1536+ This library is distributed in the hope that it will be useful,
1537+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1538+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1539+ Library General Public License for more details.
1540+
1541+ You should have received a copy of the GNU Library General Public License
1542+ along with this library; see the file COPYING.LIB. If not, write to
1543+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1544+ Boston, MA 02110-1301, USA.
1545+*/
1546+#ifndef EXPORTEDPLATFORMMENUBAR_H
1547+#define EXPORTEDPLATFORMMENUBAR_H
1548+
1549+#include <qpa/qplatformmenu.h>
1550+class ExportedPlatformMenuBarPrivate;
1551+class ExportedPlatformMenuPrivate;
1552+class ExportedPlatformMenuItemPrivate;
1553+class ExportedPlatformMenu;
1554+class ExportedPlatformMenuItem;
1555+
1556+// Local
1557+#include <dbusmenu_export.h>
1558+
1559+class DBUSMENU_EXPORT ExportedPlatformMenuBar : public QPlatformMenuBar
1560+{
1561+ Q_OBJECT
1562+public:
1563+ ExportedPlatformMenuBar(const QString& exportPath);
1564+ ~ExportedPlatformMenuBar();
1565+
1566+ QString exportedPath() const;
1567+
1568+ virtual void insertMenu(QPlatformMenu *menu, QPlatformMenu* before) override;
1569+ virtual void removeMenu(QPlatformMenu *menu) override;
1570+ virtual void syncMenu(QPlatformMenu *menuItem) override;
1571+ virtual void handleReparent(QWindow *newParentWindow) override;
1572+ virtual QPlatformMenu *menuForTag(quintptr tag) const override;
1573+
1574+ QPlatformMenu *menuAt(int position) const;
1575+ uint menuCount();
1576+
1577+Q_SIGNALS:
1578+ void menuInserted(QPlatformMenu *menu);
1579+ void menuRemoved(QPlatformMenu *menu);
1580+
1581+private:
1582+ ExportedPlatformMenuBarPrivate *const d;
1583+ friend class ExportedPlatformMenuBarPrivate;
1584+};
1585+
1586+class DBUSMENU_EXPORT ExportedPlatformMenu : public QPlatformMenu
1587+{
1588+ Q_OBJECT
1589+public:
1590+ ExportedPlatformMenu();
1591+ ~ExportedPlatformMenu();
1592+
1593+ virtual void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) override;
1594+ virtual void removeMenuItem(QPlatformMenuItem *menuItem) override;
1595+ virtual void syncMenuItem(QPlatformMenuItem *menuItem) override;
1596+ virtual void syncSeparatorsCollapsible(bool enable) override;
1597+
1598+ virtual void setTag(quintptr tag) override;
1599+ virtual quintptr tag() const override;
1600+
1601+ virtual void setText(const QString &text) override;
1602+ virtual void setIcon(const QIcon &icon) override;
1603+ virtual void setEnabled(bool isEnabled) override;
1604+ virtual void setVisible(bool isVisible) override;
1605+ virtual void setMinimumWidth(int width) override;
1606+ virtual void setFont(const QFont &font) override;
1607+
1608+ virtual QPlatformMenuItem *menuItemAt(int position) const override;
1609+ virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const override;
1610+ uint menuItemCount();
1611+
1612+ virtual QPlatformMenuItem *createMenuItem() const override;
1613+
1614+ int id() const;
1615+
1616+Q_SIGNALS:
1617+ void menuItemInserted(QPlatformMenuItem *menuItem);
1618+ void menuItemRemoved(QPlatformMenuItem *menuItem);
1619+
1620+ void propertyUpdated();
1621+
1622+private:
1623+ ExportedPlatformMenuPrivate *const d;
1624+ friend class ExportedPlatformMenuPrivate;
1625+};
1626+
1627+
1628+class DBUSMENU_EXPORT ExportedPlatformMenuItem : public QPlatformMenuItem
1629+{
1630+ Q_OBJECT
1631+public:
1632+ ExportedPlatformMenuItem();
1633+ ~ExportedPlatformMenuItem();
1634+
1635+ virtual void setTag(quintptr tag) override;
1636+ virtual quintptr tag() const override;
1637+
1638+ virtual void setText(const QString &text) override;
1639+ virtual void setIcon(const QIcon &icon) override;
1640+ virtual void setMenu(QPlatformMenu *menu) override;
1641+ virtual void setVisible(bool isVisible) override;
1642+ virtual void setIsSeparator(bool isSeparator) override;
1643+ virtual void setFont(const QFont &font) override;
1644+ virtual void setRole(MenuRole role) override;
1645+ virtual void setCheckable(bool checkable) override;
1646+ virtual void setChecked(bool isChecked) override;
1647+ virtual void setShortcut(const QKeySequence& shortcut) override;
1648+ virtual void setEnabled(bool enabled) override;
1649+ virtual void setIconSize(int size) override;
1650+
1651+ int id() const;
1652+ QPlatformMenu* menu() const;
1653+
1654+Q_SIGNALS:
1655+ void propertyUpdated();
1656+
1657+private:
1658+ ExportedPlatformMenuItemPrivate *const d;
1659+ friend class ExportedPlatformMenuItemPrivate;
1660+};
1661+#endif // EXPORTEDPLATFORMMENUBAR_H
1662
1663=== added file 'src/qpa/exportedplatformmenubar_p.cpp'
1664--- src/qpa/exportedplatformmenubar_p.cpp 1970-01-01 00:00:00 +0000
1665+++ src/qpa/exportedplatformmenubar_p.cpp 2015-03-18 11:19:06 +0000
1666@@ -0,0 +1,129 @@
1667+/* This file is part of the dbusmenu-qt library
1668+ Copyright 2015 Canonical
1669+ Author: Nick Dedekind <nick.dedekind@canonical.com>
1670+
1671+ This library is free software; you can redistribute it and/or
1672+ modify it under the terms of the GNU Library General Public
1673+ License (LGPL) as published by the Free Software Foundation;
1674+ either version 2 of the License, or (at your option) any later
1675+ version.
1676+
1677+ This library is distributed in the hope that it will be useful,
1678+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1679+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1680+ Library General Public License for more details.
1681+
1682+ You should have received a copy of the GNU Library General Public License
1683+ along with this library; see the file COPYING.LIB. If not, write to
1684+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1685+ Boston, MA 02110-1301, USA.
1686+*/
1687+
1688+// Local
1689+#include "exportedplatformmenubar_p.h"
1690+#include "dbusmenushortcut_p.h"
1691+#include "debug_p.h"
1692+#include "utils_p.h"
1693+
1694+// Qt
1695+#include <QBuffer>
1696+
1697+int nextMenuId = 1;
1698+
1699+void insertIconProperty(QVariantMap *map, const QIcon& icon)
1700+{
1701+ // provide the icon name for per-theme lookups
1702+ const QString iconName = icon.name();
1703+ if (!iconName.isEmpty()) {
1704+ map->insert(DBusMenuProperty::IconName, iconName);
1705+ }
1706+
1707+ if (!icon.isNull()) {
1708+ QBuffer buffer;
1709+ icon.pixmap(16).save(&buffer, "PNG");
1710+ map->insert(DBusMenuProperty::IconData, buffer.data());
1711+ }
1712+}
1713+
1714+ExportedPlatformMenuBarPrivate::ExportedPlatformMenuBarPrivate()
1715+{
1716+}
1717+
1718+//////////////////////////////////////////////////////
1719+
1720+ExportedPlatformMenuPrivate::ExportedPlatformMenuPrivate()
1721+ : m_tag(0)
1722+ , m_id(nextMenuId++)
1723+{
1724+
1725+}
1726+
1727+QVariantMap ExportedPlatformMenuPrivate::propertiesForMenu(const ExportedPlatformMenu *menu)
1728+{
1729+ QVariantMap map;
1730+ map.insert(DBusMenuProperty::ChildrenDisplay, "submenu");
1731+ map.insert(DBusMenuProperty::Label, Utils::swapMnemonicChar(ExportedPlatformMenuPrivate::get_text(menu), '&', '_'));
1732+ if (!ExportedPlatformMenuPrivate::get_enabled(menu)) {
1733+ map.insert(DBusMenuProperty::Enabled, false);
1734+ }
1735+ if (!ExportedPlatformMenuPrivate::get_visible(menu)) {
1736+ map.insert(DBusMenuProperty::Visible, false);
1737+ }
1738+ insertIconProperty(&map, ExportedPlatformMenuPrivate::get_icon(menu));
1739+ return map;
1740+}
1741+
1742+//////////////////////////////////////////////////////
1743+
1744+ExportedPlatformMenuItemPrivate::ExportedPlatformMenuItemPrivate()
1745+ : m_id(nextMenuId++)
1746+ , m_menu(nullptr)
1747+{
1748+}
1749+
1750+QVariantMap ExportedPlatformMenuItemPrivate::propertiesForMenuItem(const ExportedPlatformMenuItem *menuItem)
1751+{
1752+ DMRETURN_VALUE_IF_FAIL(menuItem, QVariantMap());
1753+
1754+ if (ExportedPlatformMenuItemPrivate::get_separator(menuItem)) {
1755+ return propertiesForSeparatorMenuItem(menuItem);
1756+ } else {
1757+ return propertiesForStandardMenuItem(menuItem);
1758+ }
1759+}
1760+
1761+QVariantMap ExportedPlatformMenuItemPrivate::propertiesForSeparatorMenuItem(const ExportedPlatformMenuItem *menuItem)
1762+{
1763+ QVariantMap map;
1764+ map.insert(DBusMenuProperty::Type, "separator");
1765+ if (!ExportedPlatformMenuItemPrivate::get_visible(menuItem)) {
1766+ map.insert(DBusMenuProperty::Visible, false);
1767+ }
1768+ return map;
1769+}
1770+
1771+QVariantMap ExportedPlatformMenuItemPrivate::propertiesForStandardMenuItem(const ExportedPlatformMenuItem *menuItem)
1772+{
1773+ QVariantMap map;
1774+ map.insert(DBusMenuProperty::Label, Utils::swapMnemonicChar(ExportedPlatformMenuItemPrivate::get_text(menuItem), '&', '_'));
1775+ if (!ExportedPlatformMenuItemPrivate::get_enabled(menuItem)) {
1776+ map.insert(DBusMenuProperty::Enabled, false);
1777+ }
1778+ if (!ExportedPlatformMenuItemPrivate::get_visible(menuItem)) {
1779+ map.insert(DBusMenuProperty::Visible, false);
1780+ }
1781+ if (ExportedPlatformMenuItemPrivate::get_checkable(menuItem)) {
1782+ map.insert(DBusMenuProperty::ToggleType, "checkmark");
1783+ map.insert(DBusMenuProperty::ToggleState, ExportedPlatformMenuItemPrivate::get_checked(menuItem) ? 1 : 0);
1784+ }
1785+ if (menuItem->menu()) {
1786+ map.insert(DBusMenuProperty::ChildrenDisplay, "submenu");
1787+ }
1788+ insertIconProperty(&map, ExportedPlatformMenuItemPrivate::get_icon(menuItem));
1789+ QKeySequence keySequence = get_shortcut(menuItem);
1790+ if (!keySequence.isEmpty()) {
1791+ DBusMenuShortcut shortcut = DBusMenuShortcut::fromKeySequence(keySequence);
1792+ map.insert(DBusMenuProperty::Shortcut, QVariant::fromValue(shortcut));
1793+ }
1794+ return map;
1795+}
1796
1797=== added file 'src/qpa/exportedplatformmenubar_p.h'
1798--- src/qpa/exportedplatformmenubar_p.h 1970-01-01 00:00:00 +0000
1799+++ src/qpa/exportedplatformmenubar_p.h 2015-03-18 11:19:06 +0000
1800@@ -0,0 +1,111 @@
1801+/* This file is part of the dbusmenu-qt library
1802+ Copyright 2015 Canonical
1803+ Author: Nick Dedekind <nick.dedekind@canonical.com>
1804+
1805+ This library is free software; you can redistribute it and/or
1806+ modify it under the terms of the GNU Library General Public
1807+ License (LGPL) as published by the Free Software Foundation;
1808+ either version 2 of the License, or (at your option) any later
1809+ version.
1810+
1811+ This library is distributed in the hope that it will be useful,
1812+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1813+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1814+ Library General Public License for more details.
1815+
1816+ You should have received a copy of the GNU Library General Public License
1817+ along with this library; see the file COPYING.LIB. If not, write to
1818+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1819+ Boston, MA 02110-1301, USA.
1820+*/
1821+#ifndef EXPORTEDPLATFORMMENUBAR_P_H
1822+#define EXPORTEDPLATFORMMENUBAR_P_H
1823+
1824+// Qt
1825+#include <QtCore/QObject>
1826+#include <QtDBus/QDBusConnection>
1827+#include <qpa/qplatformmenu.h>
1828+
1829+// Local
1830+#include "dbusmenuexporterdbusinterface_p.h"
1831+#include "exportedplatformmenubar.h"
1832+
1833+class QAction;
1834+class QMenu;
1835+
1836+class ExportedPlatformMenuBar;
1837+class ExportedPlatformMenu;
1838+class ExportedPlatformMenuItem;
1839+class QPADBusMenuExporter;
1840+
1841+/**
1842+ * A QPADBusMenuExporter instance can serialize a qua menu over DBus
1843+ */
1844+class ExportedPlatformMenuBarPrivate
1845+{
1846+public:
1847+ ExportedPlatformMenuBarPrivate();
1848+
1849+ QString m_objectPath;
1850+ QList<QPlatformMenu*> m_menus;
1851+};
1852+
1853+class ExportedPlatformMenuPrivate
1854+{
1855+public:
1856+ ExportedPlatformMenuPrivate();
1857+
1858+ static QVariantMap propertiesForMenu(const ExportedPlatformMenu *menu);
1859+
1860+#define STATIC_PROPERTY(name, type, defaultValue) \
1861+ type m_##name = defaultValue; \
1862+ static type get_##name(const ExportedPlatformMenu *menu) { return menu->d->m_##name; } \
1863+ static void set_##name(ExportedPlatformMenu *menu, const type& value) { menu->d->m_##name = value; }
1864+
1865+ STATIC_PROPERTY(text, QString, QString())
1866+ STATIC_PROPERTY(visible, bool, true)
1867+ STATIC_PROPERTY(enabled, bool, true)
1868+ STATIC_PROPERTY(icon, QIcon, QIcon())
1869+#undef STATIC_PROPERTY
1870+
1871+ ExportedPlatformMenu* m_menu;
1872+ QList<QPlatformMenu*> m_menus;
1873+ QList<QPlatformMenuItem*> m_menuItems;
1874+ quintptr m_tag;
1875+ int m_id;
1876+};
1877+
1878+class ExportedPlatformMenuItemPrivate
1879+{
1880+public:
1881+ ExportedPlatformMenuItemPrivate();
1882+
1883+ static QVariantMap propertiesForMenuItem(const ExportedPlatformMenuItem *menuItem);
1884+ static QVariantMap propertiesForSeparatorMenuItem(const ExportedPlatformMenuItem *menuItem);
1885+ static QVariantMap propertiesForStandardMenuItem(const ExportedPlatformMenuItem *menuItem);
1886+
1887+#define STATIC_PROPERTY(name, type, defaultValue) \
1888+ type m_##name = defaultValue; \
1889+ static type get_##name(const ExportedPlatformMenuItem *menuItem) { return menuItem->d->m_##name; } \
1890+ static void set_##name(ExportedPlatformMenuItem *menuItem, const type& value) { menuItem->d->m_##name = value; }
1891+
1892+ STATIC_PROPERTY(separator, bool, false)
1893+ STATIC_PROPERTY(visible, bool, true)
1894+ STATIC_PROPERTY(text, QString, QString())
1895+ STATIC_PROPERTY(enabled, bool, true)
1896+ STATIC_PROPERTY(checkable, bool, false)
1897+ STATIC_PROPERTY(checked, bool, false)
1898+ STATIC_PROPERTY(shortcut, QKeySequence, QKeySequence())
1899+ STATIC_PROPERTY(icon, QIcon, QIcon())
1900+ STATIC_PROPERTY(iconSize, int, 16)
1901+#undef STATIC_PROPERTY
1902+
1903+ ExportedPlatformMenuItem* m_menuItem;
1904+ quintptr m_tag;
1905+ int m_id;
1906+ QPlatformMenu* m_menu;
1907+};
1908+
1909+extern int nextMenuId;
1910+
1911+#endif // EXPORTEDPLATFORMMENUBAR_P_H
1912
1913=== added file 'src/qpa/logging_p.h'
1914--- src/qpa/logging_p.h 1970-01-01 00:00:00 +0000
1915+++ src/qpa/logging_p.h 2015-03-18 11:19:06 +0000
1916@@ -0,0 +1,38 @@
1917+/* This file is part of the dbusmenu-qt library
1918+ Copyright 2015 Canonical
1919+ Author: Nick Dedekind <nick.dedekind@canonical.com>
1920+
1921+ This library is free software; you can redistribute it and/or
1922+ modify it under the terms of the GNU Library General Public
1923+ License (LGPL) as published by the Free Software Foundation;
1924+ either version 2 of the License, or (at your option) any later
1925+ version.
1926+
1927+ This library is distributed in the hope that it will be useful,
1928+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1929+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1930+ Library General Public License for more details.
1931+
1932+ You should have received a copy of the GNU Library General Public License
1933+ along with this library; see the file COPYING.LIB. If not, write to
1934+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1935+ Boston, MA 02110-1301, USA.
1936+*/
1937+#ifndef LOGGING_H
1938+#define LOGGING_H
1939+
1940+#include <QDebug>
1941+
1942+//#define ENABLE_DEBUG_LOGGING
1943+
1944+#ifdef ENABLE_DEBUG_LOGGING
1945+#define LOG qDebug() << __PRETTY_FUNCTION__
1946+#define LOG_VAR(x) qDebug() << __PRETTY_FUNCTION__<< #x ":" << x
1947+#else
1948+#define LOG QNoDebug()
1949+#define LOG_VAR(x) QNoDebug() << __PRETTY_FUNCTION__<< #x ":" << x
1950+#endif
1951+
1952+#define WARN qWarning() << __PRETTY_FUNCTION__
1953+
1954+#endif // LOGGING_H
1955
1956=== added file 'src/qpa/qpadbusmenuexporter_p.cpp'
1957--- src/qpa/qpadbusmenuexporter_p.cpp 1970-01-01 00:00:00 +0000
1958+++ src/qpa/qpadbusmenuexporter_p.cpp 2015-03-18 11:19:06 +0000
1959@@ -0,0 +1,357 @@
1960+/* This file is part of the dbusmenu-qt library
1961+ Copyright 2015 Canonical
1962+ Author: Nick Dedekind <nick.dedekind@canonical.com>
1963+
1964+ This library is free software; you can redistribute it and/or
1965+ modify it under the terms of the GNU Library General Public
1966+ License (LGPL) as published by the Free Software Foundation;
1967+ either version 2 of the License, or (at your option) any later
1968+ version.
1969+
1970+ This library is distributed in the hope that it will be useful,
1971+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1972+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1973+ Library General Public License for more details.
1974+
1975+ You should have received a copy of the GNU Library General Public License
1976+ along with this library; see the file COPYING.LIB. If not, write to
1977+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1978+ Boston, MA 02110-1301, USA.
1979+*/
1980+
1981+// Local
1982+#include "qpadbusmenuexporter_p.h"
1983+#include "exportedplatformmenubar.h"
1984+#include "exportedplatformmenubar_p.h"
1985+#include "utils_p.h"
1986+#include "logging_p.h"
1987+
1988+// Qt
1989+#include <QTimer>
1990+
1991+QPADBusMenuExporter::QPADBusMenuExporter(const QString &objectPath, ExportedPlatformMenuBar* menuBar)
1992+ : DBusMenuExporterDBusInterface(objectPath, menuBar)
1993+ , m_menuBar(menuBar)
1994+ , m_revision(1)
1995+ , m_emittedLayoutUpdatedOnce(false)
1996+{
1997+ LOG << "created exporter menu @ " << objectPath;
1998+
1999+ m_propertyTimer = new QTimer(this);
2000+ m_propertyTimer->setInterval(0);
2001+ m_propertyTimer->setSingleShot(true);
2002+ connect(m_propertyTimer, &QTimer::timeout, this, &QPADBusMenuExporter::doMenuPropertyUpdate);
2003+
2004+ m_layoutTimer = new QTimer(this);
2005+ m_layoutTimer->setInterval(0);
2006+ m_layoutTimer->setSingleShot(true);
2007+ connect(m_layoutTimer, &QTimer::timeout, this, &QPADBusMenuExporter::doMenuLayoutUpdate);
2008+
2009+ for (uint i = 0; i < m_menuBar->menuCount(); i++) {
2010+ auto exportedMenu = qobject_cast<ExportedPlatformMenu*>(m_menuBar->menuAt(i));
2011+ addMenu(exportedMenu, 0);
2012+ }
2013+
2014+ connect(menuBar, &ExportedPlatformMenuBar::menuInserted, this, [this](QPlatformMenu* menu) {
2015+ addMenu(qobject_cast<ExportedPlatformMenu*>(menu), 0);
2016+ });
2017+ connect(menuBar, &ExportedPlatformMenuBar::menuRemoved, this, [this](QPlatformMenu* menu) {
2018+ removeMenu(qobject_cast<ExportedPlatformMenu*>(menu), 0);
2019+ });
2020+}
2021+
2022+QPADBusMenuExporter::~QPADBusMenuExporter()
2023+{
2024+}
2025+
2026+void QPADBusMenuExporter::Event(int id, const QString &eventType, const QDBusVariant &data, uint timestamp)
2027+{
2028+ Q_UNUSED(data);
2029+ Q_UNUSED(timestamp);
2030+ LOG << " id:" << id << ", eventType:" << eventType;
2031+
2032+ ExportedPlatformMenuItem* menuItem = m_menuItemForId.value(id, nullptr);
2033+ if (menuItem) {
2034+ if (eventType == "clicked") {
2035+ QMetaObject::invokeMethod(menuItem, "activated");
2036+ } else if (eventType == "hovered") {
2037+ QMetaObject::invokeMethod(menuItem, "hovered");
2038+ }
2039+ }
2040+}
2041+
2042+QDBusVariant QPADBusMenuExporter::GetProperty(int id, const QString &property)
2043+{
2044+ if (!m_propertiesForId.contains(id)) return QDBusVariant();
2045+ return QDBusVariant(m_propertiesForId.value(id).value(property));
2046+}
2047+
2048+void QPADBusMenuExporter::fillLayout(DBusMenuLayoutItem *item, int id, int depth, const QStringList &propertyNames)
2049+{
2050+ item->id = id;
2051+ item->properties = getProperties(id, propertyNames);
2052+
2053+ if (depth != 0) {
2054+ if (id == 0) {
2055+ for (uint i = 0; i < m_menuBar->menuCount(); i++) {
2056+ auto exportedMenu = qobject_cast<ExportedPlatformMenu*>(m_menuBar->menuAt(i));
2057+ if (exportedMenu) {
2058+ DBusMenuLayoutItem child;
2059+ fillLayout(&child, exportedMenu->id(), depth - 1, propertyNames);
2060+ item->children << child;
2061+ }
2062+ }
2063+ } else {
2064+ // menu with children.
2065+ ExportedPlatformMenu* menu = m_menuForId.value(id, nullptr);
2066+ if (menu) {
2067+ for (uint i = 0; i < menu->menuItemCount(); i++) {
2068+ auto exportedMenuItem = qobject_cast<ExportedPlatformMenuItem*>(menu->menuItemAt(i));
2069+
2070+ DBusMenuLayoutItem child;
2071+ fillLayout(&child, exportedMenuItem->id(), depth-1, propertyNames);
2072+ item->children << child;
2073+ }
2074+ } else {
2075+ // child menu items which has an attached menu
2076+ ExportedPlatformMenuItem* menuItem = m_menuItemForId.value(id, nullptr);
2077+ if (menuItem) {
2078+ auto menu = qobject_cast<ExportedPlatformMenu*>(menuItem->menu());
2079+ if (menu) {
2080+ for (uint i = 0; i < menu->menuItemCount(); i++) {
2081+ auto exportedMenuItem = qobject_cast<ExportedPlatformMenuItem*>(menu->menuItemAt(i));
2082+
2083+ DBusMenuLayoutItem child;
2084+ fillLayout(&child, exportedMenuItem->id(), depth-1, propertyNames);
2085+ item->children << child;
2086+ }
2087+ }
2088+ }
2089+ }
2090+ }
2091+ }
2092+}
2093+
2094+uint QPADBusMenuExporter::GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item)
2095+{
2096+ doMenuPropertyUpdate();
2097+
2098+ fillLayout(&item, parentId, recursionDepth, propertyNames);
2099+ return m_revision;
2100+}
2101+
2102+DBusMenuItemList QPADBusMenuExporter::GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames)
2103+{
2104+ DBusMenuItemList list;
2105+ Q_FOREACH(int id, ids) {
2106+ DBusMenuItem item;
2107+ item.id = id;
2108+ item.properties = getProperties(item.id, propertyNames);
2109+ list << item;
2110+ }
2111+ return list;
2112+}
2113+
2114+bool QPADBusMenuExporter::AboutToShow(int id)
2115+{
2116+ return false;
2117+}
2118+
2119+void QPADBusMenuExporter::menuPropertyUpdated(int id)
2120+{
2121+ if (m_propertyUpdates.contains(id)) return;
2122+
2123+ m_propertyUpdates << id;
2124+ if (!m_propertyTimer->isActive()) m_propertyTimer->start();
2125+}
2126+
2127+void QPADBusMenuExporter::menuLayoutUpdated(int id)
2128+{
2129+ if (m_layoutUpdates.contains(id)) return;
2130+
2131+ m_layoutUpdates << id;
2132+ if (!m_layoutTimer->isActive()) m_layoutTimer->start();
2133+}
2134+
2135+inline void logPropertyUpdates(const DBusMenuItemList& updates, const DBusMenuItemKeysList& removals)
2136+{
2137+ Q_FOREACH(const DBusMenuItem& update, updates) {
2138+ qDebug() << "property updates for " << update.id << endl
2139+ << " " << update.properties;
2140+ }
2141+ Q_FOREACH(const DBusMenuItemKeys& remove, removals) {
2142+ qDebug() << "property updates for " << remove.id << endl
2143+ << " " << remove.properties;
2144+ }
2145+}
2146+
2147+void QPADBusMenuExporter::doMenuPropertyUpdate()
2148+{
2149+ if (m_propertyUpdates.isEmpty()) {
2150+ return;
2151+ }
2152+ DBusMenuItemList updatedList;
2153+ DBusMenuItemKeysList removedList;
2154+
2155+ Q_FOREACH(int id, m_propertyUpdates) {
2156+ QVariantMap newProperties;
2157+ ExportedPlatformMenuItem* menuItem = m_menuItemForId.value(id, nullptr);
2158+ // no longer exists?
2159+ if (menuItem) {
2160+ newProperties = ExportedPlatformMenuItemPrivate::propertiesForMenuItem(menuItem);
2161+ } else {
2162+ ExportedPlatformMenu* menu = m_menuForId.value(id, nullptr);
2163+ if (menu) {
2164+ newProperties = ExportedPlatformMenuPrivate::propertiesForMenu(menu);
2165+ }
2166+ }
2167+
2168+ QVariantMap& oldProperties = m_propertiesForId[id];
2169+ QVariantMap updatedProperties;
2170+ QStringList removedProperties;
2171+
2172+ Utils::parsePropertyChanges(oldProperties, newProperties, updatedProperties, removedProperties);
2173+
2174+ // Update our data (oldProperties is a reference)
2175+ oldProperties = newProperties;
2176+
2177+ if (!updatedProperties.isEmpty()) {
2178+ DBusMenuItem item;
2179+ item.id = id;
2180+ item.properties = updatedProperties;
2181+ updatedList << item;
2182+ }
2183+ if (!removedProperties.isEmpty()) {
2184+ DBusMenuItemKeys itemKeys;
2185+ itemKeys.id = id;
2186+ itemKeys.properties = removedProperties;
2187+ removedList << itemKeys;
2188+ }
2189+ }
2190+ m_propertyUpdates.clear();
2191+
2192+ if (!m_emittedLayoutUpdatedOnce) {
2193+ // No need to tell the world about action changes: nobody knows the
2194+ // menu layout so nobody knows about the actions.
2195+ // Note: We still need to reach this method because we want our properties to be
2196+ // updated, even if we don't announce changes.
2197+ return;
2198+ }
2199+ if (!updatedList.isEmpty() || !removedList.isEmpty()) {
2200+#ifdef ENABLE_DEBUG_LOGGING
2201+ logPropertyUpdates(updatedList, removedList);
2202+#endif
2203+
2204+ Q_EMIT ItemsPropertiesUpdated(updatedList, removedList);
2205+ }
2206+}
2207+
2208+void QPADBusMenuExporter::doMenuLayoutUpdate()
2209+{
2210+ // Tell the world about the update
2211+ if (m_emittedLayoutUpdatedOnce) {
2212+ Q_FOREACH(int id, m_layoutUpdates) {
2213+ Q_EMIT LayoutUpdated(++m_revision, id);
2214+ }
2215+ } else {
2216+ // First time we emit LayoutUpdated, no need to emit several layout
2217+ // updates, signals the whole layout (id==0) has been updated
2218+ Q_EMIT LayoutUpdated(++m_revision, 0);
2219+ m_emittedLayoutUpdatedOnce = true;
2220+ }
2221+ m_layoutUpdates.clear();
2222+}
2223+
2224+void QPADBusMenuExporter::addMenu(ExportedPlatformMenu *menu, int parentId)
2225+{
2226+ if (!menu) return;
2227+ if (m_menuForId.contains(menu->id())) return;
2228+
2229+ for (uint i = 0; i < menu->menuItemCount(); i++) {
2230+ auto exportedMenuItem = qobject_cast<ExportedPlatformMenuItem*>(menu->menuItemAt(i));
2231+ addMenuItem(exportedMenuItem, menu->id());
2232+ }
2233+
2234+ m_menuForId[menu->id()] = menu;
2235+ m_propertiesForId[menu->id()] = ExportedPlatformMenuPrivate::propertiesForMenu(menu);
2236+ connect(menu, &ExportedPlatformMenu::propertyUpdated, this, [&, menu]() {
2237+ menuPropertyUpdated(menu->id());
2238+ });
2239+ connect(menu, &ExportedPlatformMenu::menuItemInserted, this, [&, menu](QPlatformMenuItem* menuItem) {
2240+ addMenuItem(qobject_cast<ExportedPlatformMenuItem*>(menuItem), menu->id());
2241+ });
2242+ connect(menu, &ExportedPlatformMenu::menuItemRemoved, this, [&, menu](QPlatformMenuItem* menuItem) {
2243+ removeMenuItem(qobject_cast<ExportedPlatformMenuItem*>(menuItem), menu->id());
2244+ });
2245+
2246+ menuLayoutUpdated(parentId);
2247+}
2248+
2249+void QPADBusMenuExporter::addMenuItem(ExportedPlatformMenuItem *menuItem, int parentId)
2250+{
2251+ if (!menuItem) return;
2252+ if (m_menuItemForId.contains(menuItem->id())) return;
2253+
2254+ m_menuItemForId[menuItem->id()] = menuItem;
2255+ m_propertiesForId[menuItem->id()] = ExportedPlatformMenuItemPrivate::propertiesForMenuItem(menuItem);
2256+
2257+ connect(menuItem, &ExportedPlatformMenuItem::propertyUpdated, this, [&, menuItem]() {
2258+ menuPropertyUpdated(menuItem->id());
2259+ });
2260+
2261+ auto menu = qobject_cast<ExportedPlatformMenu*>(menuItem->menu());
2262+ if (menu) {
2263+ addMenu(menu, parentId);
2264+ }
2265+ menuLayoutUpdated(parentId);
2266+}
2267+
2268+void QPADBusMenuExporter::removeMenu(ExportedPlatformMenu *menu, int parentId)
2269+{
2270+ if (!menu) return;
2271+
2272+ for (uint i = 0; i < menu->menuItemCount(); i++) {
2273+ auto exportedMenuItem = qobject_cast<ExportedPlatformMenuItem*>(menu->menuItemAt(i));
2274+ removeMenuItem(exportedMenuItem, parentId);
2275+ }
2276+ disconnect(menu, 0, this, 0);
2277+}
2278+
2279+void QPADBusMenuExporter::removeMenuItem(ExportedPlatformMenuItem *menuItem, int parentId)
2280+{
2281+ if (!menuItem) return;
2282+
2283+ auto menu = qobject_cast<ExportedPlatformMenu*>(menuItem->menu());
2284+ if (menu) {
2285+ removeMenu(menu, menuItem->id());
2286+ }
2287+
2288+ m_menuItemForId.remove(menuItem->id());
2289+ m_propertiesForId.remove(menuItem->id());
2290+ disconnect(menuItem, 0, this, 0);
2291+
2292+ menuLayoutUpdated(parentId);
2293+}
2294+
2295+QVariantMap QPADBusMenuExporter::getProperties(int id, const QStringList &names) const
2296+{
2297+ if (id == 0) {
2298+ QVariantMap map;
2299+ map.insert(DBusMenuProperty::ChildrenDisplay, "submenu");
2300+ return map;
2301+ }
2302+ QVariantMap all = m_propertiesForId.value(id);
2303+ if (names.isEmpty()) {
2304+ return all;
2305+ } else {
2306+ QVariantMap map;
2307+ Q_FOREACH(const QString &name, names) {
2308+ QVariant value = all.value(name);
2309+ if (value.isValid()) {
2310+ map.insert(name, value);
2311+ }
2312+ }
2313+ return map;
2314+ }
2315+}
2316+
2317
2318=== added file 'src/qpa/qpadbusmenuexporter_p.h'
2319--- src/qpa/qpadbusmenuexporter_p.h 1970-01-01 00:00:00 +0000
2320+++ src/qpa/qpadbusmenuexporter_p.h 2015-03-18 11:19:06 +0000
2321@@ -0,0 +1,94 @@
2322+/* This file is part of the dbusmenu-qt library
2323+ Copyright 2015 Canonical
2324+ Author: Nick Dedekind <nick.dedekind@canonical.com>
2325+
2326+ This library is free software; you can redistribute it and/or
2327+ modify it under the terms of the GNU Library General Public
2328+ License (LGPL) as published by the Free Software Foundation;
2329+ either version 2 of the License, or (at your option) any later
2330+ version.
2331+
2332+ This library is distributed in the hope that it will be useful,
2333+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2334+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2335+ Library General Public License for more details.
2336+
2337+ You should have received a copy of the GNU Library General Public License
2338+ along with this library; see the file COPYING.LIB. If not, write to
2339+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2340+ Boston, MA 02110-1301, USA.
2341+*/
2342+#ifndef QPADBUSMENUEXPORTER_H
2343+#define QPADBUSMENUEXPORTER_H
2344+
2345+// Qt
2346+#include <QtCore/QObject>
2347+#include <QtDBus/QDBusConnection>
2348+#include <qpa/qplatformmenu.h>
2349+
2350+// Local
2351+#include "dbusmenuexporterdbusinterface_p.h"
2352+
2353+class QAction;
2354+class QMenu;
2355+
2356+class ExportedPlatformMenuBar;
2357+class ExportedPlatformMenu;
2358+class ExportedPlatformMenuItem;
2359+
2360+/**
2361+ * A QPADBusMenuExporter instance can serialize a qua menu over DBus
2362+ */
2363+class QPADBusMenuExporter : public DBusMenuExporterDBusInterface
2364+{
2365+ Q_OBJECT
2366+ Q_CLASSINFO("D-Bus Interface", "com.canonical.dbusmenu")
2367+public:
2368+ QPADBusMenuExporter(const QString& path, ExportedPlatformMenuBar* menuBar);
2369+ virtual ~QPADBusMenuExporter();
2370+
2371+ // overrides
2372+ void Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp) override;
2373+ QDBusVariant GetProperty(int id, const QString &property) override;
2374+ uint GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item) override;
2375+ DBusMenuItemList GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames) override;
2376+ bool AboutToShow(int id) override;
2377+
2378+private Q_SLOTS:
2379+ void menuPropertyUpdated(int id);
2380+ void menuLayoutUpdated(int id);
2381+
2382+private Q_SLOTS:
2383+ void doMenuPropertyUpdate();
2384+ void doMenuLayoutUpdate();
2385+
2386+private:
2387+ Q_DISABLE_COPY(QPADBusMenuExporter)
2388+
2389+ void addMenu(ExportedPlatformMenu* menu, int parentId);
2390+ void addMenuItem(ExportedPlatformMenuItem* menu, int parentId);
2391+
2392+ void removeMenu(ExportedPlatformMenu* menu, int parentId);
2393+ void removeMenuItem(ExportedPlatformMenuItem* menuItem, int parentId);
2394+
2395+ void fillLayout(DBusMenuLayoutItem *item, int id, int depth, const QStringList &propertyNames);
2396+ QVariantMap getProperties(int id, const QStringList &names) const;
2397+
2398+ ExportedPlatformMenuBar* m_menuBar;
2399+ QTimer* m_propertyTimer;
2400+ QTimer* m_layoutTimer;
2401+
2402+ QList<int> m_propertyUpdates;
2403+ QList<int> m_layoutUpdates;
2404+ uint m_revision;
2405+ bool m_emittedLayoutUpdatedOnce;
2406+
2407+ QHash<int, ExportedPlatformMenuItem*> m_menuItemForId;
2408+ QHash<int, ExportedPlatformMenu*> m_menuForId;
2409+ QHash<int, QVariantMap> m_propertiesForId;
2410+
2411+ friend class ExportedPlatformMenu;
2412+ friend class ExportedPlatformMenuItem;
2413+};
2414+
2415+#endif /* QPADBUSMENUEXPORTER_H */
2416
2417=== modified file 'src/utils.cpp'
2418--- src/utils.cpp 2010-09-20 08:55:12 +0000
2419+++ src/utils.cpp 2015-03-18 11:19:06 +0000
2420@@ -23,7 +23,7 @@
2421 // Qt
2422 #include <QString>
2423
2424-QString swapMnemonicChar(const QString &in, const char src, const char dst)
2425+QString Utils::swapMnemonicChar(const QString &in, const char src, const char dst)
2426 {
2427 QString out;
2428 bool mnemonicFound = false;
2429@@ -62,3 +62,38 @@
2430
2431 return out;
2432 }
2433+
2434+
2435+void Utils::parsePropertyChanges(const QVariantMap &oldProperties,
2436+ const QVariantMap &newProperties,
2437+ QVariantMap &updatedProperties,
2438+ QStringList &removedProperties)
2439+{
2440+ // Find updated and removed properties
2441+ QVariantMap::ConstIterator newEnd = newProperties.constEnd();
2442+
2443+ QVariantMap::ConstIterator
2444+ oldIt = oldProperties.constBegin(),
2445+ oldEnd = oldProperties.constEnd();
2446+ for(; oldIt != oldEnd; ++oldIt) {
2447+ QString key = oldIt.key();
2448+ QVariantMap::ConstIterator newIt = newProperties.constFind(key);
2449+ if (newIt != newEnd) {
2450+ if (newIt.value() != oldIt.value()) {
2451+ updatedProperties.insert(key, newIt.value());
2452+ }
2453+ } else {
2454+ removedProperties << key;
2455+ }
2456+ }
2457+
2458+ // Find new properties (treat them as updated properties)
2459+ QVariantMap::ConstIterator newIt = newProperties.constBegin();
2460+ for (; newIt != newEnd; ++newIt) {
2461+ QString key = newIt.key();
2462+ oldIt = oldProperties.constFind(key);
2463+ if (oldIt == oldEnd) {
2464+ updatedProperties.insert(key, newIt.value());
2465+ }
2466+ }
2467+}
2468
2469=== modified file 'src/utils_p.h'
2470--- src/utils_p.h 2010-09-20 08:55:12 +0000
2471+++ src/utils_p.h 2015-03-18 11:19:06 +0000
2472@@ -22,10 +22,20 @@
2473 #define UTILS_P_H
2474
2475 class QString;
2476-
2477-/**
2478- * Swap mnemonic char: Qt uses '&', while dbusmenu uses '_'
2479- */
2480-QString swapMnemonicChar(const QString &in, const char src, const char dst);
2481+class QStringList;
2482+#include <QVariant>
2483+
2484+namespace Utils {
2485+
2486+ /**
2487+ * Swap mnemonic char: Qt uses '&', while dbusmenu uses '_'
2488+ */
2489+ QString swapMnemonicChar(const QString &in, const char src, const char dst);
2490+
2491+ void parsePropertyChanges(const QVariantMap& oldProperties,
2492+ const QVariantMap& newProperties,
2493+ QVariantMap& updatedProperties,
2494+ QStringList& removedProperties);
2495+}
2496
2497 #endif /* UTILS_P_H */
2498
2499=== modified file 'tests/CMakeLists.txt'
2500--- tests/CMakeLists.txt 2015-03-18 11:19:06 +0000
2501+++ tests/CMakeLists.txt 2015-03-18 11:19:06 +0000
2502@@ -120,5 +120,18 @@
2503 ${test_LIBRARIES}
2504 )
2505
2506+
2507+# exportedplatformmenutest
2508+if (USE_QT5)
2509+ add_test_executable(exportedplatformmenutest
2510+ exportedplatformmenutest.cpp
2511+ testutils.cpp
2512+ )
2513+
2514+ target_link_libraries(exportedplatformmenutest
2515+ ${test_LIBRARIES}
2516+ )
2517+endif()
2518+
2519 # Keep this at the end
2520 create_check_target()
2521
2522=== modified file 'tests/dbusmenuexportertest.cpp'
2523--- tests/dbusmenuexportertest.cpp 2015-03-18 11:19:06 +0000
2524+++ tests/dbusmenuexportertest.cpp 2015-03-18 11:19:06 +0000
2525@@ -31,7 +31,7 @@
2526
2527 // DBusMenuQt
2528 #include <dbusmenuexporter.h>
2529-#include <dbusmenutypes_p.h>
2530+#include <dbusmenutypes.h>
2531 #include <dbusmenushortcut_p.h>
2532 #include <debug_p.h>
2533
2534@@ -114,6 +114,7 @@
2535 if (enabled) {
2536 QVERIFY(!item.properties.contains("enabled"));
2537 } else {
2538+ QVERIFY(item.properties.contains("enabled"));
2539 QCOMPARE(item.properties.value("enabled").toBool(), false);
2540 }
2541 if (iconName.isEmpty()) {
2542
2543=== added file 'tests/exportedplatformmenutest.cpp'
2544--- tests/exportedplatformmenutest.cpp 1970-01-01 00:00:00 +0000
2545+++ tests/exportedplatformmenutest.cpp 2015-03-18 11:19:06 +0000
2546@@ -0,0 +1,366 @@
2547+/* This file is part of the dbusmenu-qt library
2548+ Copyright 2015 Canonical
2549+ Author: Aurelien Gateau <aurelien.gateau@canonical.com>
2550+
2551+ This library is free software; you can redistribute it and/or
2552+ modify it under the terms of the GNU Library General Public
2553+ License (LGPL) as published by the Free Software Foundation;
2554+ either version 2 of the License, or (at your option) any later
2555+ version.
2556+
2557+ This library is distributed in the hope that it will be useful,
2558+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2559+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2560+ Library General Public License for more details.
2561+
2562+ You should have received a copy of the GNU Library General Public License
2563+ along with this library; see the file COPYING.LIB. If not, write to
2564+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2565+ Boston, MA 02110-1301, USA.
2566+*/
2567+// Self
2568+#include "exportedplatformmenutest.h"
2569+
2570+// Qt
2571+#include <QDBusConnection>
2572+#include <QDBusInterface>
2573+#include <QDBusReply>
2574+#include <QtTest>
2575+
2576+// DBusMenuQt
2577+#include <qpa/exportedplatformmenubar.h>
2578+#include <dbusmenutypes.h>
2579+#include <dbusmenushortcut_p.h>
2580+#include <debug_p.h>
2581+
2582+// Local
2583+#include "testutils.h"
2584+
2585+QTEST_MAIN(ExportedPlatformMenuTest)
2586+
2587+static const char *TEST_SERVICE = "org.kde.dbusmenu-qt-test";
2588+static const char *TEST_OBJECT_PATH = "/TestMenuBar";
2589+
2590+Q_DECLARE_METATYPE(QList<int>)
2591+
2592+static DBusMenuLayoutItemList getChildren(QDBusAbstractInterface* iface, int parentId, const QStringList &propertyNames)
2593+{
2594+ QDBusPendingReply<uint, DBusMenuLayoutItem> reply = iface->call("GetLayout", parentId, /*recursionDepth=*/ 1, propertyNames);
2595+ reply.waitForFinished();
2596+ if (!reply.isValid()) {
2597+ qFatal("%s", qPrintable(reply.error().message()));
2598+ return DBusMenuLayoutItemList();
2599+ }
2600+
2601+ DBusMenuLayoutItem rootItem = reply.argumentAt<1>();
2602+ return rootItem.children;
2603+}
2604+
2605+void ExportedPlatformMenuTest::init()
2606+{
2607+ QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
2608+ QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, false);
2609+}
2610+
2611+void ExportedPlatformMenuTest::cleanup()
2612+{
2613+ QVERIFY(QDBusConnection::sessionBus().unregisterService(TEST_SERVICE));
2614+}
2615+
2616+void ExportedPlatformMenuTest::testGetSomeMenuProperties_data()
2617+{
2618+ QTest::addColumn<QString>("label");
2619+ QTest::addColumn<QString>("iconName");
2620+ QTest::addColumn<bool>("enabled");
2621+
2622+ QTest::newRow("label only") << "label" << QString() << true;
2623+ QTest::newRow("disabled, label only") << "label" << QString() << false;
2624+ QTest::newRow("icon name") << "label" << "edit-undo" << true;
2625+}
2626+
2627+void ExportedPlatformMenuTest::testGetSomeMenuProperties()
2628+{
2629+ QFETCH(QString, label);
2630+ QFETCH(QString, iconName);
2631+ QFETCH(bool, enabled);
2632+
2633+ // Create an exporter for a menu with one action, defined by the test data
2634+ ExportedPlatformMenuBar menuBar(TEST_OBJECT_PATH);
2635+ ExportedPlatformMenu menu;
2636+ menu.setText(label);
2637+ if (!iconName.isEmpty()) {
2638+ QIcon icon = QIcon::fromTheme(iconName);
2639+ QVERIFY(!icon.isNull());
2640+ menu.setIcon(icon);
2641+ }
2642+ menu.setEnabled(enabled);
2643+ menuBar.insertMenu(&menu, nullptr);
2644+
2645+ // Check out exporter is on DBus
2646+ QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
2647+ QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
2648+
2649+ // Get exported menu info
2650+ QStringList propertyNames = QStringList() << "type" << "enabled" << "label" << "icon-name";
2651+ DBusMenuLayoutItemList list = getChildren(&iface, /*parentId=*/0, propertyNames);
2652+ QVERIFY(!list.isEmpty());
2653+ DBusMenuLayoutItem item = list.first();
2654+
2655+ QVERIFY(item.id != 0);
2656+ QVERIFY(item.children.isEmpty());
2657+ QVERIFY(!item.properties.contains("type"));
2658+ QCOMPARE(item.properties.value("label").toString(), label);
2659+ if (enabled) {
2660+ QVERIFY(!item.properties.contains("enabled"));
2661+ } else {
2662+ QVERIFY(item.properties.contains("enabled"));
2663+ QCOMPARE(item.properties.value("enabled").toBool(), false);
2664+ }
2665+ if (iconName.isEmpty()) {
2666+ QVERIFY(!item.properties.contains("icon-name"));
2667+ } else {
2668+ QCOMPARE(item.properties.value("icon-name").toString(), iconName);
2669+ }
2670+}
2671+
2672+void ExportedPlatformMenuTest::testGetSomeMenuItemProperties_data()
2673+{
2674+ QTest::addColumn<QString>("label");
2675+ QTest::addColumn<QString>("iconName");
2676+ QTest::addColumn<bool>("enabled");
2677+
2678+ QTest::newRow("label only") << "label" << QString() << true;
2679+ QTest::newRow("disabled, label only") << "label" << QString() << false;
2680+ QTest::newRow("icon name") << "label" << "edit-undo" << true;
2681+}
2682+
2683+void ExportedPlatformMenuTest::testGetSomeMenuItemProperties()
2684+{
2685+ QFETCH(QString, label);
2686+ QFETCH(QString, iconName);
2687+ QFETCH(bool, enabled);
2688+
2689+ // Create an exporter for a menu with one action, defined by the test data
2690+ ExportedPlatformMenuBar menuBar(TEST_OBJECT_PATH);
2691+ ExportedPlatformMenu menu;
2692+ menuBar.insertMenu(&menu, nullptr);
2693+
2694+ ExportedPlatformMenuItem menuItem1;
2695+ menuItem1.setText(label);
2696+ if (!iconName.isEmpty()) {
2697+ QIcon icon = QIcon::fromTheme(iconName);
2698+ QVERIFY(!icon.isNull());
2699+ menuItem1.setIcon(icon);
2700+ }
2701+ menuItem1.setEnabled(enabled);
2702+ menu.insertMenuItem(&menuItem1, nullptr);
2703+
2704+ // Check out exporter is on DBus
2705+ QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
2706+ QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
2707+
2708+ // Get exported menu info
2709+ QStringList propertyNames = QStringList() << "type" << "enabled" << "label" << "icon-name";
2710+ DBusMenuLayoutItemList list = getChildren(&iface, /*parentId=*/0, propertyNames);
2711+ QVERIFY(!list.isEmpty());
2712+
2713+ // Now get the mennu children (menu items)
2714+ list = getChildren(&iface, list.first().id, QStringList());
2715+ QVERIFY(!list.isEmpty());
2716+ DBusMenuLayoutItem item = list.first();
2717+
2718+ QVERIFY(item.id != 0);
2719+ QVERIFY(item.children.isEmpty());
2720+ QVERIFY(!item.properties.contains("type"));
2721+ QCOMPARE(item.properties.value("label").toString(), label);
2722+ if (enabled) {
2723+ QVERIFY(!item.properties.contains("enabled"));
2724+ } else {
2725+ QVERIFY(item.properties.contains("enabled"));
2726+ QCOMPARE(item.properties.value("enabled").toBool(), false);
2727+ }
2728+ if (iconName.isEmpty()) {
2729+ QVERIFY(!item.properties.contains("icon-name"));
2730+ } else {
2731+ QCOMPARE(item.properties.value("icon-name").toString(), iconName);
2732+ }
2733+}
2734+
2735+void ExportedPlatformMenuTest::testGetAllProperties()
2736+{
2737+ // set of properties which must be returned because their values are not
2738+ // the default values
2739+ const QSet<QString> a1Properties = QSet<QString>()
2740+ << "label"
2741+ ;
2742+
2743+ const QSet<QString> separatorProperties = QSet<QString>()
2744+ << "type";
2745+
2746+ const QSet<QString> a2Properties = QSet<QString>()
2747+ << "label"
2748+ << "enabled"
2749+ << "icon-name"
2750+ << "icon-data" // Icon data is always provided if the icon is valid.
2751+ << "visible";
2752+
2753+ ExportedPlatformMenuBar menuBar(TEST_OBJECT_PATH);
2754+ ExportedPlatformMenu menu;
2755+ menuBar.insertMenu(&menu, nullptr);
2756+
2757+ ExportedPlatformMenuItem menuItem1;
2758+ menuItem1.setText("m1");
2759+ menu.insertMenuItem(&menuItem1, nullptr);
2760+
2761+ ExportedPlatformMenuItem separator;
2762+ separator.setIsSeparator(true);
2763+ menu.insertMenuItem(&separator, nullptr);
2764+
2765+ ExportedPlatformMenuItem menuItem2;
2766+ menuItem2.setText("m2");
2767+ menuItem2.setEnabled(false);
2768+ menuItem2.setVisible(false);
2769+ QIcon icon = QIcon::fromTheme("edit-undo");
2770+ QVERIFY(!icon.isNull());
2771+ menuItem2.setIcon(icon);
2772+ menu.insertMenuItem(&menuItem2, nullptr);
2773+
2774+ // Export them
2775+ QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
2776+ QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
2777+
2778+ // Get menu children
2779+ DBusMenuLayoutItemList list = getChildren(&iface, menu.id(), QStringList());
2780+ QCOMPARE(list.count(), 3);
2781+
2782+ // Check we get the right properties
2783+ DBusMenuLayoutItem item = list.takeFirst();
2784+ QCOMPARE(QSet<QString>::fromList(item.properties.keys()), a1Properties);
2785+
2786+ item = list.takeFirst();
2787+ QCOMPARE(QSet<QString>::fromList(item.properties.keys()), separatorProperties);
2788+
2789+ item = list.takeFirst();
2790+ QCOMPARE(QSet<QString>::fromList(item.properties.keys()), a2Properties);
2791+}
2792+
2793+void ExportedPlatformMenuTest::testGetNonExistentProperty()
2794+{
2795+ const char* NON_EXISTENT_KEY = "i-do-not-exist";
2796+
2797+ ExportedPlatformMenuBar menuBar(TEST_OBJECT_PATH);
2798+ ExportedPlatformMenu menu;
2799+ menuBar.insertMenu(&menu, nullptr);
2800+
2801+ QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
2802+ DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList() << NON_EXISTENT_KEY);
2803+ QCOMPARE(list.count(), 1);
2804+
2805+ DBusMenuLayoutItem item = list.takeFirst();
2806+ QVERIFY(!item.properties.contains(NON_EXISTENT_KEY));
2807+}
2808+
2809+void ExportedPlatformMenuTest::testClickedEvent()
2810+{
2811+ ExportedPlatformMenuBar menuBar(TEST_OBJECT_PATH);
2812+ ExportedPlatformMenu menu;
2813+ menuBar.insertMenu(&menu, nullptr);
2814+
2815+ ExportedPlatformMenuItem menuItem1;
2816+ menuItem1.setText("m1");
2817+ menu.insertMenuItem(&menuItem1, nullptr);
2818+
2819+ QSignalSpy spy(&menuItem1, SIGNAL(activated()));
2820+
2821+ QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
2822+ DBusMenuLayoutItemList list = getChildren(&iface, menu.id(), QStringList());
2823+ QCOMPARE(list.count(), 1);
2824+ int id = list.first().id;
2825+
2826+ QVariant empty = QVariant::fromValue(QDBusVariant(QString()));
2827+ uint timestamp = QDateTime::currentDateTime().toTime_t();
2828+ iface.call("Event", id, "clicked", empty, timestamp);
2829+ QTest::qWait(100);
2830+
2831+ QCOMPARE(spy.count(), 1);
2832+}
2833+
2834+void ExportedPlatformMenuTest::testSubMenu()
2835+{
2836+ // Root
2837+ // -- submenu
2838+ // ---- childmenu
2839+ // ----- hildmenu
2840+
2841+ // Create our test menu
2842+ ExportedPlatformMenuBar menuBar(TEST_OBJECT_PATH);
2843+ ExportedPlatformMenu menu;
2844+ menuBar.insertMenu(&menu, nullptr);
2845+
2846+ ExportedPlatformMenu subMenu;
2847+ ExportedPlatformMenuItem subMenuItem;
2848+ subMenuItem.setMenu(&subMenu);
2849+ menu.insertMenuItem(&subMenuItem, nullptr);
2850+
2851+ ExportedPlatformMenuItem childMenu1;
2852+ ExportedPlatformMenuItem childMenu2;
2853+ subMenu.insertMenuItem(&childMenu1, nullptr);
2854+ subMenu.insertMenuItem(&childMenu2, nullptr);
2855+
2856+ // Check the structure
2857+ QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
2858+ DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList());
2859+ QCOMPARE(list.count(), 1);
2860+
2861+ list = getChildren(&iface, list.first().id, QStringList());
2862+ QCOMPARE(list.count(), 1);
2863+
2864+ list = getChildren(&iface, list.first().id, QStringList());
2865+ QCOMPARE(list.count(), 2);
2866+}
2867+
2868+void ExportedPlatformMenuTest::testDynamicSubMenu()
2869+{
2870+ // Root
2871+ // -- childmenu
2872+ // -- childmenu
2873+
2874+ // Track LayoutUpdated() signal: we don't want this signal to be emitted
2875+ // too often because it causes refreshes
2876+ QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
2877+ ManualSignalSpy layoutUpdatedSpy;
2878+ QDBusConnection::sessionBus().connect(TEST_SERVICE, TEST_OBJECT_PATH, "com.canonical.dbusmenu", "LayoutUpdated", "ui", &layoutUpdatedSpy, SLOT(receiveCall(uint, int)));
2879+
2880+ // Create our test menu
2881+ ExportedPlatformMenuBar menuBar(TEST_OBJECT_PATH);
2882+ ExportedPlatformMenu menu;
2883+ menuBar.insertMenu(&menu, nullptr);
2884+
2885+ // LayoutUpdated should be emitted once because inputMenu is filled
2886+ QTest::qWait(100);
2887+ QCOMPARE(layoutUpdatedSpy.count(), 1);
2888+ QCOMPARE(layoutUpdatedSpy.takeFirst().at(1).toInt(), 0);
2889+
2890+ ExportedPlatformMenu subMenu;
2891+ ExportedPlatformMenuItem subMenuItem1;
2892+ subMenuItem1.setMenu(&subMenu);
2893+ ExportedPlatformMenuItem subMenuItem2;
2894+ subMenuItem2.setMenu(&subMenu);
2895+ menu.insertMenuItem(&subMenuItem1, nullptr);
2896+ menu.insertMenuItem(&subMenuItem2, nullptr);
2897+
2898+ QTest::qWait(100);
2899+ // LayoutUpdated should be emitted once more with the parent menus id
2900+ // because menu item was inserted.
2901+ QCOMPARE(layoutUpdatedSpy.count(), 1);
2902+ QCOMPARE(layoutUpdatedSpy.takeFirst().at(1).toInt(), menu.id());
2903+
2904+ DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList());
2905+ QCOMPARE(list.count(), 1);
2906+
2907+ list = getChildren(&iface, list.first().id, QStringList());
2908+ QCOMPARE(list.count(), 2);
2909+}
2910+
2911+
2912+#include "exportedplatformmenutest.moc"
2913
2914=== added file 'tests/exportedplatformmenutest.h'
2915--- tests/exportedplatformmenutest.h 1970-01-01 00:00:00 +0000
2916+++ tests/exportedplatformmenutest.h 2015-03-18 11:19:06 +0000
2917@@ -0,0 +1,55 @@
2918+/* This file is part of the dbusmenu-qt library
2919+ Copyright 2015 Canonical
2920+ Author: Aurelien Gateau <aurelien.gateau@canonical.com>
2921+
2922+ This library is free software; you can redistribute it and/or
2923+ modify it under the terms of the GNU Library General Public
2924+ License (LGPL) as published by the Free Software Foundation;
2925+ either version 2 of the License, or (at your option) any later
2926+ version.
2927+
2928+ This library is distributed in the hope that it will be useful,
2929+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2930+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2931+ Library General Public License for more details.
2932+
2933+ You should have received a copy of the GNU Library General Public License
2934+ along with this library; see the file COPYING.LIB. If not, write to
2935+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2936+ Boston, MA 02110-1301, USA.
2937+*/
2938+#ifndef EXPORTEDPLATFORMMENUTEST_H
2939+#define EXPORTEDPLATFORMMENUTEST_H
2940+
2941+#define QT_GUI_LIB
2942+#include <QtGui>
2943+
2944+// Qt
2945+#include <QObject>
2946+
2947+// Local
2948+
2949+class ExportedPlatformMenuTest : public QObject
2950+{
2951+Q_OBJECT
2952+private Q_SLOTS:
2953+ // properties
2954+ void testGetSomeMenuProperties();
2955+ void testGetSomeMenuProperties_data();
2956+ void testGetSomeMenuItemProperties();
2957+ void testGetSomeMenuItemProperties_data();
2958+ void testGetAllProperties();
2959+ void testGetNonExistentProperty();
2960+
2961+ // events
2962+ void testClickedEvent();
2963+
2964+ // heirachy
2965+ void testSubMenu();
2966+ void testDynamicSubMenu();
2967+
2968+ void init();
2969+ void cleanup();
2970+};
2971+
2972+#endif /* EXPORTEDPLATFORMMENUTEST_H */
2973
2974=== modified file 'tests/testutils.h'
2975--- tests/testutils.h 2011-08-29 14:51:01 +0000
2976+++ tests/testutils.h 2015-03-18 11:19:06 +0000
2977@@ -23,7 +23,7 @@
2978
2979 // Local
2980 #include <debug_p.h>
2981-#include <dbusmenutypes_p.h>
2982+#include <dbusmenutypes.h>
2983
2984 // Qt
2985 #include <QObject>

Subscribers

People subscribed via source and target branches

to all changes: