~kalikiana/unity-action-api/cutedocs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/* This file is part of unity-action-api
 * Copyright 2013 Canonical Ltd.
 *
 * unity-action-api is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3,
 * as published by the Free Software Foundation.
 *
 * unity-action-api is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 * MERCHANTABILITY, SATISFACTORY QUALITY, 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 <http://www.gnu.org/licenses/>.
 */

#include <unity/action/Action>
#include <QMutex>

#include <QDebug>

using namespace unity::action;

namespace unity {
namespace action {
/*!
 * \class Action
 * \brief The main action class.
 *
 * Unity services visualizing this class will usually
 * be represented it as a simple button or menu item, depending upon where it is contributed.
 *
 * The optional name property is available through D-Bus and can be used to activate a specific Action
 * from external componenets such as the Launcher. See \ref page_platform-integration and
 * \ref page_offline-actions for more information.
 *
 * If the parameterType property is set, the Action is said to be parameterised. This means that when it is
 * bound to a menu or button, the action expects a typed input parameter. The type affects the allowed value
 * of the QVariant that must be passed to the trigger() and triggered().
 *
 * \note As QVariant does automatic conversions between different normally uncorvertable types the developer
 *       must be careful of the side effects the conversions might have if accidentally passing wrong type
 *       of a parameter to trigger() or when handling the value of triggered(). Please, see the QVariant
 *       documentation for more information on the conversions QVariant does.
 *
 * Action has to be added to the ActionManager or a ActionContext to make it available for external components.
 */

/*!
 * \enum Action::Type
 * \brief Available parameter types.
 *
 * This enum defines the available types that the action trigger() and triggered()
 * support.
 *
 *
 * \var Action::Type Action::None
 *
 * No paramater. Trying to pass anything else than an empty
 * QVariant is an error.
 *
 *
 * \var Action::Type Action::String
 *
 * String parameter.
 *
 *
 * \var Action::Type Action::Integer
 *
 * Integer parameter.
 *
 *\var Action::Type Action::Bool
 *
 * Boolean parameter.
 *
 *
 *\var Action::Type Action::Real
 *
 * Single precision floating point parameter.
 */


// property documentation

/*!
 * \property QString Action::description
 *
 * User visible secondary description for the action.
 *
 * Description is more verbose than the text() and should describe the Action with
 * couple of words.
 *
 * \initvalue ""
 *
 * \accessors description(), setDescription()
 *
 * \notify descriptionChanged()
 */

/*!
 * \property bool Action::enabled
 *
 * If set to false the action can not be triggered.
 *
 * Components visualizing the action migth either hide the
 * action or make it insensitive.
 *
 * If set to false the Action is removed from the search
 * results of the HUD.
 *
 * \initvalue true
 *
 * \accessors enabled(), setEnabled()
 *
 * \notify enabledChanged()
 */

/*!
 * \property QString Action::iconName
 *
 * Name of a icon for this action.
 *
 * When the action is exported to external components the iconName
 * must be avaible on system icon theme engine.
 *
 * \initvalue ""
 *
 * \accessors iconName(), setIconName()
 *
 * \notify iconNameChanged()
 */

/*!
 * \property QString Action::keywords
 *
 * Additional user visible keywords for the action.
 *
 * Keywords improve the HUD search results when the user tries to search for an action
 * with a synonym of the text(). For example if we the application has an action "Crop"
 * but the user tries to "Trim" then without the keywords the HUD would not try to offer
 * the "Crop" action.
 *
 * The format of the keywords string is "Keyword 1;Keyword 2;Keyword 3" to allow translators
 * to define different number of keywords per language.
 *
 * The keywords are separated by ; and they may contain spaces.
 *
 * \code
 *     Action *action = new Action(this);
 *     action->setText(tr("Crop"));
 *     action->description(tr("Crop the image"));
 *     action->setKeywords(tr("Trim;Cut"));
 * \endcode
 *
 * \initvalue ""
 *
 * \accessors keywords(), setKeywords()
 *
 * \notify keywordsChanged()
 */

/*!
 * \property QString Action::name
 *
 * The name of the action. By default an action gets it's name
 * generated automatically if not overridden with setName() later.
 * If name is set to "" then the action restores it's autogenerated name.
 *
 * The actions is accessible from D-Bus with this name.
 *
 * The name is not user visible.
 *
 * \note Changing the name is potentially an expensive operation if the action is already added to the manager.
 *       If possible, set the name for your action before adding it to the manager.
 *
 * \initvalue autogenerated
 *
 * \accessors name(), setName()
 *
 * \notify nameChanged()
 */

/*!
 * \property Action::Type Action::parameterType()
 *
 * Type of the parameter passed to trigger() and triggered().
 *
 * \note Changing the parameterType is potentially an expensive operation if the action is already added to the manager.
 *       If possible, set the parameterType of your action before adding it to the manager.
 *
 * \initvalue Action::None
 *
 * \accessors parameterType(), setParameterType()
 *
 * \notify parameterTypeChanged()
 */

/*!
 * \property QString Action::text
 *
 * The user visible primary label of the action.
 *
 * \initvalue ""
 *
 * \accessors text(), setText()
 *
 * \notify textChanged()
 */


// signal documentation

/*!
 * \fn void Action::triggered(QVariant)
 *
 * \param value the value which which was passed to trigger()
 *
 * The value is always compatible with the set parameterType. For example
 * if parameterType is Action::String the value can be converted to QString
 * by using the QVariant conversion functions:
 * \code
 *     QString param = value.toString();
 * \endcode
 */
}
}


