qmenumodel-0.2.7+14.04.20140305/0000755000015201777760000000000012305545277016273 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/cmake/0000755000015201777760000000000012305545277017353 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/cmake/lcov.cmake0000644000015201777760000000500512305545024021306 0ustar pbusernogroup00000000000000# - This module creates a new 'lcov' target which generates # a coverage analysis html output. # LCOV is a graphical front-end for GCC's coverage testing tool gcov. Please see # http://ltp.sourceforge.net/coverage/lcov.php # # Usage: you must add an option to your CMakeLists.txt to build your application # with coverage support. Then you need to include this file to the lcov target. # # Example: # IF(BUILD_WITH_COVERAGE) # SET(CMAKE_C_FLAGS "-g -O0 -Wall -fprofile-arcs -ftest-coverage") # SET(CMAKE_CXX_FLAGS "-g -O0 -Wall -fprofile-arcs -ftest-coverage") # SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage -lgcov") # include(${CMAKE_SOURCE_DIR}/cmake/lcov.cmake) # ENDIF(BUILD_WITH_COVERAGE) #============================================================================= # Copyright 2010 ascolab GmbH # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distributed this file outside of CMake, substitute the full # License text for the above reference.) set(REMOVE_PATTERN q*.h *.moc moc_*.cpp locale_facets.h new) ## lcov target ADD_CUSTOM_TARGET(lcov) ADD_CUSTOM_COMMAND(TARGET lcov COMMAND mkdir -p coverage WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) ADD_CUSTOM_COMMAND(TARGET lcov COMMAND lcov --directory . --zerocounters WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) ADD_CUSTOM_COMMAND(TARGET lcov COMMAND make test WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) ADD_CUSTOM_COMMAND(TARGET lcov COMMAND lcov --directory . --capture --output-file ./coverage/stap_all.info --no-checksum --compat-libtool WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) ADD_CUSTOM_COMMAND(TARGET lcov COMMAND lcov --directory . -r ./coverage/stap_all.info ${REMOVE_PATTERN} --output-file ./coverage/stap.info WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) ADD_CUSTOM_COMMAND(TARGET lcov COMMAND genhtml -o ./coverage --title "Code Coverage" --legend --show-details --demangle-cpp ./coverage/stap.info WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) ADD_CUSTOM_COMMAND(TARGET lcov COMMAND echo "Open ${CMAKE_BINARY_DIR}/coverage/index.html to view the coverage analysis results." WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) qmenumodel-0.2.7+14.04.20140305/tests/0000755000015201777760000000000012305545277017435 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/tests/script/0000755000015201777760000000000012305545277020741 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/tests/script/CMakeLists.txt0000644000015201777760000000030612305545024023466 0ustar pbusernogroup00000000000000project(dbusmenuscript) add_library(dbusmenuscript STATIC dbusmenuscript.cpp) set_target_properties(dbusmenuscript PROPERTIES COMPILE_FLAGS -fPIC) qt5_use_modules(dbusmenuscript Core DBus Test) qmenumodel-0.2.7+14.04.20140305/tests/script/menuscript.py0000644000015201777760000001735612305545024023506 0ustar pbusernogroup00000000000000# Copyright 2013 Canonical Ltd. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # import dbus import dbus.service from dbus import glib from dbus.mainloop.glib import DBusGMainLoop from gi.repository import GObject from gi.repository import GLib from gi.repository import Gio SERVICE_NAME = "com.canonical.test" INTERFACE_NAME = "com.canonical.test.menuscript" OBJECT_PATH = "/com/canonical/test/menuscript" MENU_SERVICE_NAME= SERVICE_NAME + ".menu" MENU_OBJECT_PATH = OBJECT_PATH + "/menu" bus = None class Script(dbus.service.Object): def __init__(self, aList, session, object_path): dbus.service.Object.__init__(self, session, object_path) self._list = aList self._session = session def run(self): self._loop = GObject.MainLoop() self._loop.run() @dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='', out_signature='', sender_keyword='sender') def publishMenu(self, sender=None): self._list.start() @dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='', out_signature='', sender_keyword='sender') def unpublishMenu(self, sender=None): self._list.stop() @dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='', out_signature='', sender_keyword='sender') def quit(self, sender=None): self.unpublishMenu(); self._loop.quit() @dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='i', out_signature='', sender_keyword='sender') def walk(self, steps, sender=None): if steps == -1 or steps > self._list.size(): steps = self._list.size() while(steps > 0): self._list.walk() steps -= 1 """ TODO: We only support string states for now """ @dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='', out_signature='ss') def popActivatedAction(self): return self._list._activatedActions.pop(0) @staticmethod def create(aList): global bus GObject.threads_init() glib.threads_init() dbus_loop = DBusGMainLoop() bus = dbus.SessionBus(mainloop=dbus_loop) bus_name = dbus.service.BusName(SERVICE_NAME, bus=bus) return Script(aList, bus_name, OBJECT_PATH) class Action(object): def __init__(self, aList, action, **kwargs): self._list = aList self._action = action self._kargs = kwargs def setProperties(self, menu, props): if props: for key in props: menu.set_attribute_value(key, props[key]) def appendItem(self): parentId = self._kargs['parentId'] if parentId and len(parentId): parent = self._list.getMenu(parentId)[0] else: parent = self._list._root if self._kargs['link'] == None: item = Gio.MenuItem.new(self._kargs['label'], self._kargs['actionName']) self.setProperties(item, self._kargs['properties']) parent.append_item(item) # Action act = Gio.SimpleAction.new(self._kargs['actionName'], self._kargs['actionStateType']) act.connect('activate', self._list._onActionActivated) self._list._rootAction.insert(act) elif self._kargs['link'] == 'section': section = Gio.Menu() parent.append_section(self._kargs['label'], section) elif self._kargs['link'] == 'submenu': submenu = Gio.Menu() parent.append_submenu(self._kargs['label'], submenu) def removeItem(self): menuId = self._kargs['menuId'] (menu, mId) = self._list.getMenu(menuId) if mId != -1: menu.remove(mId) if self._kargs['actionName']: # Remove action self._list._rootAction.remove(self._kargs['actionName']) else: print("Remove menu item") def run(self): if self._action == 'append': self.appendItem() elif self._action == 'remove': self.removeItem() class ActionList(object): def __init__(self, objectPath): self._actions = [] self._actions_bk = [] self._objectPath = objectPath self._bus = None self._exportMenuID = None self._exportActionID = None self._ownNameID = None self._root = None self._rootAction = None self._activatedActions = [] def appendItem(self, label, actionName, link=None, parentId=None, properties=None, actionStateType=None): self._actions.append(Action(self, 'append', parentId=parentId, label=label, actionName=actionName, link=link, properties=properties, actionStateType=actionStateType)) def removeItem(self, menuId, actionName=None): self._actions.append(Action(self, 'remove', menuId=menuId, actionName=actionName)) def _save(self): self._actions_bk = [] self._actions_bk.extend(self._actions) def _restore(self): if len(self._actions_bk): self._actions = [] self._actions.extend(self._actions_bk) def _findMenu(self, root, ids): if len(ids) == 0: return (root, -1) currentId = int(ids[0]) link = root.get_item_link(currentId, 'section') if link == None: link = root.get_item_link(currentId, 'submenu') if link: return self._findMenu(link, ids[1:]) else: return (root, currentId) def getMenu(self, menuId): return self._findMenu(self._root, str(menuId).split('.')); def walk(self): item = self._actions.pop(0) item.run() def size(self): return len(self._actions) def _exportService(self, connection, name): self._root = Gio.Menu() self._rootAction = Gio.SimpleActionGroup() self._bus = connection self._exportMenuID = connection.export_menu_model(MENU_OBJECT_PATH, self._root) self._exportActionID = connection.export_action_group(MENU_OBJECT_PATH, self._rootAction) def start(self): self._save() self._ownNameID = Gio.bus_own_name(2, MENU_SERVICE_NAME, 0, self._exportService, None, None) def stop(self): if self._exportMenuID: self._bus.unexport_menu_model(self._exportMenuID) self._exportMenuID = None if self._exportActionID: self._bus.unexport_action_group(self._exportActionID) self._exportActionID = None if self._ownNameID: Gio.bus_unown_name(self._ownNameID) self._ownNameID = None self._root = None self._rootAction = None self._restore() def _onActionActivated(self, action, parameter): self._activatedActions.append((action.get_name(), parameter.get_string())) qmenumodel-0.2.7+14.04.20140305/tests/script/dbusmenuscript.h0000644000015201777760000000265712305545024024161 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #ifndef DBUSMENUSCRIPT_H #define DBUSMENUSCRITP_H #include #include #include #define SCRIPT_SERVICE_NAME "com.canonical.test" #define SCRIPT_OBJECT_PATH "/com/canonical/test/menuscript" #define SCRIPT_INTERFACE_NAME "com.canonical.test.menuscript" #define MENU_SERVICE_NAME SCRIPT_SERVICE_NAME ".menu" #define MENU_OBJECT_PATH SCRIPT_OBJECT_PATH "/menu" class DBusMenuScript { public: DBusMenuScript(); ~DBusMenuScript(); bool connect(); void quit(); void walk(int steps = 1); void run(); void publishMenu(); void unpublishMenu(); QPair popActivatedAction(); private: QDBusInterface *m_script; }; #endif qmenumodel-0.2.7+14.04.20140305/tests/script/dbusmenuscript.cpp0000644000015201777760000000514212305545024024504 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "dbusmenuscript.h" #include #include #include #define WAIT_TIMEOUT 500 DBusMenuScript::DBusMenuScript() :m_script(0) { } DBusMenuScript::~DBusMenuScript() { quit(); } bool DBusMenuScript::connect() { QTest::qWait(WAIT_TIMEOUT); m_script = new QDBusInterface(SCRIPT_SERVICE_NAME, SCRIPT_OBJECT_PATH, SCRIPT_INTERFACE_NAME, QDBusConnection::sessionBus(), 0); if (m_script && m_script->isValid()) { return true; } else { qWarning() << "DBUS ERROR:" << m_script->lastError().message(); return false; } } void DBusMenuScript::publishMenu() { if (m_script) { m_script->call("publishMenu"); QTest::qWait(WAIT_TIMEOUT); } } void DBusMenuScript::unpublishMenu() { if (m_script) { m_script->call("unpublishMenu"); QTest::qWait(WAIT_TIMEOUT); } } void DBusMenuScript::quit() { if (m_script) { m_script->call("quit"); QTest::qWait(WAIT_TIMEOUT); delete m_script; m_script = 0; } } void DBusMenuScript::walk(int steps) { if (m_script) { m_script->call("walk", steps); QTest::qWait(WAIT_TIMEOUT); } } void DBusMenuScript::run() { if (m_script) { m_script->call("walk", -1); QTest::qWait(WAIT_TIMEOUT); } } QPair DBusMenuScript::popActivatedAction() { if (m_script) { QDBusMessage reply = m_script->call("popActivatedAction"); if (reply.arguments().count() > 0) { QVariant value; QString name = reply.arguments()[0].toString(); if (reply.arguments().count() > 1) { value = reply.arguments()[1]; } return qMakePair(name, value); } } return qMakePair(QString(), QVariant()); } qmenumodel-0.2.7+14.04.20140305/tests/CMakeLists.txt0000644000015201777760000000006412305545024022163 0ustar pbusernogroup00000000000000add_subdirectory(script) add_subdirectory(client) qmenumodel-0.2.7+14.04.20140305/tests/client/0000755000015201777760000000000012305545277020713 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/tests/client/modeltest.cpp0000644000015201777760000001423012305545024023405 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "qdbusmenumodel.h" #include "dbusmenuscript.h" #include #include #include #include extern "C" { #include } class ModelTest : public QObject { Q_OBJECT private: DBusMenuScript m_script; QDBusMenuModel m_model; private Q_SLOTS: void initTestCase() { QVERIFY(m_script.connect()); } void cleanupTestCase() { m_script.quit(); } void init() { m_model.stop(); m_model.setBusType(DBusEnums::SessionBus); m_model.setBusName(MENU_SERVICE_NAME); m_model.setObjectPath(MENU_OBJECT_PATH); } void cleanup() { m_script.unpublishMenu(); } /* * Test if parent function always return a empty QModelIndex */ void testParent() { QCOMPARE(m_model.parent(QModelIndex()), QModelIndex()); } /* * Test if the propety busType handle correct integer values */ void testBusTypeProperty() { m_model.setProperty("busType", 1); QCOMPARE(m_model.busType(), DBusEnums::SessionBus); m_model.setProperty("busType", 2); QCOMPARE(m_model.busType(), DBusEnums::SystemBus); m_model.setProperty("busType", 0); QCOMPARE(m_model.busType(), DBusEnums::SystemBus); m_model.setProperty("busType", 10); QCOMPARE(m_model.busType(), DBusEnums::SystemBus); } /* * Test if model return the correct values for standard properties */ void testData() { // Make menu available m_script.publishMenu(); m_script.run(); // start model m_model.start(); // Wait for dbus sync QTest::qWait(500); QCOMPARE(m_model.status(), DBusEnums::Connected); QCOMPARE(m_model.rowCount(), 4); // Label (String) QVariant label = m_model.data(m_model.index(0, 0), QMenuModel::Label); QVERIFY(label.isValid()); QCOMPARE(label.type(), QVariant::String); QCOMPARE(label.toString(), QString("Menu0")); // Action (String) QVariant action = m_model.data(m_model.index(1, 0), QMenuModel::Action); QVERIFY(action.isValid()); QCOMPARE(action.type(), QVariant::String); QCOMPARE(action.toString(), QString("Menu1Act")); // Wait for menu load (submenus are loaded async) QTest::qWait(500); QCOMPARE(m_model.rowCount(m_model.index(2, 0)), 2); } /* * Test if the model parse correct GVariant values types */ void testExtraData() { // Make menu available m_script.publishMenu(); m_script.run(); // start model m_model.start(); // Wait for dbus sync QTest::qWait(500); QCOMPARE(m_model.status(), DBusEnums::Connected); QCOMPARE(m_model.rowCount(), 4); QVariant e = m_model.data(m_model.index(0, 0), QMenuModel::Extra); QVERIFY(e.isValid()); QVariantMap extra = e.toMap(); // Boolean QVariant v = extra["boolean"]; QCOMPARE(v.type(), QVariant::Bool); QCOMPARE(v.toBool(), true); // Byte v = extra["byte"]; QCOMPARE(v.typeName(), "uchar"); QCOMPARE(v.value(), (uchar)42); // Int16 v = extra["int16"]; QCOMPARE(v.typeName(), "short"); QCOMPARE(v.value(), (short)-42); // UInt16 v = extra["uint16"]; QCOMPARE(v.typeName(), "ushort"); QCOMPARE(v.value(), (ushort)42); // Int32 v = extra["int32"]; QCOMPARE(v.type(), QVariant::Int); QCOMPARE(v.toInt(), -42); // UInt32 v = extra["uint32"]; QCOMPARE(v.type(), QVariant::UInt); QCOMPARE(v.toUInt(), (uint) 42); // Int64 v = extra["int64"]; QCOMPARE(v.type(), QVariant::LongLong); QCOMPARE(v.value(), (long) -42); // UInt64 v = extra["uint64"]; QCOMPARE(v.type(), QVariant::ULongLong); QCOMPARE(v.value(), (ulong) 42); // Double v = extra["double"]; QCOMPARE(v.type(), QVariant::Double); QCOMPARE(v.toDouble(), 42.42); // String v = extra["string"]; QCOMPARE(v.type(), QVariant::String); QCOMPARE(v.toString(), QString("42")); // Map v = extra["map"]; QVariantMap map; map.insert("int64", QVariant::fromValue(-42)); map.insert("string", "42"); map.insert("double", 42.42); QCOMPARE(v.type(), QVariant::Map); QCOMPARE(v.toMap(), map); // Utf8 v = extra["utf8"]; QCOMPARE(v.type(), QVariant::String); QCOMPARE(v.toString(), QString("dança")); // Tuple v = extra["tuple"]; QVariantList lst; lst << "1" << 2 << 3.3; QCOMPARE(v.type(), QVariant::List); QCOMPARE(v.toList(), lst); } /* * Test if model is destroyed without crash */ void testDestroyModel() { // Make menu available m_script.publishMenu(); m_script.run(); // create a new model QDBusMenuModel *model = new QDBusMenuModel(); model->setBusType(DBusEnums::SessionBus); model->setBusName(MENU_SERVICE_NAME); model->setObjectPath(MENU_OBJECT_PATH); model->start(); // Wait for dbus sync QTest::qWait(500); delete model; } }; QTEST_MAIN(ModelTest) #include "modeltest.moc" qmenumodel-0.2.7+14.04.20140305/tests/client/script_modeltest.py0000755000015201777760000000470712305545024024652 0ustar pbusernogroup00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright 2013 Canonical Ltd. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # import time from gi.repository import GLib from menuscript import Script, ActionList, MENU_OBJECT_PATH al = ActionList(MENU_OBJECT_PATH) # create map pmap = {'int64' : GLib.Variant('x', -42), 'string': GLib.Variant('s', '42'), 'double': GLib.Variant('d', 42.42)} al.appendItem("Menu0", "Menu0Act", None, None, {'x-boolean' : GLib.Variant('b', True), 'x-byte' : GLib.Variant('y', 42), 'x-int16' : GLib.Variant('n', -42), 'x-uint16' : GLib.Variant('q', 42), 'x-int32' : GLib.Variant('i', -42), 'x-uint32' : GLib.Variant('u', 42), 'x-int64' : GLib.Variant('x', -42), 'x-uint64' : GLib.Variant('t', 42), 'x-double' : GLib.Variant('d', 42.42), 'x-string' : GLib.Variant('s', '42'), 'x-utf8' : GLib.Variant('s', 'dança'), 'x-map' : GLib.Variant('a{sv}', pmap), 'x-tuple' : GLib.Variant('(sid)', ("1", 2, 3.3)), }) al.appendItem("Menu1", "Menu1Act") al.appendItem("Menu2", "Menu2Act", "section") al.appendItem("Menu2.1", "Menu2.1Act", None, "2") al.appendItem("Menu2.2", "Menu2.2Act", None, "2") al.appendItem("Menu3", "Menu3Act", "submenu") al.appendItem("Menu3.1", "Menu3.1Act", None, "3") al.appendItem("Menu3.2", "Menu3.2Act", None, "3") t = Script.create(al) t.run() qmenumodel-0.2.7+14.04.20140305/tests/client/treetest.cpp0000644000015201777760000000702712305545024023252 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho * Olivier Tilloy */ #include "qmenumodel.h" extern "C" { #include } #include class TestModel : public QMenuModel { Q_OBJECT public: TestModel() : QMenuModel(0) { GMenu *menu5 = g_menu_new(); g_menu_append(menu5, "menu6", NULL); g_menu_append(menu5, "menu7", NULL); GMenu *menu3 = g_menu_new(); g_menu_append(menu3, "menu4", NULL); g_menu_append_section(menu3, "menu5", G_MENU_MODEL(menu5)); g_menu_append(menu3, "menu8", NULL); GMenu *menu = g_menu_new(); g_menu_append(menu, "menu0", NULL); g_menu_append(menu, "menu1", NULL); g_menu_append(menu, "menu2", NULL); g_menu_append_section(menu, "menu3", G_MENU_MODEL(menu3)); setMenuModel(G_MENU_MODEL(menu)); m_menus << menu << menu3 << menu5; } private: QList m_menus; }; class TreeTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { g_type_init(); } void testMenuBuild() { TestModel menu; QCOMPARE(menu.rowCount(), 4); QModelIndex row0 = menu.index(0); QVERIFY(row0.isValid()); QCOMPARE(menu.rowCount(row0), 0); QModelIndex row3 = menu.index(3); QVERIFY(row3.isValid()); QCOMPARE(menu.rowCount(row3), 3); QCOMPARE(menu.data(row3, QMenuModel::Label).toString(), QString("menu3")); QModelIndex row4 = row3.child(0, 0); QVERIFY(row4.isValid()); QCOMPARE(menu.rowCount(row4), 0); QCOMPARE(menu.data(row4, QMenuModel::Depth).toInt(), 1); QCOMPARE(menu.data(row4, QMenuModel::Label).toString(), QString("menu4")); QModelIndex row5 = row3.child(1, 0); QVERIFY(row5.isValid()); QCOMPARE(menu.rowCount(row5), 2); QCOMPARE(menu.data(row5, QMenuModel::Depth).toInt(), 1); QCOMPARE(menu.data(row5, QMenuModel::Label).toString(), QString("menu5")); QModelIndex row6 = row5.child(0, 0); QVERIFY(row6.isValid()); QCOMPARE(menu.rowCount(row6), 0); QCOMPARE(menu.data(row6, QMenuModel::Depth).toInt(), 2); QCOMPARE(menu.data(row6, QMenuModel::Label).toString(), QString("menu6")); QModelIndex row7 = row5.child(1, 0); QVERIFY(row7.isValid()); QCOMPARE(menu.rowCount(row7), 0); QCOMPARE(menu.data(row7, QMenuModel::Depth).toInt(), 2); QCOMPARE(menu.data(row7, QMenuModel::Label).toString(), QString("menu7")); QModelIndex parent_6 = menu.parent(row6); QVERIFY(parent_6.isValid()); QCOMPARE(menu.rowCount(parent_6), 2); QCOMPARE(menu.data(parent_6, QMenuModel::Depth).toInt(), 1); QCOMPARE(menu.data(parent_6, QMenuModel::Label).toString(), QString("menu5")); } }; QTEST_MAIN(TreeTest) #include "treetest.moc" qmenumodel-0.2.7+14.04.20140305/tests/client/loadmodel.qml0000644000015201777760000000273212305545024023360 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ import QtQuick 2.0 import QMenuModel 0.1 Item { id: root width: 100 height: 100 property bool reset: resetModel onResetChanged: { if (reset) { // destroy the current model and check if it will not crash the QML engine view.model.destroy(); } } ListView { id: view anchors.fill: parent delegate: Text { text: label } } Component.onCompleted: { // dynamically create the model to destroy it later var model = Qt.createQmlObject("import QMenuModel 0.1; QDBusMenuModel { id: menuModel; busType: globalBusType; busName: globalBusName; objectPath: globalObjectPath; }", view, ""); model.start(); view.model = model; } } qmenumodel-0.2.7+14.04.20140305/tests/client/actiongrouptest.cpp0000644000015201777760000001245512305545024024646 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "qdbusmenumodel.h" #include "qdbusactiongroup.h" #include "dbusmenuscript.h" #include "qstateaction.h" #include #include #include #include class ActionGroupTest : public QObject { Q_OBJECT private: DBusMenuScript m_script; QDBusMenuModel m_model; QDBusActionGroup m_actionGroup; private Q_SLOTS: void initTestCase() { QVERIFY(m_script.connect()); } void cleanupTestCase() { m_script.quit(); } void init() { m_model.stop(); m_model.setBusType(DBusEnums::SessionBus); m_model.setBusName(MENU_SERVICE_NAME); m_model.setObjectPath(MENU_OBJECT_PATH); m_actionGroup.stop(); m_actionGroup.setBusType(DBusEnums::SessionBus); m_actionGroup.setBusName(MENU_SERVICE_NAME); m_actionGroup.setObjectPath(MENU_OBJECT_PATH); } void cleanup() { m_script.unpublishMenu(); } /* * Test if the propety busType handle correct integer values */ void testBusTypeProperty() { m_actionGroup.setProperty("busType", 1); QCOMPARE(m_actionGroup.busType(), DBusEnums::SessionBus); m_actionGroup.setProperty("busType", 2); QCOMPARE(m_actionGroup.busType(), DBusEnums::SystemBus); m_actionGroup.setProperty("busType", 0); QCOMPARE(m_actionGroup.busType(), DBusEnums::SystemBus); m_actionGroup.setProperty("busType", 10); QCOMPARE(m_actionGroup.busType(), DBusEnums::SystemBus); } /* * Test if QDBusActionGroup change to correct state after DBus * ervice appear */ void testServiceAppear() { m_model.start(); m_actionGroup.start(); QCOMPARE(m_actionGroup.status(), DBusEnums::Connecting); // Make menu available m_script.publishMenu(); QCOMPARE(m_actionGroup.status(), DBusEnums::Connected); } /* * Test if QDBusActionGroup change to correct state after DBus * service disappear */ void testServiceDisappear() { m_model.start(); m_actionGroup.start(); // Make menu available m_script.publishMenu(); QCOMPARE(m_actionGroup.status(), DBusEnums::Connected); // Append menus m_script.walk(2); // Remove menu from dbus m_script.unpublishMenu(); QCOMPARE(m_actionGroup.status(), DBusEnums::Connecting); m_actionGroup.stop(); QCOMPARE(m_actionGroup.status(), DBusEnums::Disconnected); } /* * Test if Action::trigger active the action over DBus */ void testActiveAction() { // start model m_model.start(); m_actionGroup.start(); // Make menu available m_script.publishMenu(); m_script.walk(2); // Get Action QVariant action = m_model.data(m_model.index(1, 0), QMenuModel::Action); QVERIFY(action.isValid()); QStateAction *act = m_actionGroup.action(action.toString()); QVERIFY(act); // test action name QCOMPARE(act->property("name").toString(), QString("Menu1Act")); act->activate(QVariant("42")); // wait for dbus propagation QTest::qWait(500); QPair result = m_script.popActivatedAction(); QCOMPARE(result.first, QString("Menu1Act")); QCOMPARE(result.second.toString(), QString("42")); } /* * Test if Action became invalid after desappear from DBus */ void testRemoveAction() { // start model m_model.start(); m_actionGroup.start(); // Make menu available and append 2 menus m_script.publishMenu(); m_script.walk(2); // Get Action QStateAction *act = m_actionGroup.action(QString("Menu1Act")); QVERIFY(act); QVERIFY(act->isValid()); // Remove 1 menu m_script.walk(1); //Check if action is invalid QVERIFY(!act->isValid()); } /* * Test if Action became valid after service appears */ void testActionIsValid() { // start model m_model.start(); m_actionGroup.start(); // Make menu available and append 2 menus m_script.publishMenu(); // Get invalid Action QStateAction *act = m_actionGroup.action(QString("Menu1Act")); QVERIFY(act); QVERIFY(!act->isValid()); QVERIFY(!act->state().isValid()); // Append menus m_script.walk(2); // Action appear QVERIFY(act->isValid()); } }; QTEST_MAIN(ActionGroupTest) #include "actiongrouptest.moc" qmenumodel-0.2.7+14.04.20140305/tests/client/servicetest.cpp0000644000015201777760000000552012305545024023747 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "qdbusmenumodel.h" #include "dbusmenuscript.h" #include #include #include #include class ServiceTest : public QObject { Q_OBJECT private: DBusMenuScript m_script; QDBusMenuModel m_model; void setupModel(QDBusMenuModel *model) { model->setBusType(DBusEnums::SessionBus); model->setBusName(MENU_SERVICE_NAME); model->setObjectPath(MENU_OBJECT_PATH); } private Q_SLOTS: void initTestCase() { QVERIFY(m_script.connect()); } void cleanupTestCase() { m_script.quit(); } void init() { m_model.stop(); m_model.setBusType(DBusEnums::SessionBus); m_model.setBusName(MENU_SERVICE_NAME); m_model.setObjectPath(MENU_OBJECT_PATH); } void cleanup() { m_script.unpublishMenu(); } void testMenuStartStopWithNoService() { m_model.start(); QCOMPARE(m_model.status(), DBusEnums::Connecting); m_model.stop(); QCOMPARE(m_model.status(), DBusEnums::Disconnected); } void testMenuStartStopWithService() { // Make menu available m_script.publishMenu(); // start model m_model.start(); // Wait for dbus sync QTest::qWait(500); QCOMPARE(m_model.status(), DBusEnums::Connected); // Diconnect model m_model.stop(); QCOMPARE(m_model.status(), DBusEnums::Disconnected); } void testMenuServiceAppearAndDissapear() { m_model.start(); QCOMPARE(m_model.status(), DBusEnums::Connecting); QSignalSpy spy(&m_model, SIGNAL(statusChanged(DBusEnums::ConnectionStatus))); // Make menu available m_script.publishMenu(); // singal changed to connected QCOMPARE(spy.count(), 1); QCOMPARE(m_model.status(), DBusEnums::Connected); // remove menu service m_script.unpublishMenu(); // signal changed to connecting QCOMPARE(spy.count(), 2); QCOMPARE(m_model.status(), DBusEnums::Connecting); } }; QTEST_MAIN(ServiceTest) #include "servicetest.moc" qmenumodel-0.2.7+14.04.20140305/tests/client/script_qmltest.py0000755000015201777760000000154112305545024024334 0ustar pbusernogroup00000000000000#!/usr/bin/env python3 # Copyright 2013 Canonical Ltd. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # import time from menuscript import Script, ActionList, MENU_OBJECT_PATH al = ActionList(MENU_OBJECT_PATH) al.appendItem("Menu0", "Menu0") al.appendItem("Menu1", "Menu1") t = Script.create(al) t.run() qmenumodel-0.2.7+14.04.20140305/tests/client/CMakeLists.txt0000644000015201777760000000420612305545024023443 0ustar pbusernogroup00000000000000macro(declare_test testname) add_executable(${testname} ${testname}.cpp) qt5_use_modules(${testname} Core DBus Widgets Test Qml Quick) target_link_libraries(${testname} qmenumodel dbusmenuscript ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ) if(TEST_XML_OUTPUT) set(TEST_ARGS -p -xunitxml -p -o -p test_${testname}.xml) else() set(TEST_ARGS "") endif() add_test(${testname} ${DBUS_RUNNER} --task ${CMAKE_CURRENT_BINARY_DIR}/${testname} ${TEST_ARGS} --task-name Client --task ${CMAKE_CURRENT_SOURCE_DIR}/script_${testname}.py --task-name Server --ignore-return) set_tests_properties(${testname} PROPERTIES TIMEOUT ${CTEST_TESTING_TIMEOUT} ENVIRONMENT "PYTHONPATH=${TEST_PYTHONPATH};QT_QPA_PLATFORM=minimal") endmacro(declare_test testname) macro(declare_simple_test testname) add_executable(${testname} ${testname}.cpp) qt5_use_modules(${testname} Core Test) target_link_libraries(${testname} qmenumodel ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ) add_test(${testname} ${CMAKE_CURRENT_BINARY_DIR}/${testname}) set_tests_properties(${testname} PROPERTIES TIMEOUT ${CTEST_TESTING_TIMEOUT}) endmacro(declare_simple_test testname) include_directories(${src_SOURCE_DIR} ${dbusmenuscript_SOURCE_DIR} ${GLIB_INCLUDE_DIRS} ) add_definitions(-DTEST_SUITE) set(TEST_PYTHONPATH ${dbusmenuscript_SOURCE_DIR}) if(NOT CTEST_TESTING_TIMEOUT) set(CTEST_TESTING_TIMEOUT 60) endif() declare_test(servicetest) declare_test(menuchangestest) declare_test(modeltest) declare_test(actiongrouptest) declare_test(qmltest) declare_test(convertertest) declare_test(modelsignalstest) declare_test(treetest) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/qmlfiles.h.in ${CMAKE_CURRENT_BINARY_DIR}/qmlfiles.h) qmenumodel-0.2.7+14.04.20140305/tests/client/loadmodel2.qml0000644000015201777760000000206112305545024023435 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ import QtQuick 2.0 import QMenuModel 0.1 Item { width: 100 height: 100 QDBusMenuModel { id: menuModel busType: globalBusType busName: globalBusName objectPath: globalObjectPath } ListView { model: menuModel delegate: Item {} } Component.onCompleted: menuModel.start() } qmenumodel-0.2.7+14.04.20140305/tests/client/qmlfiles.h.in0000644000015201777760000000031312305545024023270 0ustar pbusernogroup00000000000000const char* QML_BASE_DIR = "@libqmenumodel_BINARY_DIR@"; const char* LOADMODEL_QML = "@CMAKE_CURRENT_SOURCE_DIR@/loadmodel.qml"; const char* LOADMODEL2_QML = "@CMAKE_CURRENT_SOURCE_DIR@/loadmodel2.qml"; qmenumodel-0.2.7+14.04.20140305/tests/client/script_servicetest.py0000755000015201777760000000154112305545024025203 0ustar pbusernogroup00000000000000#!/usr/bin/env python3 # Copyright 2013 Canonical Ltd. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # import time from menuscript import Script, ActionList, MENU_OBJECT_PATH al = ActionList(MENU_OBJECT_PATH) al.appendItem("Menu0", "Menu0") al.appendItem("Menu1", "Menu1") t = Script.create(al) t.run() qmenumodel-0.2.7+14.04.20140305/tests/client/script_menuchangestest.py0000755000015201777760000000163712305545024026046 0ustar pbusernogroup00000000000000#!/usr/bin/env python3 # Copyright 2013 Canonical Ltd. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . import time from menuscript import Script, ActionList, MENU_OBJECT_PATH al = ActionList(MENU_OBJECT_PATH) al.appendItem("Menu0", "Menu0") al.appendItem("Menu1", "Menu1") al.removeItem(0) # remove Menu0 al.removeItem(0) # remove Menu1 t = Script.create(al) t.run() qmenumodel-0.2.7+14.04.20140305/tests/client/script_actiongrouptest.py0000755000015201777760000000205512305545024026076 0ustar pbusernogroup00000000000000#!/usr/bin/env python3 # Copyright 2013 Canonical Ltd. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . import time from gi.repository import GLib from menuscript import Script, ActionList, MENU_OBJECT_PATH from gi._gi import variant_type_from_string al = ActionList(MENU_OBJECT_PATH) al.appendItem("Menu0", "Menu0Act", actionStateType=variant_type_from_string('s')) al.appendItem("Menu1", "Menu1Act", actionStateType=variant_type_from_string('s')) al.removeItem("1", "Menu1Act") t = Script.create(al) t.run() qmenumodel-0.2.7+14.04.20140305/tests/client/modelsignalstest.cpp0000644000015201777760000002062512305545024024773 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "qmenumodel.h" #include #include #include extern "C" { #include } class MenuModelTestClass : public QMenuModel { Q_OBJECT public: MenuModelTestClass() : QMenuModel(G_MENU_MODEL(g_menu_new())), m_step(0) { } void loadModel() { GMenu *root = G_MENU(menuModel()); // STEP 0 m_step = 0; GMenu *section = g_menu_new(); g_menu_append(section, "msg1", NULL); g_menu_append_section(root, "section1", G_MENU_MODEL(section)); // STEP 1 m_step++; GMenu *section2 = g_menu_new(); g_menu_append_section(root, "section2", G_MENU_MODEL(section2)); // STEP 2 m_step++; g_menu_append(root, "item1", NULL); // STEP 3 m_step++; g_menu_insert(root, 1, "item2", NULL); } void clear() { GMenu *root = G_MENU(menuModel()); // STEP 0 m_step = 0; g_menu_remove(root, 0); // STEP 1 m_step++; g_menu_remove(root, 2); // STEP 2 m_step++; g_menu_remove(root, 0); // STEP 3 m_step++; g_menu_remove(root, 0); } public Q_SLOTS: void checkModelStateBeforeInsert(const QModelIndex &parent, int start, int end) { if (m_step == 0) { QCOMPARE(rowCount(), 0); QVERIFY(data(index(1), QMenuModel::Label).isNull()); } else if (m_step == 1) { QCOMPARE(rowCount(), 1); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("section1")); QVERIFY(data(index(1), QMenuModel::Label).isNull()); } else if (m_step == 2) { QCOMPARE(rowCount(), 2); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("section1")); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("section2")); QVERIFY(data(index(2), QMenuModel::Label).isNull()); } else if (m_step == 3) { QCOMPARE(rowCount(), 3); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("section1")); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("section2")); QCOMPARE(data(index(2), QMenuModel::Label).toString(), QString("item1")); QVERIFY(data(index(3), QMenuModel::Label).isNull()); } } void checkModelStateAfterInsert(const QModelIndex &parent, int start, int end) { if (m_step == 0) { QCOMPARE(rowCount(), 1); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("section1")); QVERIFY(data(index(1), QMenuModel::Label).isNull()); } else if (m_step == 1) { QCOMPARE(rowCount(), 2); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("section1")); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("section2")); QVERIFY(data(index(2), QMenuModel::Label).isNull()); } else if (m_step == 2) { QCOMPARE(rowCount(), 3); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("section1")); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("section2")); QCOMPARE(data(index(2), QMenuModel::Label).toString(), QString("item1")); QVERIFY(data(index(3), QMenuModel::Label).isNull()); } else if (m_step == 3) { QCOMPARE(rowCount(), 4); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("section1")); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("item2")); QCOMPARE(data(index(2), QMenuModel::Label).toString(), QString("section2")); QCOMPARE(data(index(3), QMenuModel::Label).toString(), QString("item1")); QVERIFY(data(index(4), QMenuModel::Label).isNull()); } } void checkModelStateBeforeRemove(const QModelIndex &parent, int start, int end) { if (m_step == 0) { QCOMPARE(rowCount(), 4); QVERIFY(data(index(0), QMenuModel::Label).isNull()); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("item2")); QCOMPARE(data(index(2), QMenuModel::Label).toString(), QString("section2")); QCOMPARE(data(index(3), QMenuModel::Label).toString(), QString("item1")); QVERIFY(data(index(4), QMenuModel::Label).isNull()); } else if (m_step == 1) { QCOMPARE(rowCount(), 3); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("item2")); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("section2")); QVERIFY(data(index(3), QMenuModel::Label).isNull()); QVERIFY(data(index(4), QMenuModel::Label).isNull()); } else if (m_step == 2) { QCOMPARE(rowCount(), 2); QVERIFY(data(index(0), QMenuModel::Label).isNull()); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("section2")); QVERIFY(data(index(2), QMenuModel::Label).isNull()); } else if (m_step == 3) { QCOMPARE(rowCount(), 1); QVERIFY(data(index(0), QMenuModel::Label).isNull()); QVERIFY(data(index(1), QMenuModel::Label).isNull()); } } void checkModelStateAfterRemove(const QModelIndex &parent, int start, int end) { if (m_step == 0) { QCOMPARE(rowCount(), 3); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("item2")); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("section2")); QCOMPARE(data(index(2), QMenuModel::Label).toString(), QString("item1")); QVERIFY(data(index(3), QMenuModel::Label).isNull()); } else if (m_step == 1) { QCOMPARE(rowCount(), 2); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("item2")); QCOMPARE(data(index(1), QMenuModel::Label).toString(), QString("section2")); QVERIFY(data(index(3), QMenuModel::Label).isNull()); } else if (m_step == 2) { QCOMPARE(rowCount(), 1); QCOMPARE(data(index(0), QMenuModel::Label).toString(), QString("section2")); QVERIFY(data(index(1), QMenuModel::Label).isNull()); } else if (m_step == 3) { QCOMPARE(rowCount(), 0); QVERIFY(data(index(0), QMenuModel::Label).isNull()); } } private: int m_step; }; class ModelSignalsTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { g_type_init(); } /* * Test if the model state still correct before and after insert a new row */ void testSignalInsertRows() { MenuModelTestClass model; QObject::connect(&model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), &model, SLOT(checkModelStateBeforeInsert(QModelIndex,int,int))); QObject::connect(&model, SIGNAL(rowsInserted(QModelIndex,int,int)), &model, SLOT(checkModelStateAfterInsert(QModelIndex,int,int))); model.loadModel(); } /* * Test if the model state still correct before and after remove a row */ void testSignalRemoveRows() { MenuModelTestClass model; model.loadModel(); QObject::connect(&model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), &model, SLOT(checkModelStateBeforeRemove(QModelIndex,int,int))); QObject::connect(&model, SIGNAL(rowsRemoved(QModelIndex,int,int)), &model, SLOT(checkModelStateAfterRemove(QModelIndex,int,int))); model.clear(); } }; QTEST_MAIN(ModelSignalsTest) #include "modelsignalstest.moc" qmenumodel-0.2.7+14.04.20140305/tests/client/cachetest.cpp0000644000015201777760000001353712305545024023361 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho * Olivier Tilloy */ #include "qmenumodel.h" extern "C" { #include } #include class TestModel : public QMenuModel { Q_OBJECT public: TestModel() : QMenuModel(0) { GMenu *menu3 = g_menu_new(); g_menu_append(menu3, "menu4", NULL); g_menu_append(menu3, "menu5", NULL); g_menu_append(menu3, "menu6", NULL); GMenu *menu = g_menu_new(); g_menu_append(menu, "menu0", NULL); g_menu_append(menu, "menu1", NULL); g_menu_append(menu, "menu2", NULL); g_menu_append_section(menu, "menu3", G_MENU_MODEL(menu3)); setMenuModel(G_MENU_MODEL(menu)); m_menus << menu << menu3; } void removeItem(int section, int index) { GMenu *menu = m_menus[section]; g_menu_remove(menu, index); } void insertItem(int section, int index, const QString &label) { GMenu *menu = m_menus[section]; g_menu_insert(menu, index, label.toUtf8().data(), NULL); } QList cacheIndexes() const { QList indexes = cache().keys(); qSort(indexes); return indexes; } private: QList m_menus; }; class CacheTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { g_type_init(); } // Verify that normal menu items are not cached (only sub-menus are) void testCacheContents() { TestModel menu; QVERIFY(menu.cacheIndexes().isEmpty()); menu.data(menu.index(1), QMenuModel::Label); QVERIFY(menu.cacheIndexes().isEmpty()); menu.data(menu.index(2), QMenuModel::Action); QVERIFY(menu.cacheIndexes().isEmpty()); } // Verify that the link attribute always returns the same cached menu void testStaticMenuCache() { TestModel menu; QModelIndex index = menu.index(3); QVariant data = menu.data(index, QMenuModel::LinkSection); QCOMPARE(menu.cacheIndexes(), QList() << 3); QVariant data2 = menu.data(index, QMenuModel::LinkSection); QCOMPARE(menu.cacheIndexes(), QList() << 3); QVERIFY(data.value() == data2.value()); QMenuModel *section = qvariant_cast(data); index = section->index(1); data = menu.data(index, QMenuModel::LinkSection); data2 = menu.data(index, QMenuModel::LinkSection); QCOMPARE(menu.cacheIndexes(), QList() << 3); QVERIFY(data.value() == data2.value()); } // Verify that the cache is correctly updated after inserting a new item void testInsertItems() { TestModel menu; QModelIndex index = menu.index(3); QVariant data = menu.data(index, QMenuModel::LinkSection); QCOMPARE(menu.cacheIndexes(), QList() << 3); menu.insertItem(0, 4, "newMenu"); QCOMPARE(menu.cacheIndexes(), QList() << 3); menu.insertItem(0, 1, "newMenu"); QCOMPARE(menu.cacheIndexes(), QList() << 4); index = menu.index(4); QVariant data2 = menu.data(index, QMenuModel::LinkSection); QCOMPARE(menu.cacheIndexes(), QList() << 4); QVERIFY(data.value() == data2.value()); } // Verify that the cache is correctly updated after removing an item that wasn’t cached void testRemoveNonCachedItem() { TestModel menu; QModelIndex index = menu.index(3); QVariant data = menu.data(index, QMenuModel::LinkSection); QCOMPARE(menu.cacheIndexes(), QList() << 3); menu.removeItem(0, 1); QCOMPARE(menu.cacheIndexes(), QList() << 2); index = menu.index(2); QVariant data2 = menu.data(index, QMenuModel::LinkSection); QCOMPARE(menu.cacheIndexes(), QList() << 2); QVERIFY(data.value() == data2.value()); } // Verify that the cache is correctly updated after removing a cached item void testRemoveCachedItem() { TestModel menu; QModelIndex index = menu.index(3); QVariant data = menu.data(index, QMenuModel::LinkSection); QCOMPARE(menu.cacheIndexes(), QList() << 3); menu.removeItem(0, 3); QVERIFY(menu.cacheIndexes().isEmpty()); } // Verify that the cache is correctly updated after multiple insertions and removals void testMultiplesUpdates() { TestModel menu; QVERIFY(menu.cacheIndexes().isEmpty()); menu.data(menu.index(3), QMenuModel::LinkSection); QCOMPARE(menu.cacheIndexes(), QList() << 3); menu.insertItem(0, 1, "newMenu"); menu.insertItem(0, 2, "newMenu"); menu.insertItem(0, 6, "newMenu"); menu.insertItem(0, 3, "newMenu"); menu.insertItem(0, 7, "newMenu"); QCOMPARE(menu.cacheIndexes(), QList() << 6); menu.removeItem(0, 4); menu.removeItem(0, 6); menu.removeItem(0, 2); QCOMPARE(menu.cacheIndexes(), QList() << 4); menu.removeItem(0, 4); QVERIFY(menu.cacheIndexes().isEmpty()); } }; QTEST_MAIN(CacheTest) #include "cachetest.moc" qmenumodel-0.2.7+14.04.20140305/tests/client/menuchangestest.cpp0000644000015201777760000000375112305545024024610 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "qdbusmenumodel.h" #include "dbusmenuscript.h" #include #include #include #include class MenuChangesTest : public QObject { Q_OBJECT private: DBusMenuScript m_script; QDBusMenuModel m_model; private Q_SLOTS: void initTestCase() { QVERIFY(m_script.connect()); } void cleanupTestCase() { m_script.quit(); } void init() { m_model.stop(); m_model.setBusType(DBusEnums::SessionBus); m_model.setBusName(MENU_SERVICE_NAME); m_model.setObjectPath(MENU_OBJECT_PATH); } void cleanup() { m_script.unpublishMenu(); } /* * Test it the model updates correct after remove or add a new menu */ void testMenuItemAppend() { m_script.publishMenu(); m_model.start(); // Create first Item m_script.walk(); QCOMPARE(m_model.rowCount(), 1); // Create second item m_script.walk(); QCOMPARE(m_model.rowCount(), 2); // Remove item0 m_script.walk(); QCOMPARE(m_model.rowCount(), 1); // Remove item1 m_script.walk(); QCOMPARE(m_model.rowCount(), 0); } }; QTEST_MAIN(MenuChangesTest) #include "menuchangestest.moc" qmenumodel-0.2.7+14.04.20140305/tests/client/qmltest.cpp0000644000015201777760000000612512305545024023102 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ extern "C" { #include } #include "qdbusmenumodel.h" #include "dbusmenuscript.h" #include "qmlfiles.h" #include #include #include #include #include #include #include class QMLTest : public QObject { Q_OBJECT private: DBusMenuScript m_script; private Q_SLOTS: void initTestCase() { QVERIFY(m_script.connect()); } void cleanupTestCase() { m_script.quit(); } void init() { } void cleanup() { m_script.unpublishMenu(); } /* * Test if model is destroyed without crash */ void destroyModel() { m_script.publishMenu(); m_script.run(); QTest::qWait(500); QQuickView *view = new QQuickView; view->engine()->addImportPath(QML_BASE_DIR); view->engine()->rootContext()->setContextProperty("resetModel", QVariant(false)); view->engine()->rootContext()->setContextProperty("globalBusType", DBusEnums::SessionBus); view->engine()->rootContext()->setContextProperty("globalBusName", MENU_SERVICE_NAME); view->engine()->rootContext()->setContextProperty("globalObjectPath", MENU_OBJECT_PATH); view->setSource(QUrl::fromLocalFile(LOADMODEL_QML)); QTest::qWait(500); view->engine()->rootContext()->setContextProperty("resetModel", true); QTest::qWait(500); } /* * Test the menu model disappearing from the bus and reappearing * while the QML application is running. */ void testServiceDisappear() { m_script.publishMenu(); m_script.run(); QTest::qWait(500); QQuickView *view = new QQuickView; view->engine()->addImportPath(QML_BASE_DIR); view->engine()->rootContext()->setContextProperty("globalBusType", DBusEnums::SessionBus); view->engine()->rootContext()->setContextProperty("globalBusName", MENU_SERVICE_NAME); view->engine()->rootContext()->setContextProperty("globalObjectPath", MENU_OBJECT_PATH); view->setSource(QUrl::fromLocalFile(LOADMODEL2_QML)); QTest::qWait(500); m_script.unpublishMenu(); QTest::qWait(500); m_script.publishMenu(); m_script.run(); QTest::qWait(500); delete view; QTest::qWait(1000); } }; QTEST_MAIN(QMLTest) #include "qmltest.moc" qmenumodel-0.2.7+14.04.20140305/tests/client/convertertest.cpp0000644000015201777760000001346512305545024024325 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ extern "C" { #include } #include "converter.h" #include #include #include class ConverterTest : public QObject { Q_OBJECT private: bool compare(const QVariant &qv, const GVariantType *type) { bool result; GVariant *gv = Converter::toGVariant(qv); result = g_variant_type_equal(g_variant_get_type(gv), type); if (!result) { qWarning() << "types are different: QVariant:" << qv.typeName() << "Result:" << (const char*) g_variant_get_type(gv) << "Expected:"<< (const char*) type; } g_variant_unref(gv); return result; } bool compareWithSchema(const QVariant &qv, const QString strType) { GVariantType* expected_type; expected_type = g_variant_type_new(strType.toUtf8().data()); bool result; GVariant *gv = Converter::toGVariantWithSchema(qv, strType.toUtf8().data()); result = g_variant_type_equal(g_variant_get_type(gv), expected_type); if (!result) { qWarning() << "types are different: QVariant:" << qv.typeName() << "Result:" << (const char*) g_variant_get_type(gv) << "Expected:"<< (const char*) expected_type; } g_variant_unref(gv); return result; } private Q_SLOTS: /* * Test converter QVariant to GVariant */ void testToGVariant() { // Boolean QVERIFY(compare(QVariant(true), G_VARIANT_TYPE_BOOLEAN)); // Byte QVERIFY(compare(QVariant::fromValue(42), G_VARIANT_TYPE_BYTE)); // Int16 QVERIFY(compare(QVariant::fromValue(-42), G_VARIANT_TYPE_INT16)); // UInt16 QVERIFY(compare(QVariant::fromValue(-42), G_VARIANT_TYPE_UINT16)); // Int32 QVERIFY(compare(QVariant(-42), G_VARIANT_TYPE_INT32)); // UInt32 QVERIFY(compare(QVariant((uint)42), G_VARIANT_TYPE_UINT32)); // Int64 QVERIFY(compare(QVariant::fromValue(-42), G_VARIANT_TYPE_INT64)); // UInt64 QVERIFY(compare(QVariant::fromValue(42), G_VARIANT_TYPE_UINT64)); // Double QVERIFY(compare(QVariant((double)42.42), G_VARIANT_TYPE_DOUBLE)); // String QVERIFY(compare(QVariant(QString("42")), G_VARIANT_TYPE_STRING)); // ByteArray QVERIFY(compare(QVariant(QByteArray("42")), G_VARIANT_TYPE_BYTESTRING)); // Map QVERIFY(compare(QVariantMap(), G_VARIANT_TYPE_VARDICT)); } void testTupleConversion() { QVariantList qTuple; qTuple << 1 << "2" << 3.3; GVariant *gTuple = Converter::toGVariant(qTuple); QVERIFY(g_variant_type_is_tuple(g_variant_get_type(gTuple))); QCOMPARE(g_variant_n_children(gTuple), (gsize)3); GVariant *v = g_variant_get_child_value(gTuple, 0); int v0 = g_variant_get_int32(v); QCOMPARE(v0, 1); g_variant_unref(v); v = g_variant_get_child_value(gTuple, 1); const gchar *v1 = g_variant_get_string(v, NULL); QCOMPARE(QString(v1), QString("2")); g_variant_unref(v); v = g_variant_get_child_value(gTuple, 2); gdouble v2 = g_variant_get_double(v); QCOMPARE(v2, 3.3); g_variant_unref(v); g_variant_unref(gTuple); } void testSchemaConvert() { // convert to integer compareWithSchema(QVariant::fromValue(1), "i"); compareWithSchema(QVariant::fromValue(1.1), "i"); // convert to integer compareWithSchema(QVariant::fromValue(true), "b"); compareWithSchema(QVariant::fromValue(1), "b"); // convert to double compareWithSchema(QVariant::fromValue(1.0), "d"); compareWithSchema(QVariant::fromValue(1), "d"); // convert to string compareWithSchema(QVariant::fromValue(1), "s"); compareWithSchema(QVariant::fromValue(1.1), "s"); // convert to tuple compareWithSchema(QVariantList() << QVariant::fromValue(true) << QVariant::fromValue(1) << QVariant::fromValue(1) << QVariant::fromValue("test1"), "(bdis)"); // convert to array compareWithSchema(QVariantList() << QVariant::fromValue(1) << QVariant::fromValue(1), "ad"); compareWithSchema(QVariantList() << QVariant::fromValue("test1") << QVariant::fromValue("test2"), "as"); // convert to array of tuple QVariantList si1(QVariantList() << QVariant::fromValue("test1") << QVariant::fromValue(1)); QVariantList si2(QVariantList() << QVariant::fromValue("test1") << QVariant::fromValue(1)); compareWithSchema(QVariantList() << QVariant::fromValue(si1) << QVariant::fromValue(si2), "a(sd)"); // convert to vardict QVariantMap map; map["test1"] = QVariant::fromValue(1); map["test2"] = QVariant::fromValue(1); compareWithSchema(map, "a{sv}"); } }; QTEST_MAIN(ConverterTest) #include "convertertest.moc" qmenumodel-0.2.7+14.04.20140305/CMakeLists.txt0000644000015201777760000000345712305545024021032 0ustar pbusernogroup00000000000000project(qmenumodel) cmake_minimum_required(VERSION 2.8.9) # Standard install paths include(GNUInstallDirs) find_package(Qt5Core REQUIRED) find_package(Qt5Qml REQUIRED) find_package(Qt5Gui REQUIRED) include(FindPkgConfig) pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32) pkg_check_modules(GIO REQUIRED gio-2.0>=2.32) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) add_definitions(-DQT_NO_KEYWORDS) find_program(DBUS_RUNNER dbus-test-runner) # Cooverage tools OPTION(ENABLE_COVERAGE "Build with coverage analysis support" OFF) if(ENABLE_COVERAGE) message(STATUS "Using coverage flags") find_program(COVERAGE_COMMAND gcov) if(NOT COVERAGE_COMMAND) message(FATAL_ERROR "gcov command not found") endif() SET(CMAKE_C_FLAGS "-g -O0 -Wall --coverage") SET(CMAKE_CXX_FLAGS "-g -O0 -Wall --coverage") SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") include(${CMAKE_SOURCE_DIR}/cmake/lcov.cmake) endif() add_subdirectory(libqmenumodel) # Tests Tools OPTION(TEST_XML_OUTPUT "Print test results on xml files" ON) if(NOT DBUS_RUNNER) message(STATUS "dbus-test-runner not found tests disabled.") else() # We need to enable test to create the 'make check' target mandatory on jenkins enable_testing() if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") message(STATUS "Current version of qemu crashes during the tests. We will skip it for now.") else() message(STATUS "Tests enabled for arch: ${CMAKE_SYSTEM_PROCESSOR}") add_subdirectory(tests) endif() endif() # Doc OPTION(GENERATE_DOC "Enable qdoc generation" OFF) if(GENERATE_DOC) message(STATUS "QDoc enabled.") find_program(QDOC_BIN qdoc) if(NOT QDOC_BIN) message(FATAL_ERROR "qdoc command not found") else() add_subdirectory(doc) endif() endif() qmenumodel-0.2.7+14.04.20140305/TODO0000644000015201777760000000060412305545024016751 0ustar pbusernogroup00000000000000= TODO = • Use PIMPLs to clean up the headers • Add a server-side API to allow applications to export their menus on the bus • [optional] Add a ProjectConfig.cmake file to allow other projects using cmake to express a dependency on libqmenumodel without requesting pkgconfig (see http://www.vtk.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file) • … qmenumodel-0.2.7+14.04.20140305/README0000644000015201777760000000235412305545024017145 0ustar pbusernogroup00000000000000QMenuModel - a Qt/QML binding for GMenuModel (see http://developer.gnome.org/gio/unstable/GMenuModel.html) = Building = The build system uses cmake. To compile, simply invoke cmake and then make, e.g.: $ cmake . $ make = Running unit tests = To run the unit tests, you will need dbus-test-runner. If it wasn’t previously installed, install it and then re-run cmake. Then run either of these commands: $ make test - or - $ ctest = Getting code coverage information = To run the unit tests and generate code coverage information, you need to re-run cmake with ENABLE_COVERAGE set to ON and then invoke `make lcov`. This requires lcov to be installed. $ cmake -DENABLE_COVERAGE=ON . $ make lcov This will generate a report (coverage/index.html) which you can view in a browser. = API documentation = To generate API documentation, you need to re-run cmake with GENERATE_DOC set to ON and then invoke `make qdoc`. This requires qdoc3 to be installed. $ cmake -DGENERATE_DOC=ON . $ make qdoc The documentation is generated in the HTML format under doc/html/. = Examples = There are examples of how to use QDBusMenuModel in QML, refer to the README file under the examples/ directory for instructions. qmenumodel-0.2.7+14.04.20140305/doc/0000755000015201777760000000000012305545277017040 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/doc/CMakeLists.txt0000644000015201777760000000064012305545024021566 0ustar pbusernogroup00000000000000set(QMENUMODEL_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/qmenumodel.qdocconf) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/qmenumodel.qdocconf.in" ${QMENUMODEL_DOC_FILE} @ONLY) add_custom_target(qdoc) add_custom_command(TARGET qdoc COMMAND ${QDOC_BIN} ${QMENUMODEL_DOC_FILE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "QDoc running...") qmenumodel-0.2.7+14.04.20140305/doc/qmenumodel.qdocconf.in0000644000015201777760000000033512305545024023320 0ustar pbusernogroup00000000000000project = QMenuModel QML elements sourcedirs = @src_SOURCE_DIR@ sources.fileextensions = "*.cpp" outputdir = html outputformats = HTML version = 0.1 syntaxhighlighting = true sourceencoding = UTF-8 outputencoding = UTF-8 qmenumodel-0.2.7+14.04.20140305/COPYING.LGPL0000644000015201777760000001674312305545024020064 0ustar pbusernogroup00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. qmenumodel-0.2.7+14.04.20140305/examples/0000755000015201777760000000000012305545277020111 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/examples/render-menumodel.qml0000644000015201777760000001153712305545024024063 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Olivier Tilloy */ // This example QML application renders a menu model exposed on the session bus // under the well-known name com.canonical.testmenu and at the object path // /com/canonical/testmenu. import QtQuick 2.0 import QMenuModel 0.1 Item { id: container width: 300 height: 300 QDBusMenuModel { id: menuModel busType: DBus.SessionBus busName: "com.canonical.testmenu" objectPath: "/com/canonical/testmenu" onStatusChanged: { if (status == DBus.Connecting) { view.reset() } } } ListView { id: view property variant __back: [] anchors.left: parent.left anchors.right:parent.right anchors.top: parent.top anchors.bottom: backbutton.top anchors.margins: 10 spacing: 3 model: menuModel delegate: Rectangle { width: parent.width height: 30 radius: 3 color: { if (linkSubMenu == null) return "lightgrey" if (delegatearea.containsMouse) return "steelblue" return "lightsteelblue" } Text { anchors.fill: parent anchors.margins: 5 verticalAlignment: Text.AlignVCenter color: (linkSubMenu == null) ? "grey" : "black" text: { if (linkSubMenu == null) return "%1 (%2)".arg(label).arg(action) else return "submenu" } } MouseArea { id: delegatearea anchors.fill: parent hoverEnabled: true onClicked: { if (linkSubMenu == null) return var newback = view.__back newback.push(view.model) view.__back = newback view.model = linkSubMenu } onEntered: { var text = "" for (var prop in extra) { text += "%1 = %2\n".arg(prop).arg(extra[prop].toString()) } if (text != "") { tooltip.text = text tooltip.visible = true } } onExited: { tooltip.visible = false } onPositionChanged: { var pos = container.mapFromItem(delegatearea, mouse.x, mouse.y) tooltip.x = pos.x + 10 tooltip.y = pos.y + 10 } } } function goback() { var newback = view.__back model = newback[newback.length - 1] newback.pop() view.__back = newback } function reset() { while (view.__back.length > 0) { goback() } } } Rectangle { id: backbutton anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom anchors.margins: 5 radius: 4 height: 50 color: (mousearea.enabled && mousearea.containsMouse) ? "steelblue" : "lightsteelblue" Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: "back" color: mousearea.enabled ? "black" : "grey" } MouseArea { id: mousearea anchors.fill: parent enabled: view.__back.length > 0 hoverEnabled: true onClicked: { view.goback() } } } Rectangle { id: tooltip property alias text: t.text visible: false width: t.width + 10 height: t.height + 10 radius: 4 color: "lightyellow" Text { id: t height: paintedHeight width: paintedWidth x: 5 y: 5 anchors.margins: 4 font.pixelSize: 11 } } Component.onCompleted: menuModel.start() } qmenumodel-0.2.7+14.04.20140305/examples/exportactiongroup.py0000755000015201777760000000502212305545024024247 0ustar pbusernogroup00000000000000#!/usr/bin/env python3 # -*- encoding: utf-8 -*- # # Copyright 2013 Canonical Ltd. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # """ This example script exports an action group on the session bus under the name com.canonical.testactiongroup and at the object path /com/canonical/testactiongroup. """ import sys from gi.repository import Gio from gi.repository import GLib BUS_NAME = 'com.canonical.testactiongroup' BUS_OBJECT_PATH = '/com/canonical/testactiongroup' def action_activated(action, data): name = action.get_name() if action.get_state_type() is None: print('stateless action activated: %s' % name) else: print('stateful action activated: %s (current state: %s)' % (name, action.get_state())) if __name__ == '__main__': bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) # Claim well-known bus name and ensure only one instance of self is running # at any given time. # http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-names proxy = Gio.DBusProxy.new_sync(bus, 0, None, 'org.freedesktop.DBus', '/org/freedesktop/DBus', 'org.freedesktop.DBus', None) result = proxy.RequestName('(su)', BUS_NAME, 0x4) if result != 1 : print >> sys.stderr, ("Name '%s' is already owned on the session bus." "Aborting.") % BUS_NAME sys.exit(1) group = Gio.SimpleActionGroup() foo = Gio.SimpleAction.new('foo', None) group.insert(foo) bar = Gio.SimpleAction.new_stateful('bar', None, GLib.Variant.new_boolean(False)) group.insert(bar) bleh = Gio.SimpleAction.new_stateful('bleh', None, GLib.Variant.new_string('bleh')) group.insert(bleh) for name in group.list_actions(): action = group.lookup_action(name) action.connect('activate', action_activated) bus.export_action_group(BUS_OBJECT_PATH, group) GLib.MainLoop().run() qmenumodel-0.2.7+14.04.20140305/examples/CMakeLists.txt0000644000015201777760000000114212305545024022635 0ustar pbusernogroup00000000000000# Standalone CMakeLists.txt to generate the info-menumodel executable. # This is not built as part of libqmenumodel, it has to be built separately # and it assumes libqmenumodel-dev is installed on the system. cmake_minimum_required(VERSION 2.8.9) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) find_package(Qt5Core REQUIRED) include(FindPkgConfig) pkg_check_modules(QMENUMODEL REQUIRED qmenumodel) add_executable(info-menumodel info-menumodel.cpp) qt5_use_modules(info-menumodel Core) include_directories(${QMENUMODEL_INCLUDE_DIRS}) target_link_libraries(info-menumodel ${QMENUMODEL_LDFLAGS}) qmenumodel-0.2.7+14.04.20140305/examples/README0000644000015201777760000000142612305545024020762 0ustar pbusernogroup00000000000000This directory contains examples that demonstrate how to use the QMenuModel binding in Qt and QML applications. To export an example menu model on the bus, run 'exportmenu.py'. To render this menu in a QML application, run 'render-menumodel.qml' in qmlscene. You will need to inform qmlscene of the location of the QMenuModel plugin if it’s not installed system-wide, e.g.: $ qmlscene -I libqmenumodel examples/render-menumodel.qml To compile a C++ executable that uses libqmenumodel to monitor and print information about the exported menu, run `cmake` and then `make` from this directory. This assumes that libqmenumodel-dev is installed on the system (it won’t work with a local copy). Then, run the executable generated: $ cmake . $ make $ ./info-menumodel qmenumodel-0.2.7+14.04.20140305/examples/unityqmlmenumodel.qml0000644000015201777760000000717612305545024024415 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: Lars Uebernickel */ import QtQuick 2.0 import QMenuModel 0.1 Item { width: 400; height: 500; UnityMenuModel { id: menu busName: "com.canonical.indicator.sound" actions: { "indicator": "/com/canonical/indicator/sound" } menuObjectPath: "/com/canonical/indicator/sound/desktop" } ListView { id: listview anchors.fill: parent anchors.margins: 10 spacing: 3 model: menu delegate: Loader { sourceComponent: { if (isSeparator) { return separator; } else if (type == "com.canonical.unity.slider") { listview.model.loadExtendedAttributes(index, {'min-icon': 'icon', 'max-icon': 'icon'}); return slider; } else { return menuitem; } } Component { id: separator Rectangle { width: listview.width height: 4 color: "blue" } } Component { id: slider Rectangle { width: listview.width color: "#ddd" height: 40 Row { anchors.fill: parent Image { source: ext.minIcon } Text { text: model.actionState } Image { source: ext.maxIcon } } } } Component { id: menuitem Rectangle { width: listview.width height: 40 color: "#ddd" Row { anchors.fill: parent anchors.margins: 5 Image { source: icon } Text { height: parent.height verticalAlignment: Text.AlignVCenter color: sensitive ? "black" : "#aaa"; text: label } } MouseArea { anchors.fill: parent onClicked: { var submenu = listview.model.submenu(index); if (submenu) listview.model = submenu; else action.activate(); } } } } } } } qmenumodel-0.2.7+14.04.20140305/examples/exportmenu.py0000755000015201777760000000501312305545024022661 0ustar pbusernogroup00000000000000#!/usr/bin/env python3 # -*- encoding: utf-8 -*- # # Copyright 2013 Canonical Ltd. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # """ This example script exports a menu model on the session bus under the name com.canonical.testmenu and at the object path /com/canonical/testmenu. The menu model contains items that have attributes with custom values, as well as sub-menus. """ import sys from gi.repository import Gio from gi.repository import GLib BUS_NAME = 'com.canonical.testmenu' BUS_OBJECT_PATH = '/com/canonical/testmenu' def bus_acquired(bus, name): menu = Gio.Menu() foo = Gio.MenuItem.new('foo', 'app.foo') foo.set_attribute_value('x-additionaltext', GLib.Variant.new_string('lorem ipsum')) foo.set_attribute_value('x-enabled', GLib.Variant.new_boolean(True)) menu.append_item(foo) bar = Gio.MenuItem.new('bar', 'bar') bar.set_attribute_value('x-defaultvalue', GLib.Variant.new_string('Hello World!')) bar.set_attribute_value('x-canonical-currentvalue', GLib.Variant.new_string('awesome')) bar.set_attribute_value('x-velocity', GLib.Variant.new_uint64(83374)) menu.append_item(bar) menu.append('bleh', 'app.bleh') submenu = Gio.Menu() submenu.append('submenu A', 'app.suba') submenu2 = Gio.Menu() submenu2.append('submenu2 A', 'app.sub2a') submenu2.append('submenu2 B', 'app.sub2b') submenu2.append('submenu2 C', 'app.sub2c') submenu.append_submenu('submenu submenu', submenu2) submenu.append('submenu C', 'app.subc') menu.append_submenu('submenu', submenu) menu.append('baz', 'app.baz') bus.export_menu_model(BUS_OBJECT_PATH, menu) actions = Gio.SimpleActionGroup.new() actions.add_action(Gio.SimpleAction.new("bar", None)) bus.export_action_group(BUS_OBJECT_PATH, actions) if __name__ == '__main__': Gio.bus_own_name(Gio.BusType.SESSION, BUS_NAME, 0, bus_acquired, None, None) GLib.MainLoop().run() qmenumodel-0.2.7+14.04.20140305/examples/info-menumodel.cpp0000644000015201777760000000635112305545024023526 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Olivier Tilloy */ /* * Example executable that links against libqmenumodel to monitor * and print information about a menu model exported on D-Bus. */ // QMenuModel #include "qmenumodel/qdbusmenumodel.h" // stdlib #include // Qt #include #include #define BUS_NAME "com.canonical.testmenu" #define BUS_OBJECT_PATH "/com/canonical/testmenu" class MenuModelMonitor : public QDBusMenuModel { Q_OBJECT public: MenuModelMonitor(QObject* parent=0) : QDBusMenuModel(parent) { setProperty("busType", DBusEnums::SessionBus); setProperty("busName", BUS_NAME); setProperty("objectPath", BUS_OBJECT_PATH); QObject::connect(this, SIGNAL(statusChanged(DBusEnums::ConnectionStatus)), SLOT(onStatusChanged(DBusEnums::ConnectionStatus))); QObject::connect(this, SIGNAL(rowsInserted(const QModelIndex&, int, int)), SLOT(onModelChanged())); QObject::connect(this, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), SLOT(onModelChanged())); std::cout << "Monitoring menu model " << property("objectPath").toString().toUtf8().constData() << " on the well-known name " << property("busName").toString().toUtf8().constData() << std::endl; } private Q_SLOTS: void onStatusChanged(DBusEnums::ConnectionStatus status) { std::cout << "Status of menu model changed to " << status << std::endl; if (status == DBusEnums::Connected) { printModel(this); } } void onModelChanged() { printModel(this); } private: void printModel(QMenuModel* model, int indent=0) { int count = model->rowCount(); for (int i = 0; i < count; ++i) { QModelIndex index = model->index(i, 0); QString label = model->data(index, QMenuModel::Label).toString(); QVariant submenu = model->data(index, QMenuModel::LinkSubMenu); for (int j = 0; j < indent * 2; ++j) std::cout << " "; std::cout << " > " << label.toUtf8().constData() << std::endl; if (submenu.isValid()) { printModel(qobject_cast(submenu.value()), indent + 1); } } } }; #include "info-menumodel.moc" int main(int argc, char** argv) { MenuModelMonitor monitor; monitor.start(); int result = QCoreApplication(argc, argv).exec(); monitor.stop(); return result; } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/0000755000015201777760000000000012305545277021130 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/libqmenumodel/CMakeLists.txt0000644000015201777760000000011312305545024023651 0ustar pbusernogroup00000000000000project(libqmenumodel) add_subdirectory(src) add_subdirectory(QMenuModel) qmenumodel-0.2.7+14.04.20140305/libqmenumodel/QMenuModel/0000755000015201777760000000000012305545277023136 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/libqmenumodel/QMenuModel/plugin.h0000644000015201777760000000205112305545024024571 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #ifndef QMENUMODELQMLPLUGIN_H #define QMENUMODELQMLPLUGIN_H #include class QMenuModelQmlPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "com.canonical.qmenumodel") public: void initializeEngine(QQmlEngine *engine, const char *uri); void registerTypes(const char *uri); }; #endif qmenumodel-0.2.7+14.04.20140305/libqmenumodel/QMenuModel/CMakeLists.txt0000644000015201777760000000152112305545024025663 0ustar pbusernogroup00000000000000project(qmlplugin) set(QMLPLUGIN_SRC plugin.cpp ) add_library(qmenumodel-qml MODULE ${QMLPLUGIN_SRC} ) include_directories( ${src_SOURCE_DIR} ${GLIB_INCLUDE_DIRS} ) target_link_libraries(qmenumodel-qml qmenumodel ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ) qt5_use_modules(qmenumodel-qml Qml Quick) execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" "${CMAKE_CURRENT_BINARY_DIR}/qmldir") execute_process( COMMAND qmake -query QT_INSTALL_QML OUTPUT_VARIABLE QT_IMPORTS_DIR OUTPUT_STRIP_TRAILING_WHITESPACE ) set(QMLPLUGIN_INSTALL_PREFIX "${QT_IMPORTS_DIR}/QMenuModel") install(TARGETS qmenumodel-qml DESTINATION ${QMLPLUGIN_INSTALL_PREFIX}) install(FILES qmldir DESTINATION ${QMLPLUGIN_INSTALL_PREFIX}) qmenumodel-0.2.7+14.04.20140305/libqmenumodel/QMenuModel/qmldir0000644000015201777760000000005112305545024024333 0ustar pbusernogroup00000000000000module QMenuModel plugin qmenumodel-qml qmenumodel-0.2.7+14.04.20140305/libqmenumodel/QMenuModel/plugin.cpp0000644000015201777760000000340212305545024025125 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "plugin.h" #include "qmenumodel.h" #include "qdbusmenumodel.h" #include "qdbusactiongroup.h" #include "qstateaction.h" #include "unitymenuaction.h" #include "unitymenumodel.h" #include void QMenuModelQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri) { } void QMenuModelQmlPlugin::registerTypes(const char *uri) { qmlRegisterUncreatableType(uri, 0, 1, "QMenuModel", "QMenuModel is a interface"); qmlRegisterUncreatableType(uri, 0, 1, "QStateAction", "QStateAction must be created by QDBusActionGroup::action"); qmlRegisterUncreatableType(uri, 0, 1, "DBus", "DBus is only a namespace"); qmlRegisterType(uri, 0, 1, "QDBusMenuModel"); qmlRegisterType(uri, 0, 1, "QDBusActionGroup"); qmlRegisterType(uri, 0, 1, "UnityMenuModel"); qmlRegisterType(uri, 0, 1, "UnityMenuAction"); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/0000755000015201777760000000000012305545277021717 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qdbusactiongroup.cpp0000644000015201777760000001706512305545024026013 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "qdbusactiongroup.h" #include "qstateaction.h" #include "converter.h" #include "qmenumodelevents.h" // Qt #include extern "C" { #include #include } /*! \qmltype QDBusActionGroup \inherits QDBusObject \brief A DBusActionGroup implementation to be used with \l QDBusMenuModel \b {This component is under heavy development.} This class can be used as a proxy for an action group that is exported over D-Bus \code QDBusActionGroup { id: actionGroup busType: 1 busName: "com.ubuntu.menu" objectPath: "com/ubuntu/menu/actions" } Button { onClicked: actionGroup.getAction("app.quit").trigger() } \endcode */ /*! \internal */ QDBusActionGroup::QDBusActionGroup(QObject *parent) :QObject(parent), QDBusObject(this), m_actionGroup(NULL) { } /*! \internal */ QDBusActionGroup::~QDBusActionGroup() { clear(); } /*! \qmlmethod QDBusActionGroup::action(QString name) Look for a action with the same name and return a \l QStateAction object. \b Note: methods should only be called after the Component has completed. */ QStateAction *QDBusActionGroup::action(const QString &name) { QStateAction *act = actionImpl(name); if (act == 0) { act = new QStateAction(this, name); } return act; } QVariant QDBusActionGroup::actionState(const QString &name) { QVariant result; GVariant *state = g_action_group_get_action_state(m_actionGroup, name.toUtf8().data()); result = Converter::toQVariant(state); if (state) { g_variant_unref(state); } return result; } bool QDBusActionGroup::hasAction(const QString &name) { if (m_actionGroup) { return g_action_group_has_action(m_actionGroup, name.toUtf8().data()); } else { return false; } } QStateAction *QDBusActionGroup::actionImpl(const QString &name) { Q_FOREACH(QStateAction *act, this->findChildren()) { if (act->name() == name) { return act; } } return 0; } /*! \internal */ void QDBusActionGroup::serviceVanish(GDBusConnection *) { setActionGroup(NULL); } /*! \internal */ void QDBusActionGroup::serviceAppear(GDBusConnection *connection) { GDBusActionGroup *ag = g_dbus_action_group_get(connection, busName().toUtf8().data(), objectPath().toUtf8().data()); setActionGroup(ag); if (ag == NULL) { stop(); } } /*! \internal */ void QDBusActionGroup::start() { QDBusObject::connect(); } /*! \internal */ void QDBusActionGroup::stop() { QDBusObject::disconnect(); } /*! \internal */ void QDBusActionGroup::setIntBusType(int busType) { if ((busType > DBusEnums::None) && (busType < DBusEnums::LastBusType)) { setBusType(static_cast(busType)); } } /*! \internal */ void QDBusActionGroup::setActionGroup(GDBusActionGroup *ag) { if (m_actionGroup == reinterpret_cast(ag)) { return; } if (m_actionGroup) { g_signal_handler_disconnect(m_actionGroup, m_signalActionAddId); g_signal_handler_disconnect(m_actionGroup, m_signalActionRemovedId); g_signal_handler_disconnect(m_actionGroup, m_signalStateChangedId); m_signalActionAddId = m_signalActionRemovedId = m_signalStateChangedId = 0; clear(); } m_actionGroup = reinterpret_cast(ag); if (m_actionGroup) { m_signalActionAddId = g_signal_connect(m_actionGroup, "action-added", G_CALLBACK(QDBusActionGroup::onActionAdded), this); m_signalActionRemovedId = g_signal_connect(m_actionGroup, "action-removed", G_CALLBACK(QDBusActionGroup::onActionRemoved), this); m_signalStateChangedId = g_signal_connect(m_actionGroup, "action-state-changed", G_CALLBACK(QDBusActionGroup::onActionStateChanged), this); gchar **actions = g_action_group_list_actions(m_actionGroup); for(guint i=0; i < g_strv_length(actions); i++) { DBusActionVisiblityEvent dave(actions[i], true); QCoreApplication::sendEvent(this, &dave); } g_strfreev(actions); } } /*! \internal */ void QDBusActionGroup::clear() { Q_FOREACH(QStateAction *act, this->findChildren()) { Q_EMIT actionVanish(act->name()); } if (m_actionGroup != NULL) { g_object_unref(m_actionGroup); m_actionGroup = NULL; } } /*! \internal */ void QDBusActionGroup::updateActionState(const QString &name, const QVariant &state) { if (m_actionGroup != NULL) { g_action_group_change_action_state(m_actionGroup, name.toUtf8().data(), Converter::toGVariant(state)); } } void QDBusActionGroup::activateAction(const QString &name, const QVariant ¶meter) { if (m_actionGroup != NULL) { g_action_group_activate_action(m_actionGroup, name.toUtf8().data(), Converter::toGVariant(parameter)); } } bool QDBusActionGroup::event(QEvent* e) { if (QDBusObject::event(e)) { return true; } else if (e->type() == DBusActionVisiblityEvent::eventType) { DBusActionVisiblityEvent *dave = static_cast(e); if (dave->visible) { Q_EMIT actionAppear(dave->name); } else { Q_EMIT actionVanish(dave->name); } } else if (e->type() == DBusActionStateEvent::eventType) { DBusActionStateEvent *dase = static_cast(e); Q_EMIT actionStateChanged(dase->name, dase->state); } return QObject::event(e); } /*! \internal */ void QDBusActionGroup::onActionAdded(GDBusActionGroup *, gchar *name, gpointer data) { QDBusActionGroup *self = reinterpret_cast(data); DBusActionVisiblityEvent dave(name, true); QCoreApplication::sendEvent(self, &dave); } /*! \internal */ void QDBusActionGroup::onActionRemoved(GDBusActionGroup *, gchar *name, gpointer data) { QDBusActionGroup *self = reinterpret_cast(data); DBusActionVisiblityEvent dave(name, false); QCoreApplication::sendEvent(self, &dave); } /*! \internal */ void QDBusActionGroup::onActionStateChanged(GDBusActionGroup *, gchar *name, GVariant *value, gpointer data) { QDBusActionGroup *self = reinterpret_cast(data); DBusActionStateEvent dase(name, Converter::toQVariant(value)); QCoreApplication::sendEvent(self, &dase); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/unitymenumodelevents.h0000644000015201777760000000345612305545024026371 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Nicholas Dedekind typedef struct _GtkMenuTrackerItem GtkMenuTrackerItem; /* Event for a unitymenumodel clear */ class UnityMenuModelClearEvent : public QEvent { public: static const QEvent::Type eventType; UnityMenuModelClearEvent(bool reset); bool reset; }; /* Event for a row add for unitymenumodel */ class UnityMenuModelAddRowEvent : public QEvent { public: static const QEvent::Type eventType; UnityMenuModelAddRowEvent(GtkMenuTrackerItem *item, int position); ~UnityMenuModelAddRowEvent(); GtkMenuTrackerItem *item; int position; }; /* Event for a row remove for unitymenumodel */ class UnityMenuModelRemoveRowEvent : public QEvent { public: static const QEvent::Type eventType; UnityMenuModelRemoveRowEvent(int position); int position; }; /* Event for a row data change for unitymenumodel */ class UnityMenuModelDataChangeEvent : public QEvent { public: static const QEvent::Type eventType; UnityMenuModelDataChangeEvent(int position); int position; }; #endif //UNITYMENUMODELEVENTS_H qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/unitymenuactionevents.cpp0000644000015201777760000000351612305545024027076 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Nicholas Dedekind (QEvent::registerEventType()); const QEvent::Type UnityMenuActionRemoveEvent::eventType = static_cast(QEvent::registerEventType()); const QEvent::Type UnityMenuActionEnabledChangedEvent::eventType = static_cast(QEvent::registerEventType()); const QEvent::Type UnityMenuActionStateChangeEvent::eventType = static_cast(QEvent::registerEventType()); UnityMenuActionAddEvent::UnityMenuActionAddEvent(bool _enabled, const QVariant& _state) : QEvent(UnityMenuActionAddEvent::eventType), enabled(_enabled), state(_state) {} UnityMenuActionRemoveEvent::UnityMenuActionRemoveEvent() : QEvent(UnityMenuActionRemoveEvent::eventType) { } UnityMenuActionEnabledChangedEvent::UnityMenuActionEnabledChangedEvent(bool _enabled) : QEvent(UnityMenuActionEnabledChangedEvent::eventType), enabled(_enabled) {} UnityMenuActionStateChangeEvent::UnityMenuActionStateChangeEvent(const QVariant& _state) : QEvent(UnityMenuActionStateChangeEvent::eventType), state(_state) {} qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/menunode.cpp0000644000015201777760000001375412305545024024235 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "menunode.h" #include "qmenumodelevents.h" #include #include #include MenuNode::MenuNode(const QString &linkType, GMenuModel *model, MenuNode *parent, int pos, QObject *listener) : m_model(model), m_parent(parent), m_signalChangedId(0), m_linkType(linkType), m_currentOpPosition(-1), m_currentOpAdded(0), m_currentOpRemoved(0) { g_object_ref(model); if (m_parent) { m_parent->insertChild(this, pos); } m_size = g_menu_model_get_n_items(model); for(int i=0; i < m_size; i++) { MenuNode::create(model, i, this, listener); } connect(listener); } MenuNode::~MenuNode() { disconnect(); Q_FOREACH(MenuNode *child, m_children) { delete child; } m_children.clear(); if (m_model) { g_object_unref(m_model); } } void MenuNode::connect(QObject *listener) { m_listener = listener; if (m_model && (m_signalChangedId == 0)) { m_signalChangedId = g_signal_connect(m_model, "items-changed", G_CALLBACK(MenuNode::onItemsChanged), this); } } void MenuNode::disconnect() { if (m_signalChangedId != 0) { g_signal_handler_disconnect(m_model, m_signalChangedId); } } int MenuNode::position() const { if (m_parent) { return m_parent->childPosition(this); } else { return 0; } } MenuNode *MenuNode::parent() const { return m_parent; } GMenuModel *MenuNode::model() const { return m_model; } QString MenuNode::linkType() const { return m_linkType; } MenuNode *MenuNode::child(int pos) const { if (m_children.contains(pos)) { return m_children.value(pos); } return 0; } int MenuNode::childPosition(GMenuModel *item) const { QMap::const_iterator i = m_children.constBegin(); while (i != m_children.constEnd()) { if (i.value()->m_model == item) { return i.key(); } ++i; } return 0; } int MenuNode::childPosition(const MenuNode *item) const { return childPosition(item->m_model); } int MenuNode::size() const { return m_size; } int MenuNode::depth() const { int depth = 0; const MenuNode *child = this; while(child->parent()) { depth++; child = child->parent(); } return depth; } int MenuNode::realPosition(int row) const { int result = row; if ((row >= 0) && (row < m_size)) { if (row >= m_currentOpPosition) { if ((m_currentOpRemoved > 0) && (row < (m_currentOpPosition + m_currentOpRemoved))) { result = -1; } else { result += (m_currentOpAdded - m_currentOpRemoved); } } return result; } else { return -1; } } void MenuNode::change(int start, int added, int removed) { if (added > 0) { for (int i=(m_size - 1 + added), iMin=start; i >= iMin; i--) { if (m_children.contains(i)) { m_children.insert(i + added, m_children.take(i)); } } m_size += added; for (int i = start; i < (start + added); i++) { MenuNode::create(m_model, i, this, m_listener); } } if (removed > 0) { int removedEnd = start + removed; for (int i=start, iMax=m_size; i < iMax; i++) { if (i <= removedEnd) { delete m_children.take(i); } else if (m_children.contains(i)) { m_children.insert(i - removed, m_children.take(i)); } } m_size -= removed; } } void MenuNode::insertChild(MenuNode *child, int pos) { if (m_children.contains(pos)) { qWarning() << "Section conflic: parent" << this << "child" << child << "pos" << pos; return; } child->m_parent = this; m_children.insert(pos, child); } MenuNode *MenuNode::find(GMenuModel *item) { if (m_model == item) { return this; } Q_FOREACH(MenuNode *child, m_children) { MenuNode *found = child->find(item); if (found) { return found; } } return 0; } MenuNode *MenuNode::create(GMenuModel *model, int pos, MenuNode *parent, QObject *listener) { QString linkType(G_MENU_LINK_SUBMENU); GMenuModel *link = g_menu_model_get_item_link(model, pos, G_MENU_LINK_SUBMENU); if (link == NULL) { linkType = G_MENU_LINK_SECTION; link = g_menu_model_get_item_link(model, pos, G_MENU_LINK_SECTION); } if (link) { return new MenuNode(linkType, link, parent, pos, listener); } return 0; } void MenuNode::commitOperation() { change(m_currentOpPosition, m_currentOpAdded, m_currentOpRemoved); m_currentOpPosition = -1; m_currentOpAdded = m_currentOpRemoved = 0; } void MenuNode::onItemsChanged(GMenuModel *model, gint position, gint removed, gint added, gpointer data) { MenuNode *self = reinterpret_cast(data); self->m_currentOpPosition = position; self->m_currentOpAdded = added; self->m_currentOpRemoved = removed; MenuNodeItemChangeEvent mnice(self, position, added, removed); QCoreApplication::sendEvent(self->m_listener, &mnice); self->commitOperation(); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qdbusmenumodel.cpp0000644000015201777760000000632012305545024025436 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ extern "C" { #include } #include "qdbusmenumodel.h" #include "qmenumodelevents.h" #include /*! \qmltype QDBusMenuModel \inherits QDBusObject \brief The QDBusMenuModel class defines the list model for DBus menus \b {This component is under heavy development.} This class expose the menu previous exported over DBus. \code QDBusMenuModel { id: menuModel busType: 1 busName: "com.ubuntu.menu" objectPath: "com/ubuntu/menu" } ListView { id: view model: menuModel Component.onCompleted: menuModel.start() } \endcode */ QDBusMenuModel::QDBusMenuModel(QObject *parent) : QMenuModel(0, parent), QDBusObject(this) { } /*! \internal */ QDBusMenuModel::~QDBusMenuModel() { } /*! \qmlmethod QDBusMenuModel::start() Start dbus watch for the busName and wait until it appears. The status will change to connecting after call this function, and as soon the busName apperas and the objectPat was found this will change to Connected. \b Note: methods should only be called after the Component has completed. */ void QDBusMenuModel::start() { QDBusObject::connect(); } /*! \qmlmethod QDBusMenuModel::stop() Stops dbus watch and clear the model, the status wil change to Disconnected. \b Note: methods should only be called after the Component has completed. */ void QDBusMenuModel::stop() { QDBusObject::disconnect(); MenuModelEvent mme(NULL); QCoreApplication::sendEvent(this, &mme); } bool QDBusMenuModel::event(QEvent* e) { if (QDBusObject::event(e)) { return true; } return QMenuModel::event(e); } /*! \internal */ void QDBusMenuModel::serviceVanish(GDBusConnection *) { MenuModelEvent mme(NULL); QCoreApplication::sendEvent(this, &mme); } /*! \internal */ void QDBusMenuModel::serviceAppear(GDBusConnection *connection) { GMenuModel *model = G_MENU_MODEL(g_dbus_menu_model_get(connection, busName().toUtf8().data(), objectPath().toUtf8().data())); MenuModelEvent mme(model); QCoreApplication::sendEvent(this, &mme); //event handling takes care of the ref g_object_unref(model); } /*! \internal */ void QDBusMenuModel::setIntBusType(int busType) { if ((busType > DBusEnums::None) && (busType < DBusEnums::LastBusType)) { setBusType(static_cast(busType)); } } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qstateaction.cpp0000644000015201777760000000776112305545024025123 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #include "qstateaction.h" #include "qdbusactiongroup.h" /*! \qmltype QStateAction \inherits QAction \brief A QStateAction implementation to be used with \l QDBusActionGroup \b {This component is under heavy development.} This class can be used as a proxy for an action that is exported over D-Bus \code QDBusActionGroup { id: actionGroup busType: 1 busName: "com.ubuntu.menu" objectPath: "com/ubuntu/menu/actions" } Button { visible: actionGroup.getAction("button.bvisible").status } \endcode */ /*! \internal */ QStateAction::QStateAction(QDBusActionGroup *group, const QString &name) : QObject(group), m_group(group), m_name(name) { // This keep the code clean // But maybe we need move the action state control to QActionGroup to optimizations QObject::connect(m_group, SIGNAL(actionAppear(QString)), this, SLOT(onActionAppear(QString))); QObject::connect(m_group, SIGNAL(actionVanish(QString)), this, SLOT(onActionVanish(QString))); QObject::connect(m_group, SIGNAL(actionStateChanged(QString,QVariant)), this, SLOT(onActionStateChanged(QString,QVariant))); m_valid = m_group->hasAction(name); if (m_valid) { setState(m_group->actionState(name)); } } /*! \qmlproperty int QStateAction::state This property holds the current action state */ QVariant QStateAction::state() const { return m_state; } /*! \qmlproperty int QStateAction::isValid This property return if the current Action is valid or not A valid Action is a action which has a DBus action linked */ bool QStateAction::isValid() const { return m_valid; } /*! Request for the state of action to be changed to \a paramenter. This call merely requests a change. The action may refuse to change its state or may change its state to something other than \a paramenter. */ void QStateAction::updateState(const QVariant &state) { QVariant v = state; if (v.convert(m_state.type())) m_group->updateActionState(m_name, v); } /*! Activates the action passing \a parameter. \a parameter must be the correct type of parameter for the action */ void QStateAction::activate(const QVariant ¶meter) { m_group->activateAction(m_name, parameter); } /*! \internal */ QString QStateAction::name() const { return m_name; } /*! \internal */ void QStateAction::setValid(bool valid) { if (m_valid != valid) { m_valid = valid; Q_EMIT validChanged(m_valid); } } /*! \internal */ void QStateAction::setState(const QVariant &state) { QVariant v = state; if (!m_state.isValid() || (v.convert(m_state.type()) && v != m_state)) { m_state = v; Q_EMIT stateChanged(m_state); } } /*! \internal */ void QStateAction::onActionAppear(const QString &name) { if (m_name == name) { setState(m_group->actionState(name)); setValid(true); } } /*! \internal */ void QStateAction::onActionVanish(const QString &name) { if (m_name == name) { setState(QVariant()); setValid(false); } } /*! \internal */ void QStateAction::onActionStateChanged(const QString &name, const QVariant &state) { if (m_name == name) { setState(state); } } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qmenumodelevents.h0000644000015201777760000000457312305545024025462 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Nicholas Dedekind #include class MenuNode; typedef struct _GDBusConnection GDBusConnection; typedef struct _GMenuModel GMenuModel; /* Event for a connection update for a dbus object */ class DbusObjectServiceEvent : public QEvent { public: static const QEvent::Type eventType; DbusObjectServiceEvent(GDBusConnection* connection, bool visible); ~DbusObjectServiceEvent(); GDBusConnection* connection; bool visible; }; /* Event for an update to the gmenumodel */ class MenuModelEvent : public QEvent { public: static const QEvent::Type eventType; MenuModelEvent(GMenuModel *model); ~MenuModelEvent(); GMenuModel *model; }; /* Event for a GAction (base) */ class DBusActionEvent : public QEvent { public: QString name; protected: DBusActionEvent(const QString& name, QEvent::Type type); }; /* Event for a GAction add/remove */ class DBusActionVisiblityEvent : public DBusActionEvent { public: static const QEvent::Type eventType; DBusActionVisiblityEvent(const QString& name, bool visible); bool visible; }; /* Event for a GAction state value update */ class DBusActionStateEvent : public DBusActionEvent { public: static const QEvent::Type eventType; DBusActionStateEvent(const QString& name, const QVariant& state); QVariant state; }; /* Event for changing gmenumodel entries */ class MenuNodeItemChangeEvent : public QEvent { public: static const QEvent::Type eventType; MenuNodeItemChangeEvent(MenuNode* node, int position, int removed, int added); MenuNode* node; int position; int removed; int added; }; #endif //QMENUMODELEVENTS_H qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qmenumodel.h0000644000015201777760000000427512305545024024234 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #ifndef QMENUTREEMODEL_H #define QMENUTREEMODEL_H #include class MenuNode; typedef struct _GMenuModel GMenuModel; class QMenuModel : public QAbstractItemModel { Q_OBJECT public: enum MenuRoles { Action = Qt::DisplayRole + 1, Label, Extra, Depth, hasSection, hasSubMenu }; ~QMenuModel(); /* QAbstractItemModel */ int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; QHash roleNames() const; Q_SIGNALS: void countChanged(); protected: QMenuModel(GMenuModel *other=0, QObject *parent=0); void setMenuModel(GMenuModel *model); GMenuModel *menuModel() const; virtual bool event(QEvent* e); private: MenuNode *m_root; MenuNode* nodeFromIndex(const QModelIndex &index) const; QModelIndex indexFromNode(MenuNode *node) const; QVariant getStringAttribute(MenuNode *node, int row, const QString &attribute) const; QVariant getExtraProperties(MenuNode *node, int row) const; bool hasLink(MenuNode *node, int row, const QString &linkType) const; QString parseExtraPropertyName(const QString &name) const; void clearModel(); }; #endif qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/menunode.h0000644000015201777760000000403512305545024023672 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #ifndef MENUNODE_H #define MENUNODE_H #include #include #include #include extern "C" { #include } class MenuNode { public: MenuNode(const QString &linkType, GMenuModel *model, MenuNode *parent, int pos, QObject *listener); ~MenuNode(); int position() const; MenuNode *parent() const; GMenuModel *model() const; QString linkType() const; void connect(QObject *listener); void disconnect(); int size() const; MenuNode *child(int pos) const; void insertChild(MenuNode *child, int pos); int childPosition(GMenuModel *item) const; int childPosition(const MenuNode *item) const; int depth() const; void change(int start, int added, int removed); MenuNode *find(GMenuModel *item); int realPosition(int row) const; void commitOperation(); static MenuNode *create(GMenuModel *model, int pos, MenuNode *parent=0, QObject *listener=0); private: GMenuModel *m_model; QMap m_children; MenuNode* m_parent; int m_size; QObject *m_listener; gulong m_signalChangedId; QString m_linkType; int m_currentOpPosition; int m_currentOpAdded; int m_currentOpRemoved; static void onItemsChanged(GMenuModel *model, gint position, gint removed, gint added, gpointer data); }; #endif qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/0000755000015201777760000000000012305545277022504 5ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkmenutracker.c0000644000015201777760000004363212305545024025674 0ustar pbusernogroup00000000000000/* * Copyright © 2013 Canonical Limited * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the licence, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Author: Ryan Lortie */ #include "config.h" #include "gtkmenutracker.h" /** * SECTION:gtkmenutracker * @Title: GtkMenuTracker * @Short_description: A helper class for interpreting #GMenuModel * * #GtkMenuTracker is a simple object to ease implementations of #GMenuModel. * Given a #GtkActionObservable (usually a #GActionMuxer) along with a * #GMenuModel, it will tell you which menu items to create and where to place * them. If a menu item is removed, it will tell you the position of the menu * item to remove. * * Using #GtkMenuTracker is fairly simple. The only guarantee you must make * to #GtkMenuTracker is that you must obey all insert signals and track the * position of items that #GtkMenuTracker gives you. That is, #GtkMenuTracker * expects positions of all the latter items to change when it calls your * insertion callback with an early position, as it may ask you to remove * an item with a readjusted position later. * * #GtkMenuTracker will give you a #GtkMenuTrackerItem in your callback. You * must hold onto this object until a remove signal is emitted. This item * represents a single menu item, which can be one of three classes: normal item, * separator, or submenu. * * Certain properties on the #GtkMenuTrackerItem are mutable, and you must * listen for changes in the item. For more details, see the documentation * for #GtkMenuTrackerItem along with https://live.gnome.org/GApplication/GMenuModel. * * The idea of @with_separators is for special cases where menu models may * be tracked in places where separators are not available, like in toplevel * "File", "Edit" menu bars. Ignoring separator items is wrong, as #GtkMenuTracker * expects the position to change, so we must tell #GtkMenuTracker to ignore * separators itself. */ typedef struct _GtkMenuTrackerSection GtkMenuTrackerSection; struct _GtkMenuTracker { GtkActionObservable *observable; GtkMenuTrackerInsertFunc insert_func; GtkMenuTrackerRemoveFunc remove_func; gpointer user_data; GtkMenuTrackerSection *toplevel; }; struct _GtkMenuTrackerSection { GMenuModel *model; GSList *items; gchar *action_namespace; guint with_separators : 1; guint has_separator : 1; gulong handler; }; static GtkMenuTrackerSection * gtk_menu_tracker_section_new (GtkMenuTracker *tracker, GMenuModel *model, gboolean with_separators, gint offset, const gchar *action_namespace); static void gtk_menu_tracker_section_free (GtkMenuTrackerSection *section); static GtkMenuTrackerSection * gtk_menu_tracker_section_find_model (GtkMenuTrackerSection *section, GMenuModel *model, gint *offset) { GSList *item; if (section->has_separator) (*offset)++; if (section->model == model) return section; for (item = section->items; item; item = item->next) { GtkMenuTrackerSection *subsection = item->data; if (subsection) { GtkMenuTrackerSection *found_section; found_section = gtk_menu_tracker_section_find_model (subsection, model, offset); if (found_section) return found_section; } else (*offset)++; } return FALSE; } /* this is responsible for syncing the showing of a separator for a * single subsection (and its children). * * we only ever show separators if we have _actual_ children (ie: we do * not show a separator if the section contains only empty child * sections). it's difficult to determine this on-the-fly, so we have * this separate function to come back later and figure it out. * * 'section' is that section. * * 'tracker' is passed in so that we can emit callbacks when we decide * to add/remove separators. * * 'offset' is passed in so we know which position to emit in our * callbacks. ie: if we add a separator right at the top of this * section then we would emit it with this offset. deeper inside, we * adjust accordingly. * * could_have_separator is true in two situations: * * - our parent section had with_separators defined and we are not the * first section (ie: we should add a separator if we have content in * order to divide us from the items above) * * - if we had a 'label' attribute set for this section * * parent_model and parent_index are passed in so that we can give them * to the insertion callback so that it can see the label (and anything * else that happens to be defined on the section). * * we iterate each item in ourselves. for subsections, we recursively * run ourselves to sync separators. after we are done, we notice if we * have any items in us or if we are completely empty and sync if our * separator is shown or not. */ static gint gtk_menu_tracker_section_sync_separators (GtkMenuTrackerSection *section, GtkMenuTracker *tracker, gint offset, gboolean could_have_separator, GMenuModel *parent_model, gint parent_index) { gboolean should_have_separator; gint n_items = 0; GSList *item; gint i = 0; for (item = section->items; item; item = item->next) { GtkMenuTrackerSection *subsection = item->data; if (subsection) { gboolean could_have_separator; could_have_separator = (section->with_separators && i > 0) || g_menu_model_get_item_attribute (section->model, i, "label", "s", NULL); n_items += gtk_menu_tracker_section_sync_separators (subsection, tracker, offset + n_items, could_have_separator, section->model, i); } else n_items++; i++; } should_have_separator = could_have_separator && n_items != 0; if (should_have_separator > section->has_separator) { /* Add a separator */ GtkMenuTrackerItem *item; item = _gtk_menu_tracker_item_new (tracker->observable, parent_model, parent_index, NULL, TRUE); (* tracker->insert_func) (item, offset, tracker->user_data); g_object_unref (item); section->has_separator = TRUE; } else if (should_have_separator < section->has_separator) { /* Remove a separator */ (* tracker->remove_func) (offset, tracker->user_data); section->has_separator = FALSE; } n_items += section->has_separator; return n_items; } static gint gtk_menu_tracker_section_measure (GtkMenuTrackerSection *section) { GSList *item; gint n_items; if (section == NULL) return 1; n_items = 0; if (section->has_separator) n_items++; for (item = section->items; item; item = item->next) n_items += gtk_menu_tracker_section_measure (item->data); return n_items; } static void gtk_menu_tracker_remove_items (GtkMenuTracker *tracker, GSList **change_point, gint offset, gint n_items) { gint i; for (i = 0; i < n_items; i++) { GtkMenuTrackerSection *subsection; gint n; subsection = (*change_point)->data; *change_point = g_slist_delete_link (*change_point, *change_point); n = gtk_menu_tracker_section_measure (subsection); gtk_menu_tracker_section_free (subsection); while (n--) (* tracker->remove_func) (offset, tracker->user_data); } } static void gtk_menu_tracker_add_items (GtkMenuTracker *tracker, GtkMenuTrackerSection *section, GSList **change_point, gint offset, GMenuModel *model, gint position, gint n_items) { while (n_items--) { GMenuModel *submenu; submenu = g_menu_model_get_item_link (model, position + n_items, G_MENU_LINK_SECTION); g_assert (submenu != model); if (submenu != NULL) { GtkMenuTrackerSection *subsection; gchar *action_namespace = NULL; g_menu_model_get_item_attribute (model, position + n_items, G_MENU_ATTRIBUTE_ACTION_NAMESPACE, "s", &action_namespace); if (section->action_namespace) { gchar *namespace; namespace = g_strjoin (".", section->action_namespace, action_namespace, NULL); subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, offset, namespace); g_free (namespace); } else subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, offset, section->action_namespace); *change_point = g_slist_prepend (*change_point, subsection); g_free (action_namespace); g_object_unref (submenu); } else { GtkMenuTrackerItem *item; item = _gtk_menu_tracker_item_new (tracker->observable, model, position + n_items, section->action_namespace, FALSE); (* tracker->insert_func) (item, offset, tracker->user_data); g_object_unref (item); *change_point = g_slist_prepend (*change_point, NULL); } } } static void gtk_menu_tracker_model_changed (GMenuModel *model, gint position, gint removed, gint added, gpointer user_data) { GtkMenuTracker *tracker = user_data; GtkMenuTrackerSection *section; GSList **change_point; gint offset = 0; gint i; /* First find which section the changed model corresponds to, and the * position of that section within the overall menu. */ section = gtk_menu_tracker_section_find_model (tracker->toplevel, model, &offset); /* Next, seek through that section to the change point. This gives us * the correct GSList** to make the change to and also finds the final * offset at which we will make the changes (by measuring the number * of items within each item of the section before the change point). */ change_point = §ion->items; for (i = 0; i < position; i++) { offset += gtk_menu_tracker_section_measure ((*change_point)->data); change_point = &(*change_point)->next; } /* We remove items in order and add items in reverse order. This * means that the offset used for all inserts and removes caused by a * single change will be the same. * * This also has a performance advantage: GtkMenuShell stores the * menu items in a linked list. In the case where we are creating a * menu for the first time, adding the items in reverse order means * that we only ever insert at index zero, prepending the list. This * means that we can populate in O(n) time instead of O(n^2) that we * would do by appending. */ gtk_menu_tracker_remove_items (tracker, change_point, offset, removed); gtk_menu_tracker_add_items (tracker, section, change_point, offset, model, position, added); /* The offsets for insertion/removal of separators will be all over * the place, however... */ gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0); } static void gtk_menu_tracker_section_free (GtkMenuTrackerSection *section) { if (section == NULL) return; g_signal_handler_disconnect (section->model, section->handler); g_slist_free_full (section->items, (GDestroyNotify) gtk_menu_tracker_section_free); g_free (section->action_namespace); g_object_unref (section->model); g_slice_free (GtkMenuTrackerSection, section); } static GtkMenuTrackerSection * gtk_menu_tracker_section_new (GtkMenuTracker *tracker, GMenuModel *model, gboolean with_separators, gint offset, const gchar *action_namespace) { GtkMenuTrackerSection *section; section = g_slice_new0 (GtkMenuTrackerSection); section->model = g_object_ref (model); section->with_separators = with_separators; section->action_namespace = g_strdup (action_namespace); gtk_menu_tracker_add_items (tracker, section, §ion->items, offset, model, 0, g_menu_model_get_n_items (model)); section->handler = g_signal_connect (model, "items-changed", G_CALLBACK (gtk_menu_tracker_model_changed), tracker); return section; } /*< private > * gtk_menu_tracker_new: * @model: the model to flatten * @with_separators: if the toplevel should have separators (ie: TRUE * for menus, FALSE for menubars) * @action_namespace: the passed-in action namespace * @insert_func: insert callback * @remove_func: remove callback * @user_data user data for callbacks * * Creates a GtkMenuTracker for @model, holding a ref on @model for as * long as the tracker is alive. * * This flattens out the model, merging sections and inserting * separators where appropriate. It monitors for changes and performs * updates on the fly. It also handles action_namespace for subsections * (but you will need to handle it yourself for submenus). * * When the tracker is first created, @insert_func will be called many * times to populate the menu with the initial contents of @model * (unless it is empty), before gtk_menu_tracker_new() returns. For * this reason, the menu that is using the tracker ought to be empty * when it creates the tracker. * * Future changes to @model will result in more calls to @insert_func * and @remove_func. * * The position argument to both functions is the linear 0-based * position in the menu at which the item in question should be inserted * or removed. * * For @insert_func, @model and @item_index are used to get the * information about the menu item to insert. @action_namespace is the * action namespace that actions referred to from that item should place * themselves in. Note that if the item is a submenu and the * "action-namespace" attribute is defined on the item, it will _not_ be * applied to the @action_namespace argument as it is meant for the * items inside of the submenu, not the submenu item itself. * * @is_separator is set to %TRUE in case the item being added is a * separator. @model and @item_index will still be meaningfully set in * this case -- to the section menu item corresponding to the separator. * This is useful if the section specifies a label, for example. If * there is an "action-namespace" attribute on this menu item then it * should be ignored by the consumer because #GtkMenuTracker has already * handled it. * * When using #GtkMenuTracker there is no need to hold onto @model or * monitor it for changes. The model will be unreffed when * gtk_menu_tracker_free() is called. */ GtkMenuTracker * gtk_menu_tracker_new (GtkActionObservable *observable, GMenuModel *model, gboolean with_separators, const gchar *action_namespace, GtkMenuTrackerInsertFunc insert_func, GtkMenuTrackerRemoveFunc remove_func, gpointer user_data) { GtkMenuTracker *tracker; tracker = g_slice_new (GtkMenuTracker); tracker->observable = g_object_ref (observable); tracker->insert_func = insert_func; tracker->remove_func = remove_func; tracker->user_data = user_data; tracker->toplevel = gtk_menu_tracker_section_new (tracker, model, with_separators, 0, action_namespace); gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0); return tracker; } GtkMenuTracker * gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem *item, GtkMenuTrackerInsertFunc insert_func, GtkMenuTrackerRemoveFunc remove_func, gpointer user_data) { return gtk_menu_tracker_new (_gtk_menu_tracker_item_get_observable (item), _gtk_menu_tracker_item_get_submenu (item), TRUE, _gtk_menu_tracker_item_get_submenu_namespace (item), insert_func, remove_func, user_data); } /*< private > * gtk_menu_tracker_free: * @tracker: a #GtkMenuTracker * * Frees the tracker, ... */ void gtk_menu_tracker_free (GtkMenuTracker *tracker) { gtk_menu_tracker_section_free (tracker->toplevel); g_object_unref (tracker->observable); g_slice_free (GtkMenuTracker, tracker); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkactionobservable.h0000644000015201777760000000577312305545024026707 0ustar pbusernogroup00000000000000/* * Copyright © 2011 Canonical Limited * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 of the * licence or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: Ryan Lortie */ #ifndef __GTK_ACTION_OBSERVABLE_H__ #define __GTK_ACTION_OBSERVABLE_H__ #include "gtkactionobserver.h" G_BEGIN_DECLS #define GTK_TYPE_ACTION_OBSERVABLE (gtk_action_observable_get_type ()) #define GTK_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ GTK_TYPE_ACTION_OBSERVABLE, GtkActionObservable)) #define GTK_IS_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ GTK_TYPE_ACTION_OBSERVABLE)) #define GTK_ACTION_OBSERVABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \ GTK_TYPE_ACTION_OBSERVABLE, \ GtkActionObservableInterface)) typedef struct _GtkActionObservableInterface GtkActionObservableInterface; struct _GtkActionObservableInterface { GTypeInterface g_iface; void (* register_observer) (GtkActionObservable *observable, const gchar *action_name, GtkActionObserver *observer); void (* unregister_observer) (GtkActionObservable *observable, const gchar *action_name, GtkActionObserver *observer); }; GType gtk_action_observable_get_type (void); void gtk_action_observable_register_observer (GtkActionObservable *observable, const gchar *action_name, GtkActionObserver *observer); void gtk_action_observable_unregister_observer (GtkActionObservable *observable, const gchar *action_name, GtkActionObserver *observer); G_END_DECLS #endif /* __GTK_ACTION_OBSERVABLE_H__ */ qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkmenutracker.h0000644000015201777760000000551612305545024025700 0ustar pbusernogroup00000000000000/* * Copyright © 2013 Canonical Limited * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the licence, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Author: Ryan Lortie */ #ifndef __GTK_MENU_TRACKER_H__ #define __GTK_MENU_TRACKER_H__ #include "gtkmenutrackeritem.h" typedef struct _GtkMenuTracker GtkMenuTracker; typedef void (* GtkMenuTrackerInsertFunc) (GtkMenuTrackerItem *item, gint position, gpointer user_data); typedef void (* GtkMenuTrackerRemoveFunc) (gint position, gpointer user_data); GtkMenuTracker * gtk_menu_tracker_new (GtkActionObservable *observer, GMenuModel *model, gboolean with_separators, const gchar *action_namespace, GtkMenuTrackerInsertFunc insert_func, GtkMenuTrackerRemoveFunc remove_func, gpointer user_data); GtkMenuTracker * gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem *item, GtkMenuTrackerInsertFunc insert_func, GtkMenuTrackerRemoveFunc remove_func, gpointer user_data); void gtk_menu_tracker_free (GtkMenuTracker *tracker); #endif /* __GTK_MENU_TRACKER_H__ */ qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtksimpleactionobserver.h0000644000015201777760000000664112305545024027617 0ustar pbusernogroup00000000000000/* * Copyright © 2013 Canonical Limited * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 of the * licence or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: Nick Dedekind . * * Authors: Ryan Lortie */ #ifndef __GTK_ACTION_OBSERVER_H__ #define __GTK_ACTION_OBSERVER_H__ #include G_BEGIN_DECLS #define GTK_TYPE_ACTION_OBSERVER (gtk_action_observer_get_type ()) #define GTK_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ GTK_TYPE_ACTION_OBSERVER, GtkActionObserver)) #define GTK_IS_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ GTK_TYPE_ACTION_OBSERVER)) #define GTK_ACTION_OBSERVER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \ GTK_TYPE_ACTION_OBSERVER, GtkActionObserverInterface)) typedef struct _GtkActionObserverInterface GtkActionObserverInterface; typedef struct _GtkActionObservable GtkActionObservable; typedef struct _GtkActionObserver GtkActionObserver; struct _GtkActionObserverInterface { GTypeInterface g_iface; void (* action_added) (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, const GVariantType *parameter_type, gboolean enabled, GVariant *state); void (* action_enabled_changed) (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, gboolean enabled); void (* action_state_changed) (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, GVariant *state); void (* action_removed) (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name); }; GType gtk_action_observer_get_type (void); void gtk_action_observer_action_added (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, const GVariantType *parameter_type, gboolean enabled, GVariant *state); void gtk_action_observer_action_enabled_changed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, gboolean enabled); void gtk_action_observer_action_state_changed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, GVariant *state); void gtk_action_observer_action_removed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name); G_END_DECLS #endif /* __GTK_ACTION_OBSERVER_H__ */ qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkmenutrackeritem.c0000644000015201777760000007217312305545024026555 0ustar pbusernogroup00000000000000/* * Copyright © 2013 Canonical Limited * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the licence, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Author: Ryan Lortie */ #include "config.h" #include "gtkmenutrackeritem.h" /** * SECTION:gtkmenutrackeritem * @Title: GtkMenuTrackerItem * @Short_description: Small helper for model menu items * * A #GtkMenuTrackerItem is a small helper class used by #GtkMenuTracker to * represent menu items. It has one of three classes: normal item, separator, * or submenu. * * If an item is one of the non-normal classes (submenu, separator), only the * label of the item needs to be respected. Otherwise, all the properties * of the item contribute to the item's appearance and state. * * Implementing the appearance of the menu item is up to toolkits, and certain * toolkits may choose to ignore certain properties, like icon or accel. The * role of the item determines its accessibility role, along with its * decoration if the GtkMenuTrackerItem::toggled property is true. As an * example, if the item has the role %GTK_MENU_TRACKER_ITEM_ROLE_CHECK and * GtkMenuTrackerItem::toggled is %FALSE, its accessible role should be that of * a check menu item, and no decoration should be drawn. But if * GtkMenuTrackerItem::toggled is %TRUE, a checkmark should be drawn. * * All properties except for the two class-determining properties, * GtkMenuTrackerItem::is-separator and GtkMenuTrackerItem::has-submenu are * allowed to change, so listen to the notify signals to update your item's * appearance. When using a GObject library, this can conveniently be done * with g_object_bind_property() and #GBinding, and this is how this is * implemented in GTK+; the appearance side is implemented in #GtkModelMenuItem. * * When an item is clicked, simply call gtk_menu_tracker_item_activated() in * response. The #GtkMenuTrackerItem will take care of everything related to * activating the item and will itself update the state of all items in * response. * * Submenus are a special case of menu item. When an item is a submenu, you * should create a submenu for it with gtk_menu_tracker_new_item_for_submenu(), * and apply the same menu tracking logic you would for a toplevel menu. * Applications using submenus may want to lazily build their submenus in * response to the user clicking on it, as building a submenu may be expensive. * * Thus, the submenu has two special controls -- the submenu's visibility * should be controlled by the GtkMenuTrackerItem::submenu-shown property, * and if a user clicks on the submenu, do not immediately show the menu, * but call gtk_menu_tracker_item_request_submenu_shown() and wait for the * GtkMenuTrackerItem::submenu-shown property to update. If the user navigates, * the application may want to be notified so it can cancel the expensive * operation that it was using to build the submenu. Thus, * gtk_menu_tracker_item_request_submenu_shown() takes a boolean parameter. * Use %TRUE when the user wants to open the submenu, and %FALSE when the * user wants to close the submenu. */ typedef GObjectClass GtkMenuTrackerItemClass; struct _GtkMenuTrackerItem { GObject parent_instance; GtkActionObservable *observable; gchar *action_namespace; GMenuItem *item; GtkMenuTrackerItemRole role : 4; guint is_separator : 1; guint can_activate : 1; guint sensitive : 1; guint toggled : 1; guint submenu_shown : 1; guint submenu_requested : 1; GVariant *action_state; }; enum { PROP_0, PROP_IS_SEPARATOR, PROP_HAS_SUBMENU, PROP_LABEL, PROP_ICON, PROP_SENSITIVE, PROP_VISIBLE, PROP_ROLE, PROP_TOGGLED, PROP_ACCEL, PROP_SUBMENU_SHOWN, PROP_ACTION_NAME, PROP_ACTION_STATE, N_PROPS }; static GParamSpec *gtk_menu_tracker_item_pspecs[N_PROPS]; static void gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface); G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerItem, gtk_menu_tracker_item, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVER, gtk_menu_tracker_item_init_observer_iface)) GType gtk_menu_tracker_item_role_get_type (void) { static gsize gtk_menu_tracker_item_role_type; if (g_once_init_enter (>k_menu_tracker_item_role_type)) { static const GEnumValue values[] = { { GTK_MENU_TRACKER_ITEM_ROLE_NORMAL, "GTK_MENU_TRACKER_ITEM_ROLE_NORMAL", "normal" }, { GTK_MENU_TRACKER_ITEM_ROLE_CHECK, "GTK_MENU_TRACKER_ITEM_ROLE_CHECK", "check" }, { GTK_MENU_TRACKER_ITEM_ROLE_RADIO, "GTK_MENU_TRACKER_ITEM_ROLE_RADIO", "radio" }, { 0, NULL, NULL } }; GType type; type = g_enum_register_static ("GtkMenuTrackerItemRole", values); g_once_init_leave (>k_menu_tracker_item_role_type, type); } return gtk_menu_tracker_item_role_type; } static void gtk_menu_tracker_item_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (object); switch (prop_id) { case PROP_IS_SEPARATOR: g_value_set_boolean (value, gtk_menu_tracker_item_get_is_separator (self)); break; case PROP_HAS_SUBMENU: g_value_set_boolean (value, gtk_menu_tracker_item_get_has_submenu (self)); break; case PROP_LABEL: g_value_set_string (value, gtk_menu_tracker_item_get_label (self)); break; case PROP_ICON: g_value_set_object (value, gtk_menu_tracker_item_get_icon (self)); break; case PROP_SENSITIVE: g_value_set_boolean (value, gtk_menu_tracker_item_get_sensitive (self)); break; case PROP_VISIBLE: g_value_set_boolean (value, gtk_menu_tracker_item_get_visible (self)); break; case PROP_ROLE: g_value_set_enum (value, gtk_menu_tracker_item_get_role (self)); break; case PROP_TOGGLED: g_value_set_boolean (value, gtk_menu_tracker_item_get_toggled (self)); break; case PROP_ACCEL: g_value_set_string (value, gtk_menu_tracker_item_get_accel (self)); break; case PROP_SUBMENU_SHOWN: g_value_set_boolean (value, gtk_menu_tracker_item_get_submenu_shown (self)); break; case PROP_ACTION_NAME: g_value_take_string (value, gtk_menu_tracker_item_get_action_name (self)); case PROP_ACTION_STATE: g_value_set_variant (value, self->action_state); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gtk_menu_tracker_item_finalize (GObject *object) { GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (object); g_free (self->action_namespace); if (self->observable) g_object_unref (self->observable); if (self->action_state) g_variant_unref (self->action_state); g_object_unref (self->item); G_OBJECT_CLASS (gtk_menu_tracker_item_parent_class)->finalize (object); } static void gtk_menu_tracker_item_init (GtkMenuTrackerItem * self) { } static void gtk_menu_tracker_item_class_init (GtkMenuTrackerItemClass *class) { class->get_property = gtk_menu_tracker_item_get_property; class->finalize = gtk_menu_tracker_item_finalize; gtk_menu_tracker_item_pspecs[PROP_IS_SEPARATOR] = g_param_spec_boolean ("is-separator", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_HAS_SUBMENU] = g_param_spec_boolean ("has-submenu", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_LABEL] = g_param_spec_string ("label", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_ICON] = g_param_spec_object ("icon", "", "", G_TYPE_ICON, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_SENSITIVE] = g_param_spec_boolean ("sensitive", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_VISIBLE] = g_param_spec_boolean ("visible", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_ROLE] = g_param_spec_enum ("role", "", "", GTK_TYPE_MENU_TRACKER_ITEM_ROLE, GTK_MENU_TRACKER_ITEM_ROLE_NORMAL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_TOGGLED] = g_param_spec_boolean ("toggled", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_ACCEL] = g_param_spec_string ("accel", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN] = g_param_spec_boolean ("submenu-shown", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_ACTION_NAME] = g_param_spec_boolean ("action-name", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); gtk_menu_tracker_item_pspecs[PROP_ACTION_STATE] = g_param_spec_boolean ("action-state", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); g_object_class_install_properties (class, N_PROPS, gtk_menu_tracker_item_pspecs); } static void gtk_menu_tracker_item_action_added (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, const GVariantType *parameter_type, gboolean enabled, GVariant *state) { GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer); GVariant *action_target; action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL); self->can_activate = (action_target == NULL && parameter_type == NULL) || (action_target != NULL && parameter_type != NULL && g_variant_is_of_type (action_target, parameter_type)); if (!self->can_activate) { if (action_target) g_variant_unref (action_target); return; } self->sensitive = enabled; if (action_target != NULL && state != NULL) { self->toggled = g_variant_equal (state, action_target); self->role = GTK_MENU_TRACKER_ITEM_ROLE_RADIO; } else if (state != NULL && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) { self->toggled = g_variant_get_boolean (state); self->role = GTK_MENU_TRACKER_ITEM_ROLE_CHECK; } g_object_freeze_notify (G_OBJECT (self)); if (self->sensitive) g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]); if (self->toggled) g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]); if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL) g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]); if (state != NULL) { self->action_state = g_variant_ref (state); g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ACTION_STATE]); } g_object_thaw_notify (G_OBJECT (self)); if (action_target) g_variant_unref (action_target); } static void gtk_menu_tracker_item_action_enabled_changed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, gboolean enabled) { GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer); if (!self->can_activate) return; if (self->sensitive == enabled) return; self->sensitive = enabled; g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]); } static void gtk_menu_tracker_item_action_state_changed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, GVariant *state) { GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer); GVariant *action_target; gboolean was_toggled; if (!self->can_activate) return; action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL); was_toggled = self->toggled; if (action_target) { self->toggled = g_variant_equal (state, action_target); g_variant_unref (action_target); } else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) self->toggled = g_variant_get_boolean (state); else self->toggled = FALSE; if (self->toggled != was_toggled) g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]); if (self->action_state) g_variant_unref (self->action_state); self->action_state = g_variant_ref (state); g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ACTION_STATE]); } static void gtk_menu_tracker_item_action_removed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name) { GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer); if (!self->can_activate) return; g_object_freeze_notify (G_OBJECT (self)); if (self->sensitive) { self->sensitive = FALSE; g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]); } if (self->toggled) { self->toggled = FALSE; g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]); } if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL) { self->role = GTK_MENU_TRACKER_ITEM_ROLE_NORMAL; g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]); } if (self->action_state != NULL) { g_variant_unref (self->action_state); g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ACTION_STATE]); } g_object_thaw_notify (G_OBJECT (self)); } static void gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface) { iface->action_added = gtk_menu_tracker_item_action_added; iface->action_enabled_changed = gtk_menu_tracker_item_action_enabled_changed; iface->action_state_changed = gtk_menu_tracker_item_action_state_changed; iface->action_removed = gtk_menu_tracker_item_action_removed; } GtkMenuTrackerItem * _gtk_menu_tracker_item_new (GtkActionObservable *observable, GMenuModel *model, gint item_index, const gchar *action_namespace, gboolean is_separator) { GtkMenuTrackerItem *self; const gchar *action_name; g_return_val_if_fail (GTK_IS_ACTION_OBSERVABLE (observable), NULL); g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL); self = g_object_new (GTK_TYPE_MENU_TRACKER_ITEM, NULL); self->item = g_menu_item_new_from_model (model, item_index); self->action_namespace = g_strdup (action_namespace); self->observable = g_object_ref (observable); self->is_separator = is_separator; if (!is_separator && g_menu_item_get_attribute (self->item, "action", "&s", &action_name)) { GActionGroup *group = G_ACTION_GROUP (observable); const GVariantType *parameter_type; gboolean enabled; GVariant *state; gboolean found; state = NULL; if (action_namespace) { gchar *full_action; full_action = g_strjoin (".", action_namespace, action_name, NULL); gtk_action_observable_register_observer (self->observable, full_action, GTK_ACTION_OBSERVER (self)); found = g_action_group_query_action (group, full_action, &enabled, ¶meter_type, NULL, NULL, &state); g_free (full_action); } else { gtk_action_observable_register_observer (self->observable, action_name, GTK_ACTION_OBSERVER (self)); found = g_action_group_query_action (group, action_name, &enabled, ¶meter_type, NULL, NULL, &state); } if (found) gtk_menu_tracker_item_action_added (GTK_ACTION_OBSERVER (self), observable, NULL, parameter_type, enabled, state); else gtk_menu_tracker_item_action_removed (GTK_ACTION_OBSERVER (self), observable, NULL); if (state) g_variant_unref (state); } else self->sensitive = TRUE; return self; } GtkActionObservable * _gtk_menu_tracker_item_get_observable (GtkMenuTrackerItem *self) { return self->observable; } /** * gtk_menu_tracker_item_get_is_separator: * @self: A #GtkMenuTrackerItem instance * * Returns whether the menu item is a separator. If so, only * certain properties may need to be obeyed. See the documentation * for #GtkMenuTrackerItem. */ gboolean gtk_menu_tracker_item_get_is_separator (GtkMenuTrackerItem *self) { return self->is_separator; } /** * gtk_menu_tracker_item_get_has_submenu: * @self: A #GtkMenuTrackerItem instance * * Returns whether the menu item has a submenu. If so, only * certain properties may need to be obeyed. See the documentation * for #GtkMenuTrackerItem. */ gboolean gtk_menu_tracker_item_get_has_submenu (GtkMenuTrackerItem *self) { GMenuModel *link; link = g_menu_item_get_link (self->item, G_MENU_LINK_SUBMENU); if (link) { g_object_unref (link); return TRUE; } else return FALSE; } const gchar * gtk_menu_tracker_item_get_label (GtkMenuTrackerItem *self) { const gchar *label = NULL; g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_LABEL, "&s", &label); return label; } /** * gtk_menu_tracker_item_get_icon: * * Returns: (transfer full): */ GIcon * gtk_menu_tracker_item_get_icon (GtkMenuTrackerItem *self) { GVariant *icon_data; GIcon *icon; icon_data = g_menu_item_get_attribute_value (self->item, "icon", NULL); if (icon_data == NULL) return NULL; icon = g_icon_deserialize (icon_data); g_variant_unref (icon_data); return icon; } gboolean gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self) { return self->sensitive; } gboolean gtk_menu_tracker_item_get_visible (GtkMenuTrackerItem *self) { return TRUE; } GtkMenuTrackerItemRole gtk_menu_tracker_item_get_role (GtkMenuTrackerItem *self) { return self->role; } gboolean gtk_menu_tracker_item_get_toggled (GtkMenuTrackerItem *self) { return self->toggled; } const gchar * gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self) { const gchar *accel = NULL; g_menu_item_get_attribute (self->item, "accel", "&s", &accel); return accel; } GMenuModel * _gtk_menu_tracker_item_get_submenu (GtkMenuTrackerItem *self) { return g_menu_item_get_link (self->item, "submenu"); } gchar * _gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self) { const gchar *namespace; if (g_menu_item_get_attribute (self->item, "action-namespace", "&s", &namespace)) { if (self->action_namespace) return g_strjoin (".", self->action_namespace, namespace, NULL); else return g_strdup (namespace); } else return g_strdup (self->action_namespace); } gboolean gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self) { return g_menu_item_get_attribute (self->item, "submenu-action", "&s", NULL); } gboolean gtk_menu_tracker_item_get_submenu_shown (GtkMenuTrackerItem *self) { return self->submenu_shown; } /** * gtk_menu_tracker_item_get_action_name: * @self: A #GtkMenuTrackerItem instance * * Returns a newly-allocated string containing the name of the action * associated with this menu item. * * Returns: (transfer full): the action name, free it with g_free() */ gchar * gtk_menu_tracker_item_get_action_name (GtkMenuTrackerItem *self) { const gchar *action_name; if (!g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_ACTION, "&s", &action_name)) return NULL; if (self->action_namespace) return g_strjoin (".", self->action_namespace, action_name, NULL); else return g_strdup (action_name); } GVariant * gtk_menu_tracker_item_get_action_state (GtkMenuTrackerItem *self) { if (self->action_state != NULL) return g_variant_ref (self->action_state); return NULL; } const gchar * gtk_menu_tracker_item_get_action_namespace (GtkMenuTrackerItem *self) { return self->action_namespace; } static void gtk_menu_tracker_item_set_submenu_shown (GtkMenuTrackerItem *self, gboolean submenu_shown) { if (submenu_shown == self->submenu_shown) return; self->submenu_shown = submenu_shown; g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN]); } void gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self) { const gchar *action_name; GVariant *action_target; g_return_if_fail (GTK_IS_MENU_TRACKER_ITEM (self)); if (!self->can_activate) return; g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_ACTION, "&s", &action_name); action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL); if (self->action_namespace) { gchar *full_action; full_action = g_strjoin (".", self->action_namespace, action_name, NULL); g_action_group_activate_action (G_ACTION_GROUP (self->observable), full_action, action_target); g_free (full_action); } else g_action_group_activate_action (G_ACTION_GROUP (self->observable), action_name, action_target); if (action_target) g_variant_unref (action_target); } void gtk_menu_tracker_item_change_state (GtkMenuTrackerItem *self, GVariant *value) { const gchar *action_name; g_return_if_fail (GTK_IS_MENU_TRACKER_ITEM (self)); g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_ACTION, "&s", &action_name); if (self->action_namespace) { gchar *full_action; full_action = g_strjoin (".", self->action_namespace, action_name, NULL); g_action_group_change_action_state (G_ACTION_GROUP (self->observable), full_action, g_variant_ref(value)); g_free (full_action); } else g_action_group_change_action_state (G_ACTION_GROUP (self->observable), action_name, g_variant_ref(value)); } typedef struct { GtkMenuTrackerItem *item; gchar *submenu_action; gboolean first_time; } GtkMenuTrackerOpener; static void gtk_menu_tracker_opener_update (GtkMenuTrackerOpener *opener) { GActionGroup *group = G_ACTION_GROUP (opener->item->observable); gboolean is_open = TRUE; /* We consider the menu as being "open" if the action does not exist * or if there is another problem (no state, wrong state type, etc.). * If the action exists, with the correct state then we consider it * open if we have ever seen this state equal to TRUE. * * In the event that we see the state equal to FALSE, we force it back * to TRUE. We do not signal that the menu was closed because this is * likely to create UI thrashing. * * The only way the menu can have a true-to-false submenu-shown * transition is if the user calls _request_submenu_shown (FALSE). * That is handled in _free() below. */ if (g_action_group_has_action (group, opener->submenu_action)) { GVariant *state = g_action_group_get_action_state (group, opener->submenu_action); if (state) { if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) is_open = g_variant_get_boolean (state); g_variant_unref (state); } } /* If it is already open, signal that. * * If it is not open, ask it to open. */ if (is_open) gtk_menu_tracker_item_set_submenu_shown (opener->item, TRUE); if (!is_open || opener->first_time) { g_action_group_change_action_state (group, opener->submenu_action, g_variant_new_boolean (TRUE)); opener->first_time = FALSE; } } static void gtk_menu_tracker_opener_added (GActionGroup *group, const gchar *action_name, gpointer user_data) { GtkMenuTrackerOpener *opener = user_data; if (g_str_equal (action_name, opener->submenu_action)) gtk_menu_tracker_opener_update (opener); } static void gtk_menu_tracker_opener_removed (GActionGroup *action_group, const gchar *action_name, gpointer user_data) { GtkMenuTrackerOpener *opener = user_data; if (g_str_equal (action_name, opener->submenu_action)) gtk_menu_tracker_opener_update (opener); } static void gtk_menu_tracker_opener_changed (GActionGroup *action_group, const gchar *action_name, GVariant *new_state, gpointer user_data) { GtkMenuTrackerOpener *opener = user_data; if (g_str_equal (action_name, opener->submenu_action)) gtk_menu_tracker_opener_update (opener); } static void gtk_menu_tracker_opener_free (gpointer data) { GtkMenuTrackerOpener *opener = data; g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_added, opener); g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_removed, opener); g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_changed, opener); g_action_group_change_action_state (G_ACTION_GROUP (opener->item->observable), opener->submenu_action, g_variant_new_boolean (FALSE)); gtk_menu_tracker_item_set_submenu_shown (opener->item, FALSE); g_free (opener->submenu_action); g_slice_free (GtkMenuTrackerOpener, opener); } static GtkMenuTrackerOpener * gtk_menu_tracker_opener_new (GtkMenuTrackerItem *item, const gchar *submenu_action) { GtkMenuTrackerOpener *opener; opener = g_slice_new (GtkMenuTrackerOpener); opener->first_time = TRUE; opener->item = item; if (item->action_namespace) opener->submenu_action = g_strjoin (".", item->action_namespace, submenu_action, NULL); else opener->submenu_action = g_strdup (submenu_action); g_signal_connect (item->observable, "action-added", G_CALLBACK (gtk_menu_tracker_opener_added), opener); g_signal_connect (item->observable, "action-removed", G_CALLBACK (gtk_menu_tracker_opener_removed), opener); g_signal_connect (item->observable, "action-state-changed", G_CALLBACK (gtk_menu_tracker_opener_changed), opener); gtk_menu_tracker_opener_update (opener); return opener; } void gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self, gboolean shown) { const gchar *submenu_action; gboolean has_submenu_action; if (shown == self->submenu_requested) return; has_submenu_action = g_menu_item_get_attribute (self->item, "submenu-action", "&s", &submenu_action); self->submenu_requested = shown; /* If we have a submenu action, start a submenu opener and wait * for the reply from the client. Otherwise, simply open the * submenu immediately. */ if (has_submenu_action) { if (shown) g_object_set_data_full (G_OBJECT (self), "submenu-opener", gtk_menu_tracker_opener_new (self, submenu_action), gtk_menu_tracker_opener_free); else g_object_set_data (G_OBJECT (self), "submenu-opener", NULL); } else gtk_menu_tracker_item_set_submenu_shown (self, shown); } gboolean gtk_menu_tracker_item_get_attribute (GtkMenuTrackerItem *self, const gchar *attribute, const gchar *format, ...) { gboolean success = FALSE; GVariant *value; g_return_val_if_fail (GTK_IS_MENU_TRACKER_ITEM (self), FALSE); g_return_val_if_fail (attribute != NULL, FALSE); g_return_val_if_fail (format != NULL, FALSE); value = g_menu_item_get_attribute_value (self->item, attribute, NULL); if (value) { if (g_variant_check_format_string (value, format, TRUE)) { va_list args; va_start (args, format); g_variant_get_va (value, format, NULL, &args); va_end (args); success = TRUE; } g_variant_unref (value); } return success; } GVariant * gtk_menu_tracker_item_get_attribute_value (GtkMenuTrackerItem *self, const gchar *attribute, const GVariantType *expected_type) { return g_menu_item_get_attribute_value (self->item, attribute, expected_type); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtksimpleactionobserver.c0000644000015201777760000001343612305545024027612 0ustar pbusernogroup00000000000000/* * Copyright © 2013 Canonical Limited * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 of the * licence or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: Nick Dedekind observable); g_free(self->action_name); G_OBJECT_CLASS (gtk_simple_action_observer_parent_class)->finalize (object); } static void gtk_simple_action_observer_init (GtkSimpleActionObserver * self) { } static void gtk_simple_action_observer_class_init (GtkSimpleActionObserverClass *class) { class->finalize = gtk_simple_action_observer_finalize; } static void gtk_simple_action_observer_action_added (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, const GVariantType *parameter_type, gboolean enabled, GVariant *state) { GtkSimpleActionObserver* self; self = GTK_SIMPLE_ACTION_OBSERVER (observer); self->action_added(self, action_name, enabled, state); } static void gtk_simple_action_observer_action_enabled_changed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, gboolean enabled) { GtkSimpleActionObserver* self; self = GTK_SIMPLE_ACTION_OBSERVER (observer); self->action_enabled_changed(self, action_name, enabled); } static void gtk_simple_action_observer_action_state_changed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, GVariant *state) { GtkSimpleActionObserver* self; self = GTK_SIMPLE_ACTION_OBSERVER (observer); self->action_state_changed(self, action_name, state); } static void gtk_simple_action_observer_action_removed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name) { GtkSimpleActionObserver* self; self = GTK_SIMPLE_ACTION_OBSERVER (observer); self->action_removed(self, action_name); } static void gtk_simple_action_observer_init_observer_iface (GtkActionObserverInterface *iface) { iface->action_added = gtk_simple_action_observer_action_added; iface->action_enabled_changed = gtk_simple_action_observer_action_enabled_changed; iface->action_state_changed = gtk_simple_action_observer_action_state_changed; iface->action_removed = gtk_simple_action_observer_action_removed; } GtkSimpleActionObserver* gtk_simple_action_observer_new (GtkActionObservable *observable, GtkActionAddedFunc action_added, GtkActionEnabledChangedFunc action_enabled_changed, GtkActionStateChangedFunc action_state_changed, GtkActionRemovedFunc action_removed) { GtkSimpleActionObserver* self; self = g_object_new (GTK_TYPE_SIMPLE_ACTION_OBSERVER, NULL); self->observable = g_object_ref (observable); self->action_name = NULL; self->action_added = action_added; self->action_enabled_changed = action_enabled_changed; self->action_state_changed = action_state_changed; self->action_removed = action_removed; return self; } void gtk_simple_action_observer_register_action (GtkSimpleActionObserver *self, const gchar *action_name) { gtk_simple_action_observer_unregister_action(self); if (action_name && g_strcmp0(action_name, "") != 0) { self->action_name = g_strdup (action_name); if (g_strcmp0(self->action_name, "") != 0) { gtk_action_observable_register_observer (self->observable, self->action_name, GTK_ACTION_OBSERVER (self)); } } } void gtk_simple_action_observer_unregister_action (GtkSimpleActionObserver *self) { if (self->action_name) { gtk_action_observable_unregister_observer(self->observable, self->action_name, GTK_ACTION_OBSERVER (self)); g_free(self->action_name); self->action_name = NULL; } } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkactionmuxer.c0000644000015201777760000006114312305545024025707 0ustar pbusernogroup00000000000000/* * Copyright © 2011 Canonical Limited * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the licence, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Author: Ryan Lortie */ #include "config.h" #include "gtkactionmuxer.h" #include "gtkactionobservable.h" #include "gtkactionobserver.h" #include /** * SECTION:gtkactionmuxer * @short_description: Aggregate and monitor several action groups * * #GtkActionMuxer is a #GActionGroup and #GtkActionObservable that is * capable of containing other #GActionGroup instances. * * The typical use is aggregating all of the actions applicable to a * particular context into a single action group, with namespacing. * * Consider the case of two action groups -- one containing actions * applicable to an entire application (such as 'quit') and one * containing actions applicable to a particular window in the * application (such as 'fullscreen'). * * In this case, each of these action groups could be added to a * #GtkActionMuxer with the prefixes "app" and "win", respectively. This * would expose the actions as "app.quit" and "win.fullscreen" on the * #GActionGroup interface presented by the #GtkActionMuxer. * * Activations and state change requests on the #GtkActionMuxer are wired * through to the underlying action group in the expected way. * * This class is typically only used at the site of "consumption" of * actions (eg: when displaying a menu that contains many actions on * different objects). */ static void gtk_action_muxer_group_iface_init (GActionGroupInterface *iface); static void gtk_action_muxer_observable_iface_init (GtkActionObservableInterface *iface); typedef GObjectClass GtkActionMuxerClass; struct _GtkActionMuxer { GObject parent_instance; GHashTable *observed_actions; GHashTable *groups; GtkActionMuxer *parent; }; G_DEFINE_TYPE_WITH_CODE (GtkActionMuxer, gtk_action_muxer, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, gtk_action_muxer_group_iface_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVABLE, gtk_action_muxer_observable_iface_init)) enum { PROP_0, PROP_PARENT, NUM_PROPERTIES }; static GParamSpec *properties[NUM_PROPERTIES]; typedef struct { GtkActionMuxer *muxer; GSList *watchers; gchar *fullname; } Action; typedef struct { GtkActionMuxer *muxer; GActionGroup *group; gchar *prefix; gulong handler_ids[4]; } Group; static void gtk_action_muxer_append_group_actions (gpointer key, gpointer value, gpointer user_data) { const gchar *prefix = key; Group *group = value; GArray *actions = user_data; gchar **group_actions; gchar **action; group_actions = g_action_group_list_actions (group->group); for (action = group_actions; *action; action++) { gchar *fullname; fullname = g_strconcat (prefix, ".", *action, NULL); g_array_append_val (actions, fullname); } g_strfreev (group_actions); } static gchar ** gtk_action_muxer_list_actions (GActionGroup *action_group) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group); GArray *actions; actions = g_array_new (TRUE, FALSE, sizeof (gchar *)); for ( ; muxer != NULL; muxer = muxer->parent) { g_hash_table_foreach (muxer->groups, gtk_action_muxer_append_group_actions, actions); } return (gchar **) g_array_free (actions, FALSE); } static Group * gtk_action_muxer_find_group (GtkActionMuxer *muxer, const gchar *full_name, const gchar **action_name) { const gchar *dot; gchar *prefix; Group *group; dot = strchr (full_name, '.'); if (!dot) return NULL; prefix = g_strndup (full_name, dot - full_name); group = g_hash_table_lookup (muxer->groups, prefix); g_free (prefix); if (action_name) *action_name = dot + 1; return group; } static void gtk_action_muxer_action_enabled_changed (GtkActionMuxer *muxer, const gchar *action_name, gboolean enabled) { Action *action; GSList *node; action = g_hash_table_lookup (muxer->observed_actions, action_name); for (node = action ? action->watchers : NULL; node; node = node->next) gtk_action_observer_action_enabled_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, enabled); g_action_group_action_enabled_changed (G_ACTION_GROUP (muxer), action_name, enabled); } static void gtk_action_muxer_group_action_enabled_changed (GActionGroup *action_group, const gchar *action_name, gboolean enabled, gpointer user_data) { Group *group = user_data; gchar *fullname; fullname = g_strconcat (group->prefix, ".", action_name, NULL); gtk_action_muxer_action_enabled_changed (group->muxer, fullname, enabled); g_free (fullname); } static void gtk_action_muxer_parent_action_enabled_changed (GActionGroup *action_group, const gchar *action_name, gboolean enabled, gpointer user_data) { GtkActionMuxer *muxer = user_data; gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled); } static void gtk_action_muxer_action_state_changed (GtkActionMuxer *muxer, const gchar *action_name, GVariant *state) { Action *action; GSList *node; action = g_hash_table_lookup (muxer->observed_actions, action_name); for (node = action ? action->watchers : NULL; node; node = node->next) gtk_action_observer_action_state_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, state); g_action_group_action_state_changed (G_ACTION_GROUP (muxer), action_name, state); } static void gtk_action_muxer_group_action_state_changed (GActionGroup *action_group, const gchar *action_name, GVariant *state, gpointer user_data) { Group *group = user_data; gchar *fullname; fullname = g_strconcat (group->prefix, ".", action_name, NULL); gtk_action_muxer_action_state_changed (group->muxer, fullname, state); g_free (fullname); } static void gtk_action_muxer_parent_action_state_changed (GActionGroup *action_group, const gchar *action_name, GVariant *state, gpointer user_data) { GtkActionMuxer *muxer = user_data; gtk_action_muxer_action_state_changed (muxer, action_name, state); } static void gtk_action_muxer_action_added (GtkActionMuxer *muxer, const gchar *action_name, GActionGroup *original_group, const gchar *orignal_action_name) { const GVariantType *parameter_type; gboolean enabled; GVariant *state; Action *action; action = g_hash_table_lookup (muxer->observed_actions, action_name); if (action && action->watchers && g_action_group_query_action (original_group, orignal_action_name, &enabled, ¶meter_type, NULL, NULL, &state)) { GSList *node; for (node = action->watchers; node; node = node->next) gtk_action_observer_action_added (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, parameter_type, enabled, state); if (state) g_variant_unref (state); } g_action_group_action_added (G_ACTION_GROUP (muxer), action_name); } static void gtk_action_muxer_action_added_to_group (GActionGroup *action_group, const gchar *action_name, gpointer user_data) { Group *group = user_data; gchar *fullname; fullname = g_strconcat (group->prefix, ".", action_name, NULL); gtk_action_muxer_action_added (group->muxer, fullname, action_group, action_name); g_free (fullname); } static void gtk_action_muxer_action_added_to_parent (GActionGroup *action_group, const gchar *action_name, gpointer user_data) { GtkActionMuxer *muxer = user_data; gtk_action_muxer_action_added (muxer, action_name, action_group, action_name); } static void gtk_action_muxer_action_removed (GtkActionMuxer *muxer, const gchar *action_name) { Action *action; GSList *node; action = g_hash_table_lookup (muxer->observed_actions, action_name); for (node = action ? action->watchers : NULL; node; node = node->next) gtk_action_observer_action_removed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name); g_action_group_action_removed (G_ACTION_GROUP (muxer), action_name); } static void gtk_action_muxer_action_removed_from_group (GActionGroup *action_group, const gchar *action_name, gpointer user_data) { Group *group = user_data; gchar *fullname; fullname = g_strconcat (group->prefix, ".", action_name, NULL); gtk_action_muxer_action_removed (group->muxer, fullname); g_free (fullname); } static void gtk_action_muxer_action_removed_from_parent (GActionGroup *action_group, const gchar *action_name, gpointer user_data) { GtkActionMuxer *muxer = user_data; gtk_action_muxer_action_removed (muxer, action_name); } static gboolean gtk_action_muxer_query_action (GActionGroup *action_group, const gchar *action_name, gboolean *enabled, const GVariantType **parameter_type, const GVariantType **state_type, GVariant **state_hint, GVariant **state) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group); Group *group; const gchar *unprefixed_name; group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name); if (group) return g_action_group_query_action (group->group, unprefixed_name, enabled, parameter_type, state_type, state_hint, state); if (muxer->parent) return g_action_group_query_action (G_ACTION_GROUP (muxer->parent), action_name, enabled, parameter_type, state_type, state_hint, state); return FALSE; } static void gtk_action_muxer_activate_action (GActionGroup *action_group, const gchar *action_name, GVariant *parameter) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group); Group *group; const gchar *unprefixed_name; group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name); if (group) g_action_group_activate_action (group->group, unprefixed_name, parameter); else if (muxer->parent) g_action_group_activate_action (G_ACTION_GROUP (muxer->parent), action_name, parameter); } static void gtk_action_muxer_change_action_state (GActionGroup *action_group, const gchar *action_name, GVariant *state) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group); Group *group; const gchar *unprefixed_name; group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name); if (group) g_action_group_change_action_state (group->group, unprefixed_name, state); else if (muxer->parent) g_action_group_change_action_state (G_ACTION_GROUP (muxer->parent), action_name, state); } static void gtk_action_muxer_unregister_internal (Action *action, gpointer observer) { GtkActionMuxer *muxer = action->muxer; GSList **ptr; for (ptr = &action->watchers; *ptr; ptr = &(*ptr)->next) if ((*ptr)->data == observer) { *ptr = g_slist_remove (*ptr, observer); if (action->watchers == NULL) g_hash_table_remove (muxer->observed_actions, action->fullname); break; } } static void gtk_action_muxer_weak_notify (gpointer data, GObject *where_the_object_was) { Action *action = data; gtk_action_muxer_unregister_internal (action, where_the_object_was); } static void gtk_action_muxer_register_observer (GtkActionObservable *observable, const gchar *name, GtkActionObserver *observer) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable); Action *action; action = g_hash_table_lookup (muxer->observed_actions, name); if (action == NULL) { action = g_slice_new (Action); action->muxer = muxer; action->fullname = g_strdup (name); action->watchers = NULL; g_hash_table_insert (muxer->observed_actions, action->fullname, action); } action->watchers = g_slist_prepend (action->watchers, observer); g_object_weak_ref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action); } static void gtk_action_muxer_unregister_observer (GtkActionObservable *observable, const gchar *name, GtkActionObserver *observer) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable); Action *action; action = g_hash_table_lookup (muxer->observed_actions, name); g_object_weak_unref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action); gtk_action_muxer_unregister_internal (action, observer); } static void gtk_action_muxer_free_group (gpointer data) { Group *group = data; gint i; /* 'for loop' or 'four loop'? */ for (i = 0; i < 4; i++) g_signal_handler_disconnect (group->group, group->handler_ids[i]); g_object_unref (group->group); g_free (group->prefix); g_slice_free (Group, group); } static void gtk_action_muxer_free_action (gpointer data) { Action *action = data; GSList *it; for (it = action->watchers; it; it = it->next) g_object_weak_unref (G_OBJECT (it->data), gtk_action_muxer_weak_notify, action); g_slist_free (action->watchers); g_free (action->fullname); g_slice_free (Action, action); } static void gtk_action_muxer_finalize (GObject *object) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (object); g_assert_cmpint (g_hash_table_size (muxer->observed_actions), ==, 0); g_hash_table_unref (muxer->observed_actions); g_hash_table_unref (muxer->groups); G_OBJECT_CLASS (gtk_action_muxer_parent_class) ->finalize (object); } static void gtk_action_muxer_dispose (GObject *object) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (object); if (muxer->parent) { g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer); g_clear_object (&muxer->parent); } g_hash_table_remove_all (muxer->observed_actions); G_OBJECT_CLASS (gtk_action_muxer_parent_class) ->dispose (object); } static void gtk_action_muxer_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (object); switch (property_id) { case PROP_PARENT: g_value_set_object (value, gtk_action_muxer_get_parent (muxer)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void gtk_action_muxer_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { GtkActionMuxer *muxer = GTK_ACTION_MUXER (object); switch (property_id) { case PROP_PARENT: gtk_action_muxer_set_parent (muxer, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void gtk_action_muxer_init (GtkActionMuxer *muxer) { muxer->observed_actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_action); muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_group); } static void gtk_action_muxer_observable_iface_init (GtkActionObservableInterface *iface) { iface->register_observer = gtk_action_muxer_register_observer; iface->unregister_observer = gtk_action_muxer_unregister_observer; } static void gtk_action_muxer_group_iface_init (GActionGroupInterface *iface) { iface->list_actions = gtk_action_muxer_list_actions; iface->query_action = gtk_action_muxer_query_action; iface->activate_action = gtk_action_muxer_activate_action; iface->change_action_state = gtk_action_muxer_change_action_state; } static void gtk_action_muxer_class_init (GObjectClass *class) { class->get_property = gtk_action_muxer_get_property; class->set_property = gtk_action_muxer_set_property; class->finalize = gtk_action_muxer_finalize; class->dispose = gtk_action_muxer_dispose; properties[PROP_PARENT] = g_param_spec_object ("parent", "Parent", "The parent muxer", GTK_TYPE_ACTION_MUXER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (class, NUM_PROPERTIES, properties); } /** * gtk_action_muxer_insert: * @muxer: a #GtkActionMuxer * @prefix: the prefix string for the action group * @action_group: a #GActionGroup * * Adds the actions in @action_group to the list of actions provided by * @muxer. @prefix is prefixed to each action name, such that for each * action x in @action_group, there is an equivalent * action @prefix.x in @muxer. * * For example, if @prefix is "app" and @action_group * contains an action called "quit", then @muxer will * now contain an action called "app.quit". * * If any #GtkActionObservers are registered for actions in the group, * "action_added" notifications will be emitted, as appropriate. * * @prefix must not contain a dot ('.'). */ void gtk_action_muxer_insert (GtkActionMuxer *muxer, const gchar *prefix, GActionGroup *action_group) { gchar **actions; Group *group; gint i; /* TODO: diff instead of ripout and replace */ gtk_action_muxer_remove (muxer, prefix); group = g_slice_new (Group); group->muxer = muxer; group->group = g_object_ref (action_group); group->prefix = g_strdup (prefix); g_hash_table_insert (muxer->groups, group->prefix, group); actions = g_action_group_list_actions (group->group); for (i = 0; actions[i]; i++) gtk_action_muxer_action_added_to_group (group->group, actions[i], group); g_strfreev (actions); group->handler_ids[0] = g_signal_connect (group->group, "action-added", G_CALLBACK (gtk_action_muxer_action_added_to_group), group); group->handler_ids[1] = g_signal_connect (group->group, "action-removed", G_CALLBACK (gtk_action_muxer_action_removed_from_group), group); group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed", G_CALLBACK (gtk_action_muxer_group_action_enabled_changed), group); group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed", G_CALLBACK (gtk_action_muxer_group_action_state_changed), group); } /** * gtk_action_muxer_remove: * @muxer: a #GtkActionMuxer * @prefix: the prefix of the action group to remove * * Removes a #GActionGroup from the #GtkActionMuxer. * * If any #GtkActionObservers are registered for actions in the group, * "action_removed" notifications will be emitted, as appropriate. */ void gtk_action_muxer_remove (GtkActionMuxer *muxer, const gchar *prefix) { Group *group; group = g_hash_table_lookup (muxer->groups, prefix); if (group != NULL) { gchar **actions; gint i; g_hash_table_steal (muxer->groups, prefix); actions = g_action_group_list_actions (group->group); for (i = 0; actions[i]; i++) gtk_action_muxer_action_removed_from_group (group->group, actions[i], group); g_strfreev (actions); gtk_action_muxer_free_group (group); } } /** * gtk_action_muxer_new: * * Creates a new #GtkActionMuxer. */ GtkActionMuxer * gtk_action_muxer_new (void) { return g_object_new (GTK_TYPE_ACTION_MUXER, NULL); } /** * gtk_action_muxer_get_parent: * @muxer: a #GtkActionMuxer * * Returns: (transfer none): the parent of @muxer, or NULL. */ GtkActionMuxer * gtk_action_muxer_get_parent (GtkActionMuxer *muxer) { g_return_val_if_fail (GTK_IS_ACTION_MUXER (muxer), NULL); return muxer->parent; } /** * gtk_action_muxer_set_parent: * @muxer: a #GtkActionMuxer * @parent: (allow-none): the new parent #GtkActionMuxer * * Sets the parent of @muxer to @parent. */ void gtk_action_muxer_set_parent (GtkActionMuxer *muxer, GtkActionMuxer *parent) { g_return_if_fail (GTK_IS_ACTION_MUXER (muxer)); g_return_if_fail (parent == NULL || GTK_IS_ACTION_MUXER (parent)); if (muxer->parent == parent) return; if (muxer->parent != NULL) { gchar **actions; gchar **it; actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent)); for (it = actions; *it; it++) gtk_action_muxer_action_removed (muxer, *it); g_strfreev (actions); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer); g_object_unref (muxer->parent); } muxer->parent = parent; if (muxer->parent != NULL) { gchar **actions; gchar **it; g_object_ref (muxer->parent); actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent)); for (it = actions; *it; it++) gtk_action_muxer_action_added (muxer, *it, G_ACTION_GROUP (muxer->parent), *it); g_strfreev (actions); g_signal_connect (muxer->parent, "action-added", G_CALLBACK (gtk_action_muxer_action_added_to_parent), muxer); g_signal_connect (muxer->parent, "action-removed", G_CALLBACK (gtk_action_muxer_action_removed_from_parent), muxer); g_signal_connect (muxer->parent, "action-enabled-changed", G_CALLBACK (gtk_action_muxer_parent_action_enabled_changed), muxer); g_signal_connect (muxer->parent, "action-state-changed", G_CALLBACK (gtk_action_muxer_parent_action_state_changed), muxer); } g_object_notify_by_pspec (G_OBJECT (muxer), properties[PROP_PARENT]); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkactionobservable.c0000644000015201777760000000513712305545024026674 0ustar pbusernogroup00000000000000/* * Copyright © 2011 Canonical Limited * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 of the * licence or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: Ryan Lortie */ #include "config.h" #include "gtkactionobservable.h" G_DEFINE_INTERFACE (GtkActionObservable, gtk_action_observable, G_TYPE_OBJECT) /* * SECTION:gtkactionobserable * @short_description: an interface implemented by objects that report * changes to actions */ void gtk_action_observable_default_init (GtkActionObservableInterface *iface) { } /** * gtk_action_observable_register_observer: * @observable: a #GtkActionObservable * @action_name: the name of the action * @observer: the #GtkActionObserver to which the events will be reported * * Registers @observer as being interested in changes to @action_name on * @observable. */ void gtk_action_observable_register_observer (GtkActionObservable *observable, const gchar *action_name, GtkActionObserver *observer) { g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable)); GTK_ACTION_OBSERVABLE_GET_IFACE (observable) ->register_observer (observable, action_name, observer); } /** * gtk_action_observable_unregister_observer: * @observable: a #GtkActionObservable * @action_name: the name of the action * @observer: the #GtkActionObserver to which the events will be reported * * Removes the registration of @observer as being interested in changes * to @action_name on @observable. * * If the observer was registered multiple times, it must be * unregistered an equal number of times. */ void gtk_action_observable_unregister_observer (GtkActionObservable *observable, const gchar *action_name, GtkActionObserver *observer) { g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable)); GTK_ACTION_OBSERVABLE_GET_IFACE (observable) ->unregister_observer (observable, action_name, observer); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkmenutrackeritem.h0000644000015201777760000001232012305545024026546 0ustar pbusernogroup00000000000000/* * Copyright © 2011, 2013 Canonical Limited * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the licence, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Author: Ryan Lortie */ #ifndef __GTK_MENU_TRACKER_ITEM_H__ #define __GTK_MENU_TRACKER_ITEM_H__ #include "gtkactionobservable.h" #define GTK_TYPE_MENU_TRACKER_ITEM (gtk_menu_tracker_item_get_type ()) #define GTK_MENU_TRACKER_ITEM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ GTK_TYPE_MENU_TRACKER_ITEM, GtkMenuTrackerItem)) #define GTK_IS_MENU_TRACKER_ITEM(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ GTK_TYPE_MENU_TRACKER_ITEM)) typedef struct _GtkMenuTrackerItem GtkMenuTrackerItem; #define GTK_TYPE_MENU_TRACKER_ITEM_ROLE (gtk_menu_tracker_item_role_get_type ()) typedef enum { GTK_MENU_TRACKER_ITEM_ROLE_NORMAL, GTK_MENU_TRACKER_ITEM_ROLE_CHECK, GTK_MENU_TRACKER_ITEM_ROLE_RADIO, } GtkMenuTrackerItemRole; GType gtk_menu_tracker_item_get_type (void) G_GNUC_CONST; GType gtk_menu_tracker_item_role_get_type (void) G_GNUC_CONST; GtkMenuTrackerItem * _gtk_menu_tracker_item_new (GtkActionObservable *observable, GMenuModel *model, gint item_index, const gchar *action_namespace, gboolean is_separator); GtkActionObservable * _gtk_menu_tracker_item_get_observable (GtkMenuTrackerItem *self); gboolean gtk_menu_tracker_item_get_is_separator (GtkMenuTrackerItem *self); gboolean gtk_menu_tracker_item_get_has_submenu (GtkMenuTrackerItem *self); const gchar * gtk_menu_tracker_item_get_label (GtkMenuTrackerItem *self); GIcon * gtk_menu_tracker_item_get_icon (GtkMenuTrackerItem *self); gboolean gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self); gboolean gtk_menu_tracker_item_get_visible (GtkMenuTrackerItem *self); GtkMenuTrackerItemRole gtk_menu_tracker_item_get_role (GtkMenuTrackerItem *self); gboolean gtk_menu_tracker_item_get_toggled (GtkMenuTrackerItem *self); const gchar * gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self); GMenuModel * _gtk_menu_tracker_item_get_submenu (GtkMenuTrackerItem *self); gchar * _gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self); gboolean gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self); void gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self); void gtk_menu_tracker_item_change_state (GtkMenuTrackerItem *self, GVariant *value); void gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self, gboolean shown); gboolean gtk_menu_tracker_item_get_submenu_shown (GtkMenuTrackerItem *self); gchar * gtk_menu_tracker_item_get_action_name (GtkMenuTrackerItem *self); GVariant * gtk_menu_tracker_item_get_action_state (GtkMenuTrackerItem *self); const gchar * gtk_menu_tracker_item_get_action_namespace (GtkMenuTrackerItem *self); gboolean gtk_menu_tracker_item_get_attribute (GtkMenuTrackerItem *self, const gchar *attribute, const gchar *format, ...); GVariant * gtk_menu_tracker_item_get_attribute_value (GtkMenuTrackerItem *self, const gchar *attribute, const GVariantType *expected_type); #endif qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkactionmuxer.h0000644000015201777760000000462012305545024025711 0ustar pbusernogroup00000000000000/* * Copyright © 2011 Canonical Limited * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the licence, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Author: Ryan Lortie */ #ifndef __GTK_ACTION_MUXER_H__ #define __GTK_ACTION_MUXER_H__ #include G_BEGIN_DECLS #define GTK_TYPE_ACTION_MUXER (gtk_action_muxer_get_type ()) #define GTK_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ GTK_TYPE_ACTION_MUXER, GtkActionMuxer)) #define GTK_IS_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ GTK_TYPE_ACTION_MUXER)) typedef struct _GtkActionMuxer GtkActionMuxer; GType gtk_action_muxer_get_type (void); GtkActionMuxer * gtk_action_muxer_new (void); void gtk_action_muxer_insert (GtkActionMuxer *muxer, const gchar *prefix, GActionGroup *action_group); void gtk_action_muxer_remove (GtkActionMuxer *muxer, const gchar *prefix); GtkActionMuxer * gtk_action_muxer_get_parent (GtkActionMuxer *muxer); void gtk_action_muxer_set_parent (GtkActionMuxer *muxer, GtkActionMuxer *parent); G_END_DECLS #endif /* __GTK_ACTION_MUXER_H__ */ qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkactionobserver.c0000644000015201777760000001360212305545024026373 0ustar pbusernogroup00000000000000/* * Copyright © 2011 Canonical Limited * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 of the * licence or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: Ryan Lortie */ #include "config.h" #include "gtkactionobserver.h" G_DEFINE_INTERFACE (GtkActionObserver, gtk_action_observer, G_TYPE_OBJECT) /** * SECTION:gtkactionobserver * @short_description: an interface implemented by objects that are * interested in monitoring actions for changes * * GtkActionObserver is a simple interface allowing objects that wish to * be notified of changes to actions to be notified of those changes. * * It is also possible to monitor changes to action groups using * #GObject signals, but there are a number of reasons that this * approach could become problematic: * * - there are four separate signals that must be manually connected * and disconnected * * - when a large number of different observers wish to monitor a * (usually disjoint) set of actions within the same action group, * there is only one way to avoid having all notifications delivered * to all observers: signal detail. In order to use signal detail, * each action name must be quarked, which is not always practical. * * - even if quarking is acceptable, #GObject signal details are * implemented by scanning a linked list, so there is no real * decrease in complexity */ void gtk_action_observer_default_init (GtkActionObserverInterface *class) { } /** * gtk_action_observer_action_added: * @observer: a #GtkActionObserver * @observable: the source of the event * @action_name: the name of the action * @enabled: %TRUE if the action is now enabled * @parameter_type: the parameter type for action invocations, or %NULL * if no parameter is required * @state: the current state of the action, or %NULL if the action is * stateless * * This function is called when an action that the observer is * registered to receive events for is added. * * This function should only be called by objects with which the * observer has explicitly registered itself to receive events. */ void gtk_action_observer_action_added (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, const GVariantType *parameter_type, gboolean enabled, GVariant *state) { g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer)); GTK_ACTION_OBSERVER_GET_IFACE (observer) ->action_added (observer, observable, action_name, parameter_type, enabled, state); } /** * gtk_action_observer_action_enabled_changed: * @observer: a #GtkActionObserver * @observable: the source of the event * @action_name: the name of the action * @enabled: %TRUE if the action is now enabled * * This function is called when an action that the observer is * registered to receive events for becomes enabled or disabled. * * This function should only be called by objects with which the * observer has explicitly registered itself to receive events. */ void gtk_action_observer_action_enabled_changed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, gboolean enabled) { g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer)); GTK_ACTION_OBSERVER_GET_IFACE (observer) ->action_enabled_changed (observer, observable, action_name, enabled); } /** * gtk_action_observer_action_state_changed: * @observer: a #GtkActionObserver * @observable: the source of the event * @action_name: the name of the action * @state: the new state of the action * * This function is called when an action that the observer is * registered to receive events for changes to its state. * * This function should only be called by objects with which the * observer has explicitly registered itself to receive events. */ void gtk_action_observer_action_state_changed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name, GVariant *state) { g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer)); GTK_ACTION_OBSERVER_GET_IFACE (observer) ->action_state_changed (observer, observable, action_name, state); } /** * gtk_action_observer_action_removed: * @observer: a #GtkActionObserver * @observable: the source of the event * @action_name: the name of the action * * This function is called when an action that the observer is * registered to receive events for is removed. * * This function should only be called by objects with which the * observer has explicitly registered itself to receive events. */ void gtk_action_observer_action_removed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name) { g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer)); GTK_ACTION_OBSERVER_GET_IFACE (observer) ->action_removed (observer, observable, action_name); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/config.h0000644000015201777760000000000012305545024024076 0ustar pbusernogroup00000000000000qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qstateaction.h0000644000015201777760000000343712305545024024564 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #ifndef QDBUSACTION_H #define QDBUSACTION_H #include #include class QDBusActionGroup; class QStateAction : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name) Q_PROPERTY(QVariant state READ state NOTIFY stateChanged) Q_PROPERTY(bool valid READ isValid NOTIFY validChanged) public: QVariant state() const; bool isValid() const; Q_INVOKABLE void activate(const QVariant ¶meter = QVariant()); Q_INVOKABLE void updateState(const QVariant ¶meter); Q_SIGNALS: void stateChanged(QVariant state); void validChanged(bool valid); private Q_SLOTS: void onActionAppear(const QString &name); void onActionVanish(const QString &name); void onActionStateChanged(const QString &name, const QVariant &state); private: QDBusActionGroup *m_group; QVariant m_state; bool m_valid; QString m_name; QStateAction(QDBusActionGroup *group, const QString &name); void setValid(bool valid); void setState(const QVariant &state); QString name() const; friend class QDBusActionGroup; }; #endif qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qmenumodel.pc.in0000644000015201777760000000053512305545024025007 0ustar pbusernogroup00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ Name: qmenumodel Description: Qt binding for GMenuModel. Version: 0.1 Requires.private: Qt5Core Qt5Widgets gio-2.0 Libs: -L${libdir} -l@SHAREDLIBNAME@ Cflags: -I${includedir}/@INCLUDEDIR@ qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/actionstateparser.cpp0000644000015201777760000000175612305545024026155 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Nick Dedekind */ #include "actionstateparser.h" #include "converter.h" ActionStateParser::ActionStateParser(QObject* parent) : QObject(parent) { } QVariant ActionStateParser::toQVariant(GVariant* state) const { if (state) { return Converter::toQVariant(state); } return QVariant(); }qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/converter.h0000644000015201777760000000227412305545024024072 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #ifndef CONVERTER_H #define CONVERTER_H typedef struct _GVariant GVariant; class QVariant; class Converter { public: static QVariant toQVariant(GVariant *value); static GVariant* toGVariant(const QVariant &value); // This converts a QVariant to a GVariant using a provided gvariant schema as // a conversion base (it will attempt to convert to this format). static GVariant* toGVariantWithSchema(const QVariant &value, const char* schema); }; #endif // CONVERTER_H qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/CMakeLists.txt0000644000015201777760000000326412305545024024452 0ustar pbusernogroup00000000000000project(src) set(QMENUMODEL_SRC actionstateparser.cpp converter.cpp dbus-enums.h menunode.cpp qmenumodel.cpp qdbusobject.cpp qdbusmenumodel.cpp qdbusactiongroup.cpp qmenumodelevents.cpp qstateaction.cpp unitymenuaction.cpp unitymenuactionevents.cpp unitymenumodel.cpp unitymenumodelevents.cpp gtk/gtkactionmuxer.c gtk/gtkactionmuxer.h gtk/gtkactionobservable.c gtk/gtkactionobservable.h gtk/gtkactionobserver.c gtk/gtkactionobserver.h gtk/gtksimpleactionobserver.c gtk/gtksimpleactionobserver.h gtk/gtkmenutracker.c gtk/gtkmenutracker.h gtk/gtkmenutrackeritem.c gtk/gtkmenutrackeritem.h ) set(SHAREDLIBNAME qmenumodel) add_library(${SHAREDLIBNAME} SHARED ${QMENUMODEL_SRC} ) set_target_properties(${SHAREDLIBNAME} PROPERTIES COMPILE_FLAGS -fPIC SOVERSION 0 VERSION 0.1.1 ) include_directories( ${GLIB_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ) target_link_libraries(${SHAREDLIBNAME} ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ) qt5_use_modules(${SHAREDLIBNAME} Core Qml Quick) install(TARGETS ${SHAREDLIBNAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) set(QMENUMODEL_HEADERS actionstateparser.h dbus-enums.h qdbusactiongroup.h qdbusmenumodel.h qdbusobject.h qmenumodel.h qstateaction.h unitymenuaction.h unitymenumodel.h ) set(INCLUDEDIR qmenumodel) install(FILES ${QMENUMODEL_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${INCLUDEDIR} ) set(PCFILE qmenumodel.pc) configure_file(${PCFILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PCFILE} @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PCFILE} DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qdbusactiongroup.h0000644000015201777760000000601412305545024025450 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #ifndef QDBUSACTIONGROUP_H #define QDBUSACTIONGROUP_H #include "qdbusobject.h" #include #include class QStateAction; typedef char gchar; typedef void* gpointer; typedef struct _GVariant GVariant; typedef struct _GActionGroup GActionGroup; typedef struct _GDBusActionGroup GDBusActionGroup; class QDBusActionGroup : public QObject, public QDBusObject { Q_OBJECT Q_PROPERTY(int busType READ busType WRITE setIntBusType NOTIFY busTypeChanged) Q_PROPERTY(QString busName READ busName WRITE setBusName NOTIFY busNameChanged) Q_PROPERTY(QString objectPath READ objectPath WRITE setObjectPath NOTIFY objectPathChanged) Q_PROPERTY(int status READ status NOTIFY statusChanged) public: QDBusActionGroup(QObject *parent=0); ~QDBusActionGroup(); void updateActionState(const QString &name, const QVariant &state); void activateAction(const QString &name, const QVariant ¶meter); bool hasAction(const QString &name); Q_INVOKABLE QStateAction *action(const QString &name); Q_INVOKABLE QVariant actionState(const QString &name); Q_SIGNALS: void busTypeChanged(DBusEnums::BusType type); void busNameChanged(const QString &busNameChanged); void objectPathChanged(const QString &objectPath); void statusChanged(DBusEnums::ConnectionStatus status); void actionAppear(const QString &name); void actionVanish(const QString &name); void actionStateChanged(const QString &name, QVariant state); public Q_SLOTS: void start(); void stop(); protected: virtual void serviceAppear(GDBusConnection *connection); virtual void serviceVanish(GDBusConnection *connection); virtual bool event(QEvent* e); private: GActionGroup *m_actionGroup; int m_signalActionAddId; int m_signalActionRemovedId; int m_signalStateChangedId; // workaround to support int as busType void setIntBusType(int busType); void setActionGroup(GDBusActionGroup *ag); QStateAction *actionImpl(const QString &name); void clear(); // glib slots static void onActionAdded(GDBusActionGroup *ag, gchar *name, gpointer data); static void onActionRemoved(GDBusActionGroup *ag, gchar *name, gpointer data); static void onActionStateChanged(GDBusActionGroup *ag, gchar *name, GVariant *value, gpointer data); }; #endif // QDBUSACTIONGROUP_H qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qmenumodelevents.cpp0000644000015201777760000000526212305545024026011 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Nicholas Dedekind #include } #include "qmenumodelevents.h" const QEvent::Type MenuNodeItemChangeEvent::eventType = static_cast(QEvent::registerEventType()); const QEvent::Type DBusActionStateEvent::eventType = static_cast(QEvent::registerEventType()); const QEvent::Type DBusActionVisiblityEvent::eventType = static_cast(QEvent::registerEventType()); const QEvent::Type MenuModelEvent::eventType = static_cast(QEvent::registerEventType()); const QEvent::Type DbusObjectServiceEvent::eventType = static_cast(QEvent::registerEventType()); MenuNodeItemChangeEvent::MenuNodeItemChangeEvent(MenuNode* _node, int _position, int _removed, int _added) : QEvent(MenuNodeItemChangeEvent::eventType), node(_node), position(_position), removed(_removed), added(_added) {} DBusActionEvent::DBusActionEvent(const QString& _name, QEvent::Type type) : QEvent(type), name(_name) { } DBusActionVisiblityEvent::DBusActionVisiblityEvent(const QString& _name, bool _visible) : DBusActionEvent(_name, DBusActionVisiblityEvent::eventType), visible(_visible) { } DBusActionStateEvent::DBusActionStateEvent(const QString& _name, const QVariant& _state) : DBusActionEvent(_name, DBusActionStateEvent::eventType), state(_state) { } DbusObjectServiceEvent::DbusObjectServiceEvent(GDBusConnection* _connection, bool _visible) : QEvent(DbusObjectServiceEvent::eventType), connection(_connection), visible(_visible) { if (connection) { g_object_ref(connection); } } DbusObjectServiceEvent::~DbusObjectServiceEvent() { if (connection) { g_object_unref(connection); } } MenuModelEvent::MenuModelEvent(GMenuModel* _model) : QEvent(MenuModelEvent::eventType), model(_model) { if (model) { g_object_ref(model); } } MenuModelEvent::~MenuModelEvent() { if (model) { g_object_unref(model); } } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/converter.cpp0000644000015201777760000002643112305545024024426 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ extern "C" { #include } #include "converter.h" #include #include /*! \internal */ QVariant Converter::toQVariant(GVariant *value) { QVariant result; if (value == NULL) { return result; } const GVariantType *type = g_variant_get_type(value); if (g_variant_type_equal(type, G_VARIANT_TYPE_BOOLEAN)) { result.setValue((bool)g_variant_get_boolean(value)); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE)) { result.setValue(g_variant_get_byte(value)); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16)) { result.setValue(qint16(g_variant_get_int16(value))); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16)) { result.setValue(quint16(g_variant_get_uint16(value))); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32)) { result.setValue(qint32(g_variant_get_int32(value))); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32)) { result.setValue(quint32(g_variant_get_uint32(value))); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64)) { result.setValue(qint64(g_variant_get_int64(value))); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64)) { result.setValue(quint64(g_variant_get_uint64(value))); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_DOUBLE)) { result.setValue(g_variant_get_double(value)); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_STRING)) { gsize size = 0; const gchar *v = g_variant_get_string(value, &size); result.setValue(QString::fromUtf8(v, size)); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_VARIANT)) { GVariant *var = g_variant_get_variant(value); result = toQVariant(var); g_variant_unref(var); } else if (g_variant_type_equal(type, G_VARIANT_TYPE_VARDICT)) { GVariantIter iter; GVariant *vvalue; gchar *key; QVariantMap qmap; g_variant_iter_init (&iter, value); while (g_variant_iter_loop (&iter, "{sv}", &key, &vvalue)) { qmap.insert(QString::fromUtf8(key), toQVariant(vvalue)); } result.setValue(qmap); } else if (g_variant_type_is_array(type)) { QVariantList lst; for (int i = 0, iMax = g_variant_n_children(value); i < iMax; i++) { GVariant *child = g_variant_get_child_value(value, i); lst << toQVariant(child); g_variant_unref(child); } result.setValue(lst); } else if (g_variant_type_is_tuple(type)) { gsize size = g_variant_n_children(value); QVariantList vlist; for (gsize i=0; i < size; i++) { GVariant *v = g_variant_get_child_value(value, i); if (v) { vlist << toQVariant(v); g_variant_unref(v); } } result.setValue(vlist); } else { qWarning() << "Unsupported GVariant value" << (char*) type; } /* TODO: implement convertions to others types * G_VARIANT_TYPE_HANDLE * G_VARIANT_TYPE_OBJECT_PATH * G_VARIANT_TYPE_SIGNATURE * G_VARIANT_TYPE_ANY * G_VARIANT_TYPE_BASIC * G_VARIANT_TYPE_MAYBE * G_VARIANT_TYPE_UNIT * G_VARIANT_TYPE_DICT_ENTRY * G_VARIANT_TYPE_DICTIONARY * G_VARIANT_TYPE_STRING_ARRAY * G_VARIANT_TYPE_BYTESTRING * G_VARIANT_TYPE_OBJECT_PATH_ARRAY * G_VARIANT_TYPE_BYTESTRING_ARRAY */ return result; } static GVariant* toGVariant(const QString &typeName, const QVariant &value) { if (typeName == "uchar") { return g_variant_new_byte(value.value()); } else if (typeName == "short") { return g_variant_new_int16(value.value()); } else if (typeName == "ushort") { return g_variant_new_uint16(value.value()); } else if (typeName == "long") { return g_variant_new_int64(value.value()); } else if (typeName == "ulong") { return g_variant_new_uint64(value.value()); } else { qWarning() << "QVariant type not supported:" << typeName; } return NULL; } GVariant* Converter::toGVariant(const QVariant &value) { GVariant *result = NULL; if (value.isNull() || !value.isValid()) return result; switch(value.type()) { case QVariant::Bool: result = g_variant_new_boolean(value.toBool()); break; case QVariant::ByteArray: result = g_variant_new_bytestring(value.toByteArray()); break; case QVariant::Double: result = g_variant_new_double(value.toDouble()); break; case QVariant::Int: result = g_variant_new_int32(value.toInt()); break; case QVariant::String: result = g_variant_new_string(value.toString().toUtf8().data()); break; case QVariant::UInt: result = g_variant_new_uint32(value.toUInt()); break; case QVariant::Map: { GVariantBuilder *b; GVariant *dict; b = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); QMapIterator i(value.toMap()); while (i.hasNext()) { i.next(); g_variant_builder_add(b, "{sv}", i.key().toUtf8().data(), toGVariant(i.value())); } result = g_variant_builder_end(b); g_variant_builder_unref(b); break; } case QVariant::List: { QVariantList lst = value.toList(); GVariant **vars = g_new(GVariant*, lst.size()); for (int i=0; i < lst.size(); i++) { vars[i] = toGVariant(lst[i]); } result = g_variant_new_tuple(vars, lst.size()); g_free(vars); break; } default: result = ::toGVariant(value.typeName(), value); } return result; } GVariant* Converter::toGVariantWithSchema(const QVariant &value, const char* schema) { if (!g_variant_type_string_is_valid(schema)) { return Converter::toGVariant(value); } GVariant* result = NULL; const GVariantType* schema_type; schema_type = g_variant_type_new(schema); if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_BOOLEAN)) { if (value.canConvert()) { result = g_variant_new_boolean (value.value()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_BYTE)) { if (value.canConvert()) { result = g_variant_new_byte (value.value()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_INT16)) { if (value.canConvert()) { result = g_variant_new_int16 (value.value()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_UINT16)) { if (value.canConvert()) { result = g_variant_new_uint16 (value.value()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_INT32)) { if (value.canConvert()) { result = g_variant_new_int32 (value.value()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_UINT32)) { if (value.canConvert()) { result = g_variant_new_uint32 (value.value()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_INT64)) { if (value.canConvert()) { result = g_variant_new_int64 (value.value()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_UINT64)) { if (value.canConvert()) { result = g_variant_new_uint64 (value.value()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_DOUBLE)) { if (value.canConvert()) { result = g_variant_new_double (value.value()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_STRING)) { if (value.canConvert()) { result = g_variant_new_string(value.toString().toUtf8().data()); } } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_VARIANT)) { result = Converter::toGVariant(value); } else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_VARDICT)) { if (value.canConvert(QVariant::Map)) { result = Converter::toGVariant(value.toMap()); } } else if (g_variant_type_is_array(schema_type)) { if (value.canConvert(QVariant::List)) { const GVariantType* entry_type; GVariant* data; entry_type = g_variant_type_element(schema_type); gchar* entryTypeString = g_variant_type_dup_string(entry_type); QVariantList lst = value.toList(); GVariant **vars = g_new(GVariant*, lst.size()); bool ok = true; for (int i=0; i < lst.size(); i++) { data = Converter::toGVariantWithSchema(lst[i], entryTypeString); if (data) { vars[i] = data; } else { ok = false; qWarning() << "Failed to convert list to array with schema:" << schema; break; } } if (ok) { result = g_variant_new_array(entry_type, vars, lst.size()); } g_free(entryTypeString); g_free(vars); } } else if (g_variant_type_is_tuple(schema_type)) { if (value.canConvert(QVariant::List)) { GVariant* data; QVariantList lst = value.toList(); GVariant **vars = g_new(GVariant*, lst.size()); const GVariantType* entry_type = g_variant_type_first(schema_type); bool ok = true; for (int i=0; i < lst.size(); i++) { gchar* entryTypeString = g_variant_type_dup_string(entry_type); data = Converter::toGVariantWithSchema(lst[i], entryTypeString); if (data) { vars[i] = data; } else { ok = false; qWarning() << "Failed to convert list to tuple with schema:" << schema; g_free(entryTypeString); break; } g_free(entryTypeString); entry_type = g_variant_type_next(entry_type); if (!entry_type) { break; } } if (ok) { result = g_variant_new_tuple(vars, lst.size()); } g_free(vars); } } // fallback to straight convert. if (!result) { result = Converter::toGVariant(value); } return result; } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/actionstateparser.h0000644000015201777760000000202612305545024025611 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Nick Dedekind */ #ifndef ACTIONSTATEPARSER_H #define ACTIONSTATEPARSER_H #include #include typedef struct _GVariant GVariant; class ActionStateParser : public QObject { Q_OBJECT public: ActionStateParser(QObject* parent = 0); virtual QVariant toQVariant(GVariant* state) const; }; #endif // ACTIONSTATEPARSER_H qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/unitymenuaction.cpp0000644000015201777760000000717012305545024025651 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: Nick Dedekind */ #include "unitymenuaction.h" #include "unitymenumodel.h" #include "unitymenuactionevents.h" #include UnityMenuAction::UnityMenuAction(QObject* parent) : QObject(parent), m_valid(false), m_enabled(false), m_model(NULL), m_index(-1) { } UnityMenuAction::~UnityMenuAction() { if (m_model) { m_model->unregisterAction(this); } } QString UnityMenuAction::name() const { return m_name; } void UnityMenuAction::setName(const QString& name) { if (m_name != name) { m_name = name; Q_EMIT nameChanged(m_name); } } UnityMenuModel* UnityMenuAction::model() const { return m_model; } void UnityMenuAction::setModel(UnityMenuModel* model) { if (m_model != model) { if (!model) { unregisterAction(); } m_model = model; registerAction(); Q_EMIT modelChanged(model); } } QVariant UnityMenuAction::state() const { return m_state; } void UnityMenuAction::setState(const QVariant& state) { if (m_state != state) { m_state = state; Q_EMIT stateChanged(m_state); } } bool UnityMenuAction::isEnabled() const { return m_enabled; } void UnityMenuAction::setEnabled(bool enabled) { if (m_enabled != enabled) { m_enabled = enabled; Q_EMIT enabledChanged(m_enabled); } } bool UnityMenuAction::isValid() const { return m_valid; } void UnityMenuAction::setValid(bool valid) { if (m_valid != valid) { m_valid = valid; Q_EMIT validChanged(m_valid); } } int UnityMenuAction::index() const { return m_index; } void UnityMenuAction::setIndex(int i) { if (i != m_index) { m_index = i; Q_EMIT indexChanged(m_index); } } void UnityMenuAction::registerAction() { if (m_model) { m_model->registerAction(this); } } void UnityMenuAction::unregisterAction() { if (m_model) { m_model->unregisterAction(this); } } bool UnityMenuAction::event(QEvent* e) { if (e->type() == UnityMenuActionAddEvent::eventType) { UnityMenuActionAddEvent *umaae = static_cast(e); setEnabled(umaae->enabled); setState(umaae->state); setValid(true); return true; } else if (e->type() == UnityMenuActionEnabledChangedEvent::eventType) { UnityMenuActionEnabledChangedEvent *umaece = static_cast(e); setEnabled(umaece->enabled); return true; } else if (e->type() == UnityMenuActionStateChangeEvent::eventType) { UnityMenuActionStateChangeEvent *umasce = static_cast(e); setState(umasce->state); return true; } else if (e->type() == UnityMenuActionRemoveEvent::eventType) { UnityMenuActionRemoveEvent *umare = static_cast(e); setValid(false); return true; } return QObject::event(e); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/unitymenumodel.cpp0000644000015201777760000007256312305545024025504 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: Lars Uebernickel */ #include "unitymenumodel.h" #include "converter.h" #include "actionstateparser.h" #include "unitymenumodelevents.h" #include "unitymenuaction.h" #include "unitymenuactionevents.h" #include #include #include extern "C" { #include "gtk/gtkactionmuxer.h" #include "gtk/gtkmenutracker.h" #include "gtk/gtksimpleactionobserver.h" } G_DEFINE_QUARK (UNITY_MENU_MODEL, unity_menu_model) G_DEFINE_QUARK (UNITY_SUBMENU_MODEL, unity_submenu_model) G_DEFINE_QUARK (UNITY_MENU_ITEM_EXTENDED_ATTRIBUTES, unity_menu_item_extended_attributes) G_DEFINE_QUARK (UNITY_MENU_ACTION, unity_menu_action) enum MenuRoles { LabelRole = Qt::DisplayRole + 1, SensitiveRole, IsSeparatorRole, IconRole, TypeRole, ExtendedAttributesRole, ActionRole, ActionStateRole, IsCheckRole, IsRadioRole, IsToggledRole }; class UnityMenuModelPrivate { public: UnityMenuModelPrivate(UnityMenuModel *model); UnityMenuModelPrivate(const UnityMenuModelPrivate& other, UnityMenuModel *model); ~UnityMenuModelPrivate(); void clearItems(bool resetModel=true); void clearName(); void updateActions(); void updateMenuModel(); QVariant itemState(GtkMenuTrackerItem *item); UnityMenuModel *model; GtkActionMuxer *muxer; GtkMenuTracker *menutracker; GSequence *items; GDBusConnection *connection; QByteArray busName; QByteArray nameOwner; guint nameWatchId; QVariantMap actions; QByteArray menuObjectPath; QHash roles; ActionStateParser* actionStateParser; QHash registeredActions; static void nameAppeared(GDBusConnection *connection, const gchar *name, const gchar *owner, gpointer user_data); static void nameVanished(GDBusConnection *connection, const gchar *name, gpointer user_data); static void menuItemInserted(GtkMenuTrackerItem *item, gint position, gpointer user_data); static void menuItemRemoved(gint position, gpointer user_data); static void menuItemChanged(GObject *object, GParamSpec *pspec, gpointer user_data); static void registeredActionAdded(GtkSimpleActionObserver *observer_item, const gchar *action_name, gboolean enabled, GVariant *state); static void registeredActionEnabledChanged(GtkSimpleActionObserver *observer_item, const gchar *action_name, gboolean enabled); static void registeredActionStateChanged(GtkSimpleActionObserver *observer_item, const gchar *action_name, GVariant *state); static void registeredActionRemoved(GtkSimpleActionObserver *observer_item, const gchar *action_name); gchar * fullActionName(UnityMenuAction *action); void updateRegisteredAction(UnityMenuAction *action); }; void menu_item_free (gpointer data) { GtkMenuTrackerItem *item = (GtkMenuTrackerItem *) data; g_signal_handlers_disconnect_by_func (item, (gpointer) UnityMenuModelPrivate::menuItemChanged, NULL); g_object_unref (item); } UnityMenuModelPrivate::UnityMenuModelPrivate(UnityMenuModel *model) { this->model = model; this->menutracker = NULL; this->connection = NULL; this->nameWatchId = 0; this->actionStateParser = new ActionStateParser(model); this->muxer = gtk_action_muxer_new (); this->items = g_sequence_new (menu_item_free); } UnityMenuModelPrivate::UnityMenuModelPrivate(const UnityMenuModelPrivate& other, UnityMenuModel *model) { this->model = model; this->menutracker = NULL; this->connection = NULL; this->nameWatchId = 0; this->actionStateParser = new ActionStateParser(model); this->muxer = GTK_ACTION_MUXER( g_object_ref(other.muxer)); this->items = g_sequence_new (menu_item_free); } UnityMenuModelPrivate::~UnityMenuModelPrivate() { this->clearItems(false); g_sequence_free(this->items); g_clear_pointer (&this->menutracker, gtk_menu_tracker_free); g_clear_object (&this->muxer); g_clear_object (&this->connection); QHash::const_iterator it = this->registeredActions.constBegin(); for (; it != this->registeredActions.constEnd(); ++it) { g_object_unref(it.value()); } this->registeredActions.clear(); if (this->nameWatchId) g_bus_unwatch_name (this->nameWatchId); } void UnityMenuModelPrivate::clearItems(bool resetModel) { UnityMenuModelClearEvent ummce(resetModel); QCoreApplication::sendEvent(model, &ummce); } void UnityMenuModelPrivate::clearName() { this->clearItems(); this->nameOwner = QByteArray(); this->updateActions(); this->updateMenuModel(); } void UnityMenuModelPrivate::updateActions() { Q_FOREACH (QString prefix, this->actions.keys()) gtk_action_muxer_remove (this->muxer, prefix.toUtf8()); if (this->nameOwner.isEmpty()) return; for (QVariantMap::const_iterator it = this->actions.constBegin(); it != this->actions.constEnd(); ++it) { GDBusActionGroup *actions; actions = g_dbus_action_group_get (this->connection, this->nameOwner, it.value().toByteArray()); gtk_action_muxer_insert (this->muxer, it.key().toUtf8(), G_ACTION_GROUP (actions)); g_object_unref (actions); } } void UnityMenuModelPrivate::updateMenuModel() { this->clearItems(); g_clear_pointer (&this->menutracker, gtk_menu_tracker_free); if (!this->nameOwner.isEmpty()) { GDBusMenuModel *menu; menu = g_dbus_menu_model_get (this->connection, this->nameOwner, this->menuObjectPath.constData()); this->menutracker = gtk_menu_tracker_new (GTK_ACTION_OBSERVABLE (this->muxer), G_MENU_MODEL (menu), TRUE, NULL, menuItemInserted, menuItemRemoved, this); g_object_unref (menu); } } QVariant UnityMenuModelPrivate::itemState(GtkMenuTrackerItem *item) { QVariant result; GVariant *state = gtk_menu_tracker_item_get_action_state (item); if (state != NULL) { if (actionStateParser != NULL) { result = actionStateParser->toQVariant(state); } g_variant_unref (state); } return result; } void UnityMenuModelPrivate::nameAppeared(GDBusConnection *connection, const gchar *name, const gchar *owner, gpointer user_data) { UnityMenuModelPrivate *priv = (UnityMenuModelPrivate *)user_data; priv->connection = (GDBusConnection *) g_object_ref (connection); priv->nameOwner = owner; priv->updateActions(); priv->updateMenuModel(); } void UnityMenuModelPrivate::nameVanished(GDBusConnection *connection, const gchar *name, gpointer user_data) { UnityMenuModelPrivate *priv = (UnityMenuModelPrivate *)user_data; priv->clearName(); } void UnityMenuModelPrivate::menuItemInserted(GtkMenuTrackerItem *item, gint position, gpointer user_data) { UnityMenuModelPrivate *priv = (UnityMenuModelPrivate *)user_data; UnityMenuModelAddRowEvent ummare(item, position); QCoreApplication::sendEvent(priv->model, &ummare); } void UnityMenuModelPrivate::menuItemRemoved(gint position, gpointer user_data) { UnityMenuModelPrivate *priv = (UnityMenuModelPrivate *)user_data; UnityMenuModelRemoveRowEvent ummrre(position); QCoreApplication::sendEvent(priv->model, &ummrre); } void UnityMenuModelPrivate::menuItemChanged(GObject *object, GParamSpec *pspec, gpointer user_data) { GSequenceIter *it = (GSequenceIter *) user_data; GtkMenuTrackerItem *item; GtkActionObservable *muxer; UnityMenuModel *model; gint position; item = (GtkMenuTrackerItem *) g_sequence_get (it); muxer = _gtk_menu_tracker_item_get_observable (item); model = (UnityMenuModel *) g_object_get_qdata (G_OBJECT (item), unity_menu_model_quark ()); position = g_sequence_iter_get_position (it); UnityMenuModelDataChangeEvent ummdce(position); QCoreApplication::sendEvent(model, &ummdce); } UnityMenuModel::UnityMenuModel(QObject *parent): QAbstractListModel(parent) { priv = new UnityMenuModelPrivate(this); } UnityMenuModel::UnityMenuModel(const UnityMenuModelPrivate& other, QObject *parent): QAbstractListModel(parent) { priv = new UnityMenuModelPrivate(other, this); } UnityMenuModel::~UnityMenuModel() { delete priv; } QByteArray UnityMenuModel::busName() const { return priv->busName; } void UnityMenuModel::setBusName(const QByteArray &name) { priv->clearName(); if (priv->nameWatchId) g_bus_unwatch_name (priv->nameWatchId); priv->nameWatchId = g_bus_watch_name (G_BUS_TYPE_SESSION, name.constData(), G_BUS_NAME_WATCHER_FLAGS_AUTO_START, UnityMenuModelPrivate::nameAppeared, UnityMenuModelPrivate::nameVanished, priv, NULL); priv->busName = name; } QVariantMap UnityMenuModel::actions() const { return priv->actions; } void UnityMenuModel::setActions(const QVariantMap &actions) { priv->actions = actions; priv->updateActions(); } QByteArray UnityMenuModel::menuObjectPath() const { return priv->menuObjectPath; } void UnityMenuModel::setMenuObjectPath(const QByteArray &path) { priv->menuObjectPath = path; priv->updateMenuModel(); } ActionStateParser* UnityMenuModel::actionStateParser() const { return priv->actionStateParser; } void UnityMenuModel::setActionStateParser(ActionStateParser* actionStateParser) { if (priv->actionStateParser != actionStateParser) { priv->actionStateParser = actionStateParser; Q_EMIT actionStateParserChanged(actionStateParser); } } int UnityMenuModel::rowCount(const QModelIndex &parent) const { return !parent.isValid() ? g_sequence_get_length (priv->items) : 0; } int UnityMenuModel::columnCount(const QModelIndex &parent) const { return 1; } static QString iconUri(GIcon *icon) { QString uri; if (G_IS_THEMED_ICON (icon)) { const gchar* const* iconNames = g_themed_icon_get_names (G_THEMED_ICON (icon)); guint index = 0; while(iconNames[index] != NULL) { if (QIcon::hasThemeIcon(iconNames[index])) { uri = QString("image://theme/") + iconNames[index]; break; } index++; } } else if (G_IS_FILE_ICON (icon)) { GFile *file; file = g_file_icon_get_file (G_FILE_ICON (icon)); if (g_file_is_native (file)) { gchar *fileuri; fileuri = g_file_get_uri (file); uri = QString(fileuri); g_free (fileuri); } } else if (G_IS_BYTES_ICON (icon)) { gsize size; gconstpointer data; gchar *base64; data = g_bytes_get_data (g_bytes_icon_get_bytes (G_BYTES_ICON (icon)), &size); base64 = g_base64_encode ((const guchar *) data, size); uri = QString("data://"); uri.append (base64); g_free (base64); } return uri; } QVariant UnityMenuModel::data(const QModelIndex &index, int role) const { GSequenceIter *it; GtkMenuTrackerItem *item; it = g_sequence_get_iter_at_pos (priv->items, index.row()); if (g_sequence_iter_is_end (it)) { return QVariant(); } item = (GtkMenuTrackerItem *) g_sequence_get (it); if (!item) { return QVariant(); } switch (role) { case LabelRole: return gtk_menu_tracker_item_get_label (item); case SensitiveRole: return gtk_menu_tracker_item_get_sensitive (item) == TRUE ? true : false; case IsSeparatorRole: return gtk_menu_tracker_item_get_is_separator (item) == TRUE ? true : false; case IconRole: { GIcon *icon = gtk_menu_tracker_item_get_icon (item); if (icon) { QString uri = iconUri(icon); g_object_unref (icon); return uri; } else return QString(); } case TypeRole: { gchar *type; if (gtk_menu_tracker_item_get_attribute (item, "x-canonical-type", "s", &type)) { QVariant v(type); g_free (type); return v; } else return QVariant(); } case ExtendedAttributesRole: { QVariantMap *map = (QVariantMap *) g_object_get_qdata (G_OBJECT (item), unity_menu_item_extended_attributes_quark ()); return map ? *map : QVariant(); } case ActionRole: { gchar *action_name = gtk_menu_tracker_item_get_action_name (item); QString v(action_name); g_free(action_name); return v; } case ActionStateRole: return priv->itemState(item); case IsCheckRole: return gtk_menu_tracker_item_get_role (item) == GTK_MENU_TRACKER_ITEM_ROLE_CHECK; case IsRadioRole: return gtk_menu_tracker_item_get_role (item) == GTK_MENU_TRACKER_ITEM_ROLE_RADIO; case IsToggledRole: return gtk_menu_tracker_item_get_toggled (item) == TRUE ? true : false; default: return QVariant(); } } QModelIndex UnityMenuModel::index(int row, int column, const QModelIndex &parent) const { return createIndex(row, column); } QModelIndex UnityMenuModel::parent(const QModelIndex &index) const { return QModelIndex(); } #include QHash UnityMenuModel::roleNames() const { QHash names; names[LabelRole] = "label"; names[SensitiveRole] = "sensitive"; names[IsSeparatorRole] = "isSeparator"; names[IconRole] = "icon"; names[TypeRole] = "type"; names[ExtendedAttributesRole] = "ext"; names[ActionRole] = "action"; names[ActionStateRole] = "actionState"; names[IsCheckRole] = "isCheck"; names[IsRadioRole] = "isRadio"; names[IsToggledRole] = "isToggled"; return names; } QObject * UnityMenuModel::submenu(int position, QQmlComponent* actionStateParser) { GSequenceIter *it; GtkMenuTrackerItem *item; UnityMenuModel *model; it = g_sequence_get_iter_at_pos (priv->items, position); if (g_sequence_iter_is_end (it)) { return NULL; } item = (GtkMenuTrackerItem *) g_sequence_get (it); if (!item || !gtk_menu_tracker_item_get_has_submenu (item)) { return NULL; } model = (UnityMenuModel *) g_object_get_qdata (G_OBJECT (item), unity_submenu_model_quark ()); if (model == NULL) { model = new UnityMenuModel(*priv, this); if (actionStateParser) { ActionStateParser* parser = qobject_cast(actionStateParser->create()); if (parser) { model->setActionStateParser(parser); } } model->priv->menutracker = gtk_menu_tracker_new_for_item_submenu (item, UnityMenuModelPrivate::menuItemInserted, UnityMenuModelPrivate::menuItemRemoved, model->priv); g_object_set_qdata (G_OBJECT (item), unity_submenu_model_quark (), model); } return model; } static void freeExtendedAttrs(gpointer data) { QVariantMap *extendedAttrs = (QVariantMap *) data; delete extendedAttrs; } static QVariant attributeToQVariant(GVariant *value, const QString &type) { QVariant result; if (type == "int") { if (g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)) { result = QVariant(g_variant_get_int32(value)); } } else if (type == "int64") { if (g_variant_is_of_type (value, G_VARIANT_TYPE_INT64)) { result = QVariant((qlonglong)g_variant_get_int64(value)); } } else if (type == "bool") { if (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) { result = QVariant(g_variant_get_boolean(value)); } } else if (type == "string") { if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) { result = QVariant(g_variant_get_string(value, NULL)); } } else if (type == "double") { if (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE)) { result = QVariant(g_variant_get_double(value)); } } else if (type == "variant") { if (g_variant_is_of_type (value, G_VARIANT_TYPE_VARIANT)) { result = Converter::toQVariant(value); } } else if (type == "icon") { GIcon *icon = g_icon_deserialize (value); if (icon) { result = iconUri(icon); g_object_unref (icon); } else { result = QVariant(""); } } return result; } /* convert 'some-key' to 'someKey' or 'SomeKey'. (from dconf-qt) */ static QString qtify_name(const char *name) { bool next_cap = false; QString result; while (*name) { if (*name == '-') { next_cap = true; } else if (next_cap) { result.append(toupper(*name)); next_cap = false; } else { result.append(*name); } name++; } return result; } bool UnityMenuModel::loadExtendedAttributes(int position, const QVariantMap &schema) { GSequenceIter *it; GtkMenuTrackerItem *item; QVariantMap *extendedAttrs; it = g_sequence_get_iter_at_pos (priv->items, position); if (g_sequence_iter_is_end (it)) { return false; } item = (GtkMenuTrackerItem *) g_sequence_get (it); if (!item) { return false; } extendedAttrs = new QVariantMap; for (QVariantMap::const_iterator it = schema.constBegin(); it != schema.constEnd(); ++it) { QString name = it.key(); QString type = it.value().toString(); GVariant *value = gtk_menu_tracker_item_get_attribute_value (item, name.toUtf8(), NULL); if (value == NULL) { qWarning("loadExtendedAttributes: menu item does not contain '%s'", it.key().toUtf8().constData()); continue; } QVariant qvalue = attributeToQVariant(value, type); if (qvalue.isValid()) extendedAttrs->insert(qtify_name (name.toUtf8()), qvalue); else qWarning("loadExtendedAttributes: key '%s' is of type '%s' (expected '%s')", name.toUtf8().constData(), g_variant_get_type_string(value), type.constData()); g_variant_unref (value); } g_object_set_qdata_full (G_OBJECT (item), unity_menu_item_extended_attributes_quark (), extendedAttrs, freeExtendedAttrs); Q_EMIT dataChanged(index(position, 0), index(position, 0), QVector() << ExtendedAttributesRole); } QVariant UnityMenuModel::get(int row, const QByteArray &role) { if (priv->roles.isEmpty()) { QHash names = roleNames(); Q_FOREACH (int role, names.keys()) priv->roles.insert(names[role], role); } return this->data(this->index(row, 0), priv->roles[role]); } void UnityMenuModel::activate(int index, const QVariant& parameter) { GSequenceIter *it; GtkMenuTrackerItem *item; it = g_sequence_get_iter_at_pos (priv->items, index); if (g_sequence_iter_is_end (it)) { return; } item = (GtkMenuTrackerItem *) g_sequence_get (it); if (!item) { return; } if (parameter.isValid()) { gchar *action; action = gtk_menu_tracker_item_get_action_name (item); g_action_group_activate_action (G_ACTION_GROUP (priv->muxer), action, Converter::toGVariant(parameter)); g_free (action); } else { gtk_menu_tracker_item_activated (item); } } void UnityMenuModel::changeState(int index, const QVariant& parameter) { GSequenceIter *it; GtkMenuTrackerItem* item; GVariant* data; GVariant* current_state; it = g_sequence_get_iter_at_pos (priv->items, index); if (g_sequence_iter_is_end (it)) { return; } item = (GtkMenuTrackerItem *) g_sequence_get (it); if (!item) { return; } current_state = gtk_menu_tracker_item_get_action_state (item); if (current_state) { // Attempt to convert the parameter to the expected type data = Converter::toGVariantWithSchema(parameter, g_variant_get_type_string(current_state)); g_variant_unref (current_state); } else { data = Converter::toGVariant(parameter); } gtk_menu_tracker_item_change_state (item, data); if (data) { g_variant_unref(data); } } bool UnityMenuModel::event(QEvent* e) { if (e->type() == UnityMenuModelClearEvent::eventType) { UnityMenuModelClearEvent *emmce = static_cast(e); GSequenceIter *begin; GSequenceIter *end; if (emmce->reset) beginResetModel(); begin = g_sequence_get_begin_iter (priv->items); end = g_sequence_get_end_iter (priv->items); g_sequence_remove_range (begin, end); if (emmce->reset) endResetModel(); return true; } else if (e->type() == UnityMenuModelAddRowEvent::eventType) { UnityMenuModelAddRowEvent *ummrce = static_cast(e); GSequenceIter *it; it = g_sequence_get_iter_at_pos (priv->items, ummrce->position); beginInsertRows(QModelIndex(), ummrce->position, ummrce->position); it = g_sequence_insert_before (it, g_object_ref (ummrce->item)); g_object_set_qdata (G_OBJECT (ummrce->item), unity_menu_model_quark (), this); g_signal_connect (ummrce->item, "notify", G_CALLBACK (UnityMenuModelPrivate::menuItemChanged), it); endInsertRows(); return true; } else if (e->type() == UnityMenuModelRemoveRowEvent::eventType) { UnityMenuModelRemoveRowEvent *ummrre = static_cast(e); GSequenceIter *it; it = g_sequence_get_iter_at_pos (priv->items, ummrre->position); if (!g_sequence_iter_is_end (it)) { beginRemoveRows(QModelIndex(), ummrre->position, ummrre->position); g_sequence_remove (it); endRemoveRows(); } return true; } else if (e->type() == UnityMenuModelDataChangeEvent::eventType) { UnityMenuModelDataChangeEvent *ummdce = static_cast(e); Q_EMIT dataChanged(index(ummdce->position, 0), index(ummdce->position, 0)); return true; } return QAbstractListModel::event(e); } void UnityMenuModel::registerAction(UnityMenuAction* action) { if (!priv->registeredActions.contains(action)) { GtkSimpleActionObserver* observer_item; observer_item = gtk_simple_action_observer_new(GTK_ACTION_OBSERVABLE (priv->muxer), UnityMenuModelPrivate::registeredActionAdded, UnityMenuModelPrivate::registeredActionEnabledChanged, UnityMenuModelPrivate::registeredActionStateChanged, UnityMenuModelPrivate::registeredActionRemoved); g_object_set_qdata (G_OBJECT (observer_item), unity_menu_action_quark (), action); priv->registeredActions[action] = observer_item; connect(action, SIGNAL(nameChanged(const QString&)), SLOT(onRegisteredActionNameChanged(const QString&))); connect(action, SIGNAL(indexChanged(int)), SLOT(onRegisteredActionIndexChanged(int))); connect(action, SIGNAL(activate(const QVariant&)), SLOT(onRegisteredActionActivated(const QVariant&))); connect(action, SIGNAL(changeState(const QVariant&)), SLOT(onRegisteredActionStateChanged(const QVariant&))); } } void UnityMenuModel::unregisterAction(UnityMenuAction* action) { if (priv->registeredActions.contains(action)) { GtkSimpleActionObserver* observer_item; observer_item = priv->registeredActions[action]; g_object_unref(observer_item); priv->registeredActions.remove(action); disconnect(action); } } /* Returns the full name for @action * * If @action is associated with a menu item that is inside of a * section or submenu with "action-namespace" set, this namespace * is prepended to @action->name() */ char * UnityMenuModelPrivate::fullActionName(UnityMenuAction *action) { GSequenceIter *iter; QByteArray bytes; const gchar *name; gchar *full_name = NULL; bytes = action->name().toUtf8(); name = bytes.constData(); iter = g_sequence_get_iter_at_pos (this->items, action->index()); if (!g_sequence_iter_is_end (iter)) { GtkMenuTrackerItem *item; const gchar *action_namespace; item = (GtkMenuTrackerItem *) g_sequence_get (iter); if (!item) { return g_strdup (name); } action_namespace = gtk_menu_tracker_item_get_action_namespace (item); if (action_namespace != NULL) return g_strjoin (".", action_namespace, name, NULL); } return g_strdup (name); } void UnityMenuModelPrivate::updateRegisteredAction(UnityMenuAction *action) { GtkSimpleActionObserver *observer_item; gchar *action_name; gboolean enabled; GVariant *state; if (!action || !this->registeredActions.contains(action)) return; action_name = fullActionName(action); observer_item = this->registeredActions[action]; gtk_simple_action_observer_register_action (observer_item, action_name); if (g_action_group_query_action (G_ACTION_GROUP (this->muxer), action_name, &enabled, NULL, NULL, NULL, &state)) { UnityMenuActionAddEvent umaae(enabled, Converter::toQVariant(state)); QCoreApplication::sendEvent(action, &umaae); if (state) { g_variant_unref (state); } } g_free(action_name); } void UnityMenuModel::onRegisteredActionNameChanged(const QString& name) { priv->updateRegisteredAction(qobject_cast(sender())); } void UnityMenuModel::onRegisteredActionIndexChanged(int index) { priv->updateRegisteredAction(qobject_cast(sender())); } void UnityMenuModel::onRegisteredActionActivated(const QVariant& parameter) { UnityMenuAction* action = qobject_cast(sender()); if (!action || action->name().isEmpty()) return; gchar* action_name = priv->fullActionName(action); g_action_group_activate_action (G_ACTION_GROUP (priv->muxer), action_name, Converter::toGVariant(parameter)); g_free(action_name); } void UnityMenuModel::onRegisteredActionStateChanged(const QVariant& parameter) { UnityMenuAction* action = qobject_cast(sender()); if (!action || action->name().isEmpty()) return; gchar* action_name = priv->fullActionName(action); g_action_group_change_action_state (G_ACTION_GROUP (priv->muxer), action_name, Converter::toGVariant(parameter)); g_free(action_name); } void UnityMenuModelPrivate::registeredActionAdded(GtkSimpleActionObserver *observer_item, const gchar *action_name, gboolean enabled, GVariant *state) { UnityMenuAction *action; action = (UnityMenuAction *) g_object_get_qdata (G_OBJECT (observer_item), unity_menu_action_quark ()); if (action) { UnityMenuActionAddEvent umaae(enabled, Converter::toQVariant(state)); QCoreApplication::sendEvent(action, &umaae); } } void UnityMenuModelPrivate::registeredActionEnabledChanged(GtkSimpleActionObserver *observer_item, const gchar *action_name, gboolean enabled) { UnityMenuAction *action; action = (UnityMenuAction *) g_object_get_qdata (G_OBJECT (observer_item), unity_menu_action_quark ()); if (action) { UnityMenuActionEnabledChangedEvent umaece(enabled); QCoreApplication::sendEvent(action, &umaece); } } void UnityMenuModelPrivate::registeredActionStateChanged(GtkSimpleActionObserver *observer_item, const gchar *action_name, GVariant *state) { UnityMenuAction *action; action = (UnityMenuAction *) g_object_get_qdata (G_OBJECT (observer_item), unity_menu_action_quark ()); if (action) { UnityMenuActionStateChangeEvent umasce(Converter::toQVariant(state)); QCoreApplication::sendEvent(action, &umasce); } } void UnityMenuModelPrivate::registeredActionRemoved(GtkSimpleActionObserver *observer_item, const gchar *action_name) { UnityMenuAction *action; action = (UnityMenuAction *) g_object_get_qdata (G_OBJECT (observer_item), unity_menu_action_quark ()); if (action) { UnityMenuActionRemoveEvent umare; QCoreApplication::sendEvent(action, &umare); } } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qdbusobject.h0000644000015201777760000000453312305545024024370 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #ifndef QDBUSOBJECT_H #define QDBUSOBJECT_H #include #include "dbus-enums.h" typedef unsigned int guint; typedef char gchar; typedef void* gpointer; typedef struct _GDBusConnection GDBusConnection; class QDBusObject { public: QDBusObject(QObject* listener); ~QDBusObject(); DBusEnums::BusType busType() const; void setBusType(DBusEnums::BusType type); QString busName() const; void setBusName(const QString &busName); QString objectPath() const; void setObjectPath(const QString &busName); DBusEnums::ConnectionStatus status() const; void connect(); void disconnect(); protected: virtual void serviceAppear(GDBusConnection *connection) = 0; virtual void serviceVanish(GDBusConnection *connection) = 0; // notify functions virtual void busTypeChanged(DBusEnums::BusType type) = 0; virtual void busNameChanged(const QString &busNameChanged) = 0; virtual void objectPathChanged(const QString &objectPath) = 0; virtual void statusChanged(DBusEnums::ConnectionStatus status) = 0; // This is not a Qbject, but we are passed events from superclass qobjects. virtual bool event(QEvent* e); private: QObject* m_listener; guint m_watchId; DBusEnums::BusType m_busType; QString m_busName; QString m_objectPath; DBusEnums::ConnectionStatus m_status; void setStatus(DBusEnums::ConnectionStatus status); // glib slots static void onServiceAppeared(GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer data); static void onServiceVanished(GDBusConnection *connection, const gchar *name, gpointer data); }; #endif qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qmenumodel.cpp0000644000015201777760000001652612305545024024571 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho * Olivier Tilloy */ extern "C" { #include } #include "qmenumodel.h" #include "menunode.h" #include "converter.h" #include "qmenumodelevents.h" #include #include /*! \qmltype QMenuModel \brief The QMenuModel class implements the base list model for menus \b {This component is under heavy development.} This is a abstracted class used by \l QDBusMenuModel. */ /*! \internal */ QMenuModel::QMenuModel(GMenuModel *other, QObject *parent) : QAbstractItemModel(parent), m_root(0) { setMenuModel(other); } /*! \internal */ QMenuModel::~QMenuModel() { clearModel(); } /*! \internal */ void QMenuModel::setMenuModel(GMenuModel *other) { if ((m_root != 0) && (m_root->model() == other)) { return; } beginResetModel(); clearModel(); if (other) { m_root = new MenuNode("", other, 0, 0, this); } endResetModel(); } /*! \internal */ void QMenuModel::clearModel() { if (m_root) { delete m_root; m_root = NULL; } } /*! \internal */ QHash QMenuModel::roleNames() const { static QHash roles; if (roles.isEmpty()) { roles[Action] = "action"; roles[Label] = "label"; roles[Extra] = "extra"; roles[Depth] = "depth"; roles[hasSection] = "hasSection"; roles[hasSubMenu] = "hasSubMenu"; } return roles; } /*! \internal */ QModelIndex QMenuModel::index(int row, int column, const QModelIndex &parent) const { MenuNode *node = nodeFromIndex(parent); if (node == 0) { return QModelIndex(); } if (parent.isValid()) { MenuNode *child = node->child(parent.row()); if (child) { node = child; } } return createIndex(row, column, node); } /*! \internal */ QModelIndex QMenuModel::parent(const QModelIndex &index) const { if (index.isValid() && index.internalPointer()) { MenuNode *node = nodeFromIndex(index); if (node->parent()) { return createIndex(node->position(), 0, node->parent()); } } return QModelIndex(); } /*! \internal */ QVariant QMenuModel::data(const QModelIndex &index, int role) const { QVariant attribute; if (!index.isValid()) { return attribute; } MenuNode *node = nodeFromIndex(index); int row = node ? node->realPosition(index.row()) : -1; if (row >= 0) { switch (role) { case Action: attribute = getStringAttribute(node, row, G_MENU_ATTRIBUTE_ACTION); break; case Qt::DisplayRole: case Label: attribute = getStringAttribute(node, row, G_MENU_ATTRIBUTE_LABEL); break; case Extra: attribute = getExtraProperties(node, row); break; case hasSection: attribute = QVariant(hasLink(node, row, G_MENU_LINK_SECTION)); break; case hasSubMenu: attribute = QVariant(hasLink(node, row, G_MENU_LINK_SUBMENU)); break; case Depth: attribute = QVariant(node->depth()); break; default: break; } } return attribute; } /*! \internal */ int QMenuModel::rowCount(const QModelIndex &index) const { if (index.isValid()) { MenuNode *node = nodeFromIndex(index); if (node) { MenuNode *child = node->child(index.row()); if (child) { return child->size(); } } return 0; } if (m_root) { return m_root->size(); } return 0; } /*! \internal */ int QMenuModel::columnCount(const QModelIndex &) const { return 1; } /*! \internal */ QVariant QMenuModel::getStringAttribute(MenuNode *node, int row, const QString &attribute) const { QVariant result; gchar* value = NULL; g_menu_model_get_item_attribute(node->model(), row, attribute.toUtf8().data(), "s", &value); if (value) { result = QVariant(QString::fromUtf8(value)); g_free(value); } return result; } /*! \internal */ QVariant QMenuModel::getExtraProperties(MenuNode *node, int row) const { GMenuAttributeIter *iter = g_menu_model_iterate_item_attributes(node->model(), row); if (iter == NULL) { return QVariant(); } QVariantMap extra; const gchar *attrName = NULL; GVariant *value = NULL; while (g_menu_attribute_iter_get_next (iter, &attrName, &value)) { if (strncmp("x-", attrName, 2) == 0) { extra.insert(parseExtraPropertyName(attrName), Converter::toQVariant(value)); } } return extra; } bool QMenuModel::event(QEvent* e) { if (e->type() == MenuNodeItemChangeEvent::eventType) { MenuNodeItemChangeEvent *mnice = static_cast(e); QModelIndex index = indexFromNode(mnice->node); if (mnice->removed > 0) { beginRemoveRows(index, mnice->position, mnice->position + mnice->removed - 1); mnice->node->commitOperation(); endRemoveRows(); } if (mnice->added > 0) { beginInsertRows(index, mnice->position, mnice->position + mnice->added - 1); mnice->node->commitOperation(); endInsertRows(); } return true; } else if (e->type() == MenuModelEvent::eventType) { MenuModelEvent *mme = static_cast(e); setMenuModel(mme->model); return true; } return QAbstractItemModel::event(e); } /*! \internal */ QModelIndex QMenuModel::indexFromNode(MenuNode *node) const { if (node == m_root) { return QModelIndex(); } return createIndex(node->position(), 0, node); } /*! \internal */ MenuNode *QMenuModel::nodeFromIndex(const QModelIndex &index) const { MenuNode *node = 0; if (index.isValid()) { node = reinterpret_cast(index.internalPointer()); } else { node = m_root; } return node; } /*! \internal */ QString QMenuModel::parseExtraPropertyName(const QString &name) const { QString newName(name); if (name.startsWith("x-")) { newName = name.mid(2); } return newName.replace("-", "_"); } GMenuModel *QMenuModel::menuModel() const { return m_root->model(); } bool QMenuModel::hasLink(MenuNode *node, int row, const QString &linkType) const { MenuNode *child = node->child(row); return (child && (child->linkType() == linkType)); } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/unitymenuaction.h0000644000015201777760000000455712305545024025324 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: Nick Dedekind */ #ifndef UNITYMENUACTION_H #define UNITYMENUACTION_H #include #include class UnityMenuModel; class UnityMenuAction: public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QVariant state READ state NOTIFY stateChanged) Q_PROPERTY(bool enabled READ isEnabled NOTIFY enabledChanged) Q_PROPERTY(bool valid READ isValid NOTIFY validChanged) Q_PROPERTY(UnityMenuModel* model READ model WRITE setModel NOTIFY modelChanged) Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged) public: UnityMenuAction(QObject* parent = 0); ~UnityMenuAction(); QString name() const; void setName(const QString& str); UnityMenuModel* model() const; void setModel(UnityMenuModel* model); int index() const; void setIndex(int i); QVariant state() const; bool isEnabled() const; bool isValid() const; Q_SIGNALS: Q_INVOKABLE void activate(const QVariant& parameter = QVariant()); Q_INVOKABLE void changeState(const QVariant& parameter); void nameChanged(const QString& name); void modelChanged(UnityMenuModel* model); void stateChanged(const QVariant& name); void enabledChanged(bool enabled); void validChanged(bool valid); void indexChanged(int index); protected: virtual bool event(QEvent* e); void setState(const QVariant& state); void setEnabled(bool enabled); void setValid(bool valid); private: void unregisterAction(); void registerAction(); QString m_name; QVariant m_state; bool m_valid; bool m_enabled; UnityMenuModel* m_model; int m_index; }; #endif // UNITYMENUACTIONGROUP_H qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qdbusmenumodel.h0000644000015201777760000000347212305545024025110 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ #ifndef QDBUSMENUMODEL_H #define QDBUSMENUMODEL_H #include "qdbusobject.h" #include "qmenumodel.h" class QDBusMenuModel : public QMenuModel, public QDBusObject { Q_OBJECT Q_PROPERTY(int busType READ busType WRITE setIntBusType NOTIFY busTypeChanged) Q_PROPERTY(QString busName READ busName WRITE setBusName NOTIFY busNameChanged) Q_PROPERTY(QString objectPath READ objectPath WRITE setObjectPath NOTIFY objectPathChanged) Q_PROPERTY(int status READ status NOTIFY statusChanged) public: QDBusMenuModel(QObject *parent=0); ~QDBusMenuModel(); Q_SIGNALS: void busTypeChanged(DBusEnums::BusType type); void busNameChanged(const QString &busNameChanged); void objectPathChanged(const QString &objectPath); void statusChanged(DBusEnums::ConnectionStatus status); public Q_SLOTS: void start(); void stop(); protected: virtual void serviceAppear(GDBusConnection *connection); virtual void serviceVanish(GDBusConnection *connection); virtual bool event(QEvent* e); private: // workaround to support int as busType void setIntBusType(int busType); }; #endif qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/dbus-enums.h0000644000015201777760000000237412305545024024146 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Olivier Tilloy */ #ifndef __DBUS_ENUMS__ #define __DBUS_ENUMS__ #include // This class acts as a namespace only, with the addition that its enums // are registered to be exposed on the QML side. class DBusEnums : public QObject { Q_OBJECT Q_ENUMS(BusType) Q_ENUMS(ConnectionStatus) public: enum BusType { None = 0, SessionBus, SystemBus, LastBusType }; enum ConnectionStatus { Disconnected = 0, Connecting, Connected }; private: DBusEnums() {} }; #endif // __DBUS_ENUMS__ qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/unitymenumodel.h0000644000015201777760000000654712305545024025150 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: Lars Uebernickel */ #ifndef UNITYMENUMODEL_H #define UNITYMENUMODEL_H #include class ActionStateParser; class QQmlComponent; class UnityMenuAction; class UnityMenuModel: public QAbstractListModel { Q_OBJECT Q_PROPERTY(QByteArray busName READ busName WRITE setBusName NOTIFY busNameChanged) Q_PROPERTY(QVariantMap actions READ actions WRITE setActions NOTIFY actionsChanged) Q_PROPERTY(QByteArray menuObjectPath READ menuObjectPath WRITE setMenuObjectPath NOTIFY menuObjectPathChanged) Q_PROPERTY(ActionStateParser* actionStateParser READ actionStateParser WRITE setActionStateParser NOTIFY actionStateParserChanged) public: UnityMenuModel(QObject *parent = NULL); virtual ~UnityMenuModel(); QByteArray busName() const; void setBusName(const QByteArray &name); QVariantMap actions() const; void setActions(const QVariantMap &actions); QByteArray menuObjectPath() const; void setMenuObjectPath(const QByteArray &path); ActionStateParser* actionStateParser() const; void setActionStateParser(ActionStateParser* actionStateParser); int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; QHash roleNames() const; Q_INVOKABLE QObject * submenu(int position, QQmlComponent* actionStateParser = NULL); Q_INVOKABLE bool loadExtendedAttributes(int position, const QVariantMap &schema); Q_INVOKABLE QVariant get(int row, const QByteArray &role); Q_INVOKABLE void activate(int index, const QVariant& parameter = QVariant()); Q_INVOKABLE void changeState(int index, const QVariant& parameter); void registerAction(UnityMenuAction* action); void unregisterAction(UnityMenuAction* action); Q_SIGNALS: void busNameChanged(const QByteArray &name); void actionsChanged(const QByteArray &path); void menuObjectPathChanged(const QByteArray &path); void actionStateParserChanged(ActionStateParser* parser); protected Q_SLOTS: void onRegisteredActionNameChanged(const QString& name); void onRegisteredActionIndexChanged(int); void onRegisteredActionActivated(const QVariant& parameter); void onRegisteredActionStateChanged(const QVariant& parameter); protected: virtual bool event(QEvent* e); private: class UnityMenuModelPrivate *priv; friend class UnityMenuModelPrivate; UnityMenuModel(const UnityMenuModelPrivate& other, QObject *parent); }; #endif qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/unitymenumodelevents.cpp0000644000015201777760000000411412305545024026714 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Nicholas Dedekind #include } #include "unitymenumodelevents.h" #include "unitymenumodel.h" const QEvent::Type UnityMenuModelClearEvent::eventType = static_cast(QEvent::registerEventType()); const QEvent::Type UnityMenuModelAddRowEvent::eventType = static_cast(QEvent::registerEventType()); const QEvent::Type UnityMenuModelRemoveRowEvent::eventType = static_cast(QEvent::registerEventType()); const QEvent::Type UnityMenuModelDataChangeEvent::eventType = static_cast(QEvent::registerEventType()); UnityMenuModelClearEvent::UnityMenuModelClearEvent(bool _reset) : QEvent(UnityMenuModelClearEvent::eventType), reset(_reset) {} UnityMenuModelAddRowEvent::UnityMenuModelAddRowEvent(GtkMenuTrackerItem *_item, int _position) : QEvent(UnityMenuModelAddRowEvent::eventType), item(_item), position(_position) { if (item) { g_object_ref(item); } } UnityMenuModelAddRowEvent::~UnityMenuModelAddRowEvent() { if (item) { g_object_unref(item); } } UnityMenuModelRemoveRowEvent::UnityMenuModelRemoveRowEvent(int _position) : QEvent(UnityMenuModelRemoveRowEvent::eventType), position(_position) {} UnityMenuModelDataChangeEvent::UnityMenuModelDataChangeEvent(int _position) : QEvent(UnityMenuModelDataChangeEvent::eventType), position(_position) {} qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qdbusobject.cpp0000644000015201777760000001306212305545024024720 0ustar pbusernogroup00000000000000/* * Copyright 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Renato Araujo Oliveira Filho */ extern "C" { #include #include } #include "qdbusobject.h" #include "qmenumodelevents.h" #include #include /*! \qmltype QDBusObject \brief The QDBusObject is a base class \b {This component is under heavy development.} This is a abstracted class used by QDBusMenuModel and QDBusActionGroup */ /*! \qmlproperty int QDBusObject::busType This property holds the dbus session type which will be used during the connection. This must be seteed before call start method The valid values are: \list \li 1 - SessionBus \li 2 - SystemBus \endlist */ /*! \qmlproperty int QDBusObject::busName This property holds the dbus service name related with menu. This must be seteed before call start method */ /*! \qmlproperty int QDBusObject::objectPath This property holds the dbus object path related with the menu. This must be seteed before call start method */ /*! \qmlproperty int QDBusObject::status This property holds current dbus connection status Te velid status are: \list \li 0 - Disconnected \li 1 - Connecting \li 2 - Connected \endlist */ QDBusObject::QDBusObject(QObject* listener) :m_listener(listener), m_watchId(0), m_busType(DBusEnums::None), m_status(DBusEnums::Disconnected) { g_type_init(); qRegisterMetaType("DBusEnums::ConnectionStatus"); } QDBusObject::~QDBusObject() { if (m_watchId != 0) { g_bus_unwatch_name (m_watchId); m_watchId = 0; } } DBusEnums::BusType QDBusObject::busType() const { return m_busType; } void QDBusObject::setBusType(DBusEnums::BusType type) { if (m_busType != type) { if (m_status != DBusEnums::Disconnected) disconnect(); m_busType = type; Q_EMIT busTypeChanged(m_busType); } } QString QDBusObject::busName() const { return m_busName; } void QDBusObject::setBusName(const QString &busName) { if (m_busName != busName) { if (m_status != DBusEnums::Disconnected) disconnect(); m_busName = busName; Q_EMIT busNameChanged(m_busName); } } QString QDBusObject::objectPath() const { return m_objectPath; } void QDBusObject::setObjectPath(const QString &objectPath) { if (m_objectPath != objectPath) { if (m_status != DBusEnums::Disconnected) disconnect(); m_objectPath = objectPath; Q_EMIT objectPathChanged(m_objectPath); } } void QDBusObject::setStatus(DBusEnums::ConnectionStatus status) { if (m_status != status) { m_status = status; Q_EMIT statusChanged(m_status); } } DBusEnums::ConnectionStatus QDBusObject::status() const { return m_status; } void QDBusObject::connect() { if (m_status != DBusEnums::Disconnected) { return; } else if ((m_busType > DBusEnums::None) && !m_objectPath.isEmpty() && !m_busName.isEmpty()) { GBusType type = m_busType == DBusEnums::SessionBus ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM; m_watchId = g_bus_watch_name (type, m_busName.toUtf8().data(), G_BUS_NAME_WATCHER_FLAGS_AUTO_START, QDBusObject::onServiceAppeared, QDBusObject::onServiceVanished, this, NULL); setStatus(DBusEnums::Connecting); } else { qWarning() << "Invalid dbus connection args"; } } void QDBusObject::disconnect() { if (m_status != DBusEnums::Disconnected) { g_bus_unwatch_name (m_watchId); m_watchId = 0; setStatus(DBusEnums::Disconnected); } } void QDBusObject::onServiceAppeared(GDBusConnection *connection, const gchar *, const gchar *, gpointer data) { QDBusObject *self = reinterpret_cast(data); if (self->m_listener) { DbusObjectServiceEvent dose(connection, true); QCoreApplication::sendEvent(self->m_listener, &dose); } } void QDBusObject::onServiceVanished(GDBusConnection *connection, const gchar *, gpointer data) { QDBusObject *self = reinterpret_cast(data); if (self->m_listener) { DbusObjectServiceEvent dose(connection, false); QCoreApplication::sendEvent(self->m_listener, &dose); } } bool QDBusObject::event(QEvent* e) { if (e->type() == DbusObjectServiceEvent::eventType) { DbusObjectServiceEvent *dose = static_cast(e); if (dose->visible) { serviceAppear(dose->connection); setStatus(DBusEnums::Connected); } else { setStatus(DBusEnums::Connecting); serviceVanish(dose->connection); } return true; } return false; } qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/unitymenuactionevents.h0000644000015201777760000000335312305545024026542 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Nicholas Dedekind #include /* Event for a unitymenuaction add */ class UnityMenuActionAddEvent : public QEvent { public: static const QEvent::Type eventType; UnityMenuActionAddEvent(bool enabled, const QVariant& state); bool enabled; QVariant state; }; /* Event for a unitymenuaction remove */ class UnityMenuActionRemoveEvent : public QEvent { public: static const QEvent::Type eventType; UnityMenuActionRemoveEvent(); }; /* Event for change in enabled value of a unitymenuaction */ class UnityMenuActionEnabledChangedEvent : public QEvent { public: static const QEvent::Type eventType; UnityMenuActionEnabledChangedEvent(bool enabled); int enabled; }; /* Event for change in state value of a unitymenuaction */ class UnityMenuActionStateChangeEvent : public QEvent { public: static const QEvent::Type eventType; UnityMenuActionStateChangeEvent(const QVariant& state); QVariant state; }; #endif //UNITYMENUACTIONEVENTS_H