/*
* 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 "actionstateparser.h"
#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),
m_actionStateParser(new ActionStateParser(this))
{
}
/*! \internal */
QDBusActionGroup::~QDBusActionGroup()
{
clear();
}
QStringList QDBusActionGroup::actions() const
{
if (!m_actionGroup) return QStringList();
QStringList list;
gchar** actions = g_action_group_list_actions(m_actionGroup);
for (uint i = 0; actions[i]; i++) {
list << QString(actions[i]);
}
g_strfreev(actions);
return list;
}
/*!
\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());
if (m_actionStateParser != NULL) {
result = m_actionStateParser->toQVariant(state);
} else {
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;
}
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);
}
}
ActionStateParser* QDBusActionGroup::actionStateParser() const
{
return m_actionStateParser;
}
void QDBusActionGroup::setActionStateParser(ActionStateParser* actionStateParser)
{
if (m_actionStateParser != actionStateParser) {
m_actionStateParser = actionStateParser;
Q_EMIT actionStateParserChanged(actionStateParser);
}
}
/*! \internal */
void QDBusActionGroup::clear()
{
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;
}
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);
}
Q_EMIT actionsChanged();
} 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);
}