//! \private
class Q_DECL_HIDDEN unity::action::Action::Private {
public:
    QString name;
    QString generatedname;
    QString text;
    QString iconName;
    QString description;
    QString keywords;
    bool enabled;
    Action::Type parameterType;

    const char *paramTypeName(Action::Type type) {
        switch (type) {
        case Action::None:    return "None";
        case Action::String:  return "String";
        case Action::Integer: return "Integer";
        case Action::Bool:    return "Bool";
        case Action::Real:    return "Real";
        }
        // should not be reached
        Q_ASSERT(0);
        return "Internal Error";
    }
};

/*!
 * \fn Action::Action(QObject *parent = 0)
 * \param parent parent QObject or 0
 *
 * Constructs a new Action. See the property documentation for
 * default values.
 */
Action::Action(QObject *parent)
    : QObject(parent),
      d(new Private())
{
    qRegisterMetaType<unity::action::Action::Type>();
    d->enabled = true;
    d->parameterType = None;

    // autogenerate a unique name
    static QMutex mutex;
    QMutexLocker locker(&mutex);
    static int id = 0;
    d->name = QString("unity-action-%1").arg(QString::number(id++));
    d->generatedname = d->name;
}

Action::~Action()
{
}

QString
Action::name() const
{
    return d->name;
}

void
Action::setName(const QString &value)
{
    QString oldName = d->name;

    if (d->name == value)
        return;
    if (!value.isNull() && !value.isEmpty())
        d->name = value;
    else
        d->name = d->generatedname;

    if (oldName != d->name)
        emit nameChanged(d->name);
}

QString
Action::text() const
{
    return d->text;
}

void
Action::setText(const QString &value)
{
    if (d->text == value)
        return;
    d->text = value;
    emit textChanged(value);
}

QString
Action::iconName() const
{
    return d->iconName;
}

void
Action::setIconName(const QString &value)
{
    if (d->iconName == value)
        return;
    d->iconName = value;
    emit iconNameChanged(value);
}

QString
Action::description() const
{
    return d->description;
}

void
Action::setDescription(const QString &value)
{
    if (d->description == value)
        return;
    d->description = value;
    emit descriptionChanged(value);
}

QString
Action::keywords() const
{
    return d->keywords;
}

void
Action::setKeywords(const QString &value)
{
    if (d->keywords == value)
        return;
    d->keywords = value;
    emit keywordsChanged(value);
}

bool
Action::enabled() const
{
    return d->enabled;
}

void
Action::setEnabled(bool value)
{
    if (d->enabled == value)
        return;
    d->enabled = value;
    emit enabledChanged(value);
}

Action::Type
Action::parameterType() const
{
    return d->parameterType;
}

void
Action::setParameterType(Type value)
{
    if (d->parameterType == value)
        return;
    d->parameterType = value;
    emit parameterTypeChanged(value);
}

/*!
 * Checks the value agains parameterType and triggers the action.
 *
 * if paramType is Action::None the action can be triggered by simly calling:
 * \code
 *     action->trigger();
 * \endcode
 *
 * \note beware of the automatic conversion QVariant does. See the
 *       QVariant documentation for details.
 */
void
Action::trigger(QVariant value)
{
    QMetaType::Type targetType = QMetaType::UnknownType;

    if (!d->enabled) {
        return;
    }

    switch (d->parameterType) {
    case None: {
        break;
    }
    case String: {
        targetType = QMetaType::QString;
        break;
    }
    case Integer: {
        targetType = QMetaType::Int;
        break;
    }
    case Bool: {
        targetType = QMetaType::Bool;
        break;
    }
    case Real: {
        targetType = QMetaType::Float;
        break;
    }
    }

    // need to take a copy of the value as we have to try to convert() it.
    QVariant tmp = value;
    if ((targetType == QMetaType::UnknownType && d->parameterType != None) ||
        (!tmp.canConvert(targetType) || !tmp.convert(targetType))) {
        qWarning() << __PRETTY_FUNCTION__ << ":\n"
                   << "\tTrying to trigger action (name: " << d->name << " :: text: " << d->text << ")\n"
                   << "\twhich has parameter type '" << d->paramTypeName(d->parameterType) << "'\n"
                   << "\twith incompatible parameter value (" << value << ")";
        return;
    }

    emit triggered(value);
}