qmenumodel-0.2.7+14.04.20140305/ 0000755 0000152 0177776 00000000000 12305545277 016273 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/cmake/ 0000755 0000152 0177776 00000000000 12305545277 017353 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/cmake/lcov.cmake 0000644 0000152 0177776 00000005005 12305545024 021306 0 ustar pbuser nogroup 0000000 0000000 # - 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/ 0000755 0000152 0177776 00000000000 12305545277 017435 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/tests/script/ 0000755 0000152 0177776 00000000000 12305545277 020741 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/tests/script/CMakeLists.txt 0000644 0000152 0177776 00000000306 12305545024 023466 0 ustar pbuser nogroup 0000000 0000000 project(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.py 0000644 0000152 0177776 00000017356 12305545024 023506 0 ustar pbuser nogroup 0000000 0000000 # 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.h 0000644 0000152 0177776 00000002657 12305545024 024161 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000005142 12305545024 024504 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.txt 0000644 0000152 0177776 00000000064 12305545024 022163 0 ustar pbuser nogroup 0000000 0000000 add_subdirectory(script)
add_subdirectory(client)
qmenumodel-0.2.7+14.04.20140305/tests/client/ 0000755 0000152 0177776 00000000000 12305545277 020713 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/tests/client/modeltest.cpp 0000644 0000152 0177776 00000014230 12305545024 023405 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.py 0000755 0000152 0177776 00000004707 12305545024 024652 0 ustar pbuser nogroup 0000000 0000000 #!/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.cpp 0000644 0000152 0177776 00000007027 12305545024 023252 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.qml 0000644 0000152 0177776 00000002732 12305545024 023360 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000012455 12305545024 024646 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000005520 12305545024 023747 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.py 0000755 0000152 0177776 00000001541 12305545024 024334 0 ustar pbuser nogroup 0000000 0000000 #!/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.txt 0000644 0000152 0177776 00000004206 12305545024 023443 0 ustar pbuser nogroup 0000000 0000000 macro(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.qml 0000644 0000152 0177776 00000002061 12305545024 023435 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.in 0000644 0000152 0177776 00000000313 12305545024 023270 0 ustar pbuser nogroup 0000000 0000000 const 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.py 0000755 0000152 0177776 00000001541 12305545024 025203 0 ustar pbuser nogroup 0000000 0000000 #!/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.py 0000755 0000152 0177776 00000001637 12305545024 026046 0 ustar pbuser nogroup 0000000 0000000 #!/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.py 0000755 0000152 0177776 00000002055 12305545024 026076 0 ustar pbuser nogroup 0000000 0000000 #!/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.cpp 0000644 0000152 0177776 00000020625 12305545024 024773 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000013537 12305545024 023361 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000003751 12305545024 024610 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000006125 12305545024 023102 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000013465 12305545024 024325 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.txt 0000644 0000152 0177776 00000003457 12305545024 021032 0 ustar pbuser nogroup 0000000 0000000 project(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/TODO 0000644 0000152 0177776 00000000604 12305545024 016751 0 ustar pbuser nogroup 0000000 0000000 = 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/README 0000644 0000152 0177776 00000002354 12305545024 017145 0 ustar pbuser nogroup 0000000 0000000 QMenuModel - 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/ 0000755 0000152 0177776 00000000000 12305545277 017040 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/doc/CMakeLists.txt 0000644 0000152 0177776 00000000640 12305545024 021566 0 ustar pbuser nogroup 0000000 0000000 set(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.in 0000644 0000152 0177776 00000000335 12305545024 023320 0 ustar pbuser nogroup 0000000 0000000 project = 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.LGPL 0000644 0000152 0177776 00000016743 12305545024 020064 0 ustar pbuser nogroup 0000000 0000000 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/ 0000755 0000152 0177776 00000000000 12305545277 020111 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/examples/render-menumodel.qml 0000644 0000152 0177776 00000011537 12305545024 024063 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.py 0000755 0000152 0177776 00000005022 12305545024 024247 0 ustar pbuser nogroup 0000000 0000000 #!/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.txt 0000644 0000152 0177776 00000001142 12305545024 022635 0 ustar pbuser nogroup 0000000 0000000 # 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/README 0000644 0000152 0177776 00000001426 12305545024 020762 0 ustar pbuser nogroup 0000000 0000000 This 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.qml 0000644 0000152 0177776 00000007176 12305545024 024415 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.py 0000755 0000152 0177776 00000005013 12305545024 022661 0 ustar pbuser nogroup 0000000 0000000 #!/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.cpp 0000644 0000152 0177776 00000006351 12305545024 023526 0 ustar pbuser nogroup 0000000 0000000 /*
* 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/ 0000755 0000152 0177776 00000000000 12305545277 021130 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/libqmenumodel/CMakeLists.txt 0000644 0000152 0177776 00000000113 12305545024 023651 0 ustar pbuser nogroup 0000000 0000000 project(libqmenumodel)
add_subdirectory(src)
add_subdirectory(QMenuModel)
qmenumodel-0.2.7+14.04.20140305/libqmenumodel/QMenuModel/ 0000755 0000152 0177776 00000000000 12305545277 023136 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/libqmenumodel/QMenuModel/plugin.h 0000644 0000152 0177776 00000002051 12305545024 024571 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.txt 0000644 0000152 0177776 00000001521 12305545024 025663 0 ustar pbuser nogroup 0000000 0000000 project(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/qmldir 0000644 0000152 0177776 00000000051 12305545024 024333 0 ustar pbuser nogroup 0000000 0000000 module QMenuModel
plugin qmenumodel-qml
qmenumodel-0.2.7+14.04.20140305/libqmenumodel/QMenuModel/plugin.cpp 0000644 0000152 0177776 00000003402 12305545024 025125 0 ustar pbuser nogroup 0000000 0000000 /*
* 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/ 0000755 0000152 0177776 00000000000 12305545277 021717 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/qdbusactiongroup.cpp 0000644 0000152 0177776 00000017065 12305545024 026013 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.h 0000644 0000152 0177776 00000003456 12305545024 026371 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000003516 12305545024 027076 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000013754 12305545024 024235 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000006320 12305545024 025436 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.cpp 0000644 0000152 0177776 00000007761 12305545024 025123 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.h 0000644 0000152 0177776 00000004573 12305545024 025462 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.h 0000644 0000152 0177776 00000004275 12305545024 024234 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.h 0000644 0000152 0177776 00000004035 12305545024 023672 0 ustar pbuser nogroup 0000000 0000000 /*
* 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/ 0000755 0000152 0177776 00000000000 12305545277 022504 5 ustar pbuser nogroup 0000000 0000000 qmenumodel-0.2.7+14.04.20140305/libqmenumodel/src/gtk/gtkmenutracker.c 0000644 0000152 0177776 00000043632 12305545024 025674 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.h 0000644 0000152 0177776 00000005773 12305545024 026707 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.h 0000644 0000152 0177776 00000005516 12305545024 025700 0 ustar pbuser nogroup 0000000 0000000 /*
* 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.h 0000644 0000152 0177776 00000006641 12305545024 027617 0 ustar pbuser nogroup 0000000 0000000 /*
* 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