~ubuntu-branches/ubuntu/trusty/hud/trusty-updates

« back to all changes in this revision

Viewing changes to libqtgmenu/internal/QtGMenuModel.cpp

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release
  • Date: 2014-01-20 19:43:59 UTC
  • mfrom: (1.1.26)
  • Revision ID: package-import@ubuntu.com-20140120194359-jxxxqtd4ql9elvpf
Tags: 13.10.1+14.04.20140120-0ubuntu1
* New rebuild forced
* Automatic snapshot from revision 362

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2013 Canonical, Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License version 3, as published
 
6
 * by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
10
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
11
 * PURPOSE.  See the GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along
 
14
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Author: Marcus Tomlinson <marcus.tomlinson@canonical.com>
 
17
 */
 
18
 
 
19
#include <QtGMenuModel.h>
 
20
#include <QtGMenuUtils.h>
 
21
 
 
22
using namespace qtgmenu;
 
23
 
 
24
QtGMenuModel::QtGMenuModel( GMenuModel* model )
 
25
    : QtGMenuModel( model, LinkType::Root, nullptr, 0 )
 
26
{
 
27
}
 
28
 
 
29
QtGMenuModel::QtGMenuModel( GMenuModel* model, const QString& bus_name, const QString& menu_path,
 
30
    const QString& actions_path )
 
31
    : QtGMenuModel( model, LinkType::Root, nullptr, 0 )
 
32
{
 
33
  m_bus_name = bus_name;
 
34
  m_menu_path = menu_path;
 
35
  m_actions_path = actions_path;
 
36
}
 
37
 
 
38
QtGMenuModel::QtGMenuModel( GMenuModel* model, LinkType link_type, QtGMenuModel* parent, int index )
 
39
    : m_parent( parent ),
 
40
      m_model( model ),
 
41
      m_link_type( link_type )
 
42
{
 
43
  ConnectCallback();
 
44
 
 
45
  if( m_parent )
 
46
  {
 
47
    m_parent->InsertChild( this, index );
 
48
 
 
49
    m_bus_name = m_parent->m_bus_name;
 
50
    m_menu_path = m_parent->m_menu_path;
 
51
    m_actions_path = m_parent->m_actions_path;
 
52
 
 
53
    gchar* label = NULL;
 
54
    if( g_menu_model_get_item_attribute( m_parent->m_model, index,
 
55
            G_MENU_ATTRIBUTE_LABEL, "s", &label ) )
 
56
    {
 
57
      QString qlabel = QString::fromUtf8( label );
 
58
      qlabel.replace( '_', '&' );
 
59
      g_free( label );
 
60
 
 
61
      m_ext_menu->setTitle( qlabel );
 
62
    }
 
63
 
 
64
    gchar* action_name = NULL;
 
65
    if( g_menu_model_get_item_attribute( m_parent->m_model, index,
 
66
            G_MENU_ATTRIBUTE_ACTION, "s", &action_name ) )
 
67
    {
 
68
      QString qaction_name = QString::fromUtf8( action_name );
 
69
      g_free( action_name );
 
70
 
 
71
      int name_length = qaction_name.size() - qaction_name.indexOf( '.' ) - 1;
 
72
      qaction_name = qaction_name.right( name_length );
 
73
 
 
74
      m_ext_menu->menuAction()->setProperty( c_property_actionName, qaction_name );
 
75
    }
 
76
 
 
77
    // if this model has a "commitLabel" property, it is a libhud parameterized action
 
78
    gchar* commit_label = NULL;
 
79
    if( g_menu_model_get_item_attribute( m_parent->m_model, index,
 
80
            "commitLabel", "s", &commit_label ) )
 
81
    {
 
82
      g_free( commit_label );
 
83
 
 
84
      // is parameterized
 
85
      m_ext_menu->menuAction()->setProperty( c_property_isParameterized, true );
 
86
 
 
87
      // dbus paths
 
88
      m_ext_menu->menuAction()->setProperty( c_property_busName, m_bus_name );
 
89
      m_ext_menu->menuAction()->setProperty( c_property_menuPath, m_menu_path );
 
90
      m_ext_menu->menuAction()->setProperty( c_property_actionsPath, m_actions_path );
 
91
    }
 
92
  }
 
93
 
 
94
  if( m_model )
 
95
  {
 
96
    m_size = g_menu_model_get_n_items( m_model );
 
97
  }
 
98
 
 
99
  ChangeMenuItems( 0, m_size, 0 );
 
100
}
 
101
 
 
102
QtGMenuModel::~QtGMenuModel()
 
103
{
 
104
  if( m_model )
 
105
  {
 
106
    if( m_size > 0 )
 
107
    {
 
108
      MenuItemsChangedCallback( m_model, 0, m_size, 0, this );
 
109
    }
 
110
    DisconnectCallback();
 
111
    g_object_unref( m_model );
 
112
  }
 
113
 
 
114
  for( auto child : m_children )
 
115
  {
 
116
    delete child;
 
117
  }
 
118
  m_children.clear();
 
119
 
 
120
  delete m_menu;
 
121
  delete m_ext_menu;
 
122
}
 
123
 
 
124
GMenuModel* QtGMenuModel::Model() const
 
125
{
 
126
  return m_model;
 
127
}
 
128
 
 
129
QtGMenuModel::LinkType QtGMenuModel::Type() const
 
130
{
 
131
  return m_link_type;
 
132
}
 
133
 
 
134
int QtGMenuModel::Size() const
 
135
{
 
136
  return m_size;
 
137
}
 
138
 
 
139
QtGMenuModel* QtGMenuModel::Parent() const
 
140
{
 
141
  return m_parent;
 
142
}
 
143
 
 
144
QtGMenuModel* QtGMenuModel::Child( int index ) const
 
145
{
 
146
  if( m_children.contains( index ) )
 
147
  {
 
148
    return m_children.value( index );
 
149
  }
 
150
 
 
151
  return nullptr;
 
152
}
 
153
 
 
154
std::shared_ptr< QMenu > QtGMenuModel::GetQMenu()
 
155
{
 
156
  auto top_menu = std::make_shared< QMenu >();
 
157
 
 
158
  AppendQMenu( top_menu );
 
159
 
 
160
  return top_menu;
 
161
}
 
162
 
 
163
void QtGMenuModel::ActionTriggered( bool checked )
 
164
{
 
165
  QAction* action = dynamic_cast< QAction* >( QObject::sender() );
 
166
  emit ActionTriggered( action->property( c_property_actionName ).toString(), checked );
 
167
}
 
168
 
 
169
void QtGMenuModel::ActionEnabled( QString action_name, bool enabled )
 
170
{
 
171
  QAction* action = FindAction( action_name );
 
172
  if( action )
 
173
  {
 
174
    action->setEnabled( enabled );
 
175
  }
 
176
}
 
177
 
 
178
void QtGMenuModel::ActionParameterized( QString action_name, bool parameterized )
 
179
{
 
180
  QAction* action = FindAction( action_name );
 
181
  if( action )
 
182
  {
 
183
    action->setProperty( c_property_isParameterized, parameterized );
 
184
  }
 
185
}
 
186
 
 
187
QtGMenuModel* QtGMenuModel::CreateChild( QtGMenuModel* parent, GMenuModel* model, int index )
 
188
{
 
189
  LinkType linkType( LinkType::SubMenu );
 
190
  GMenuModel* link = g_menu_model_get_item_link( model, index, G_MENU_LINK_SUBMENU );
 
191
 
 
192
  if( !link )
 
193
  {
 
194
    linkType = LinkType::Section;
 
195
    link = g_menu_model_get_item_link( model, index, G_MENU_LINK_SECTION );
 
196
  }
 
197
 
 
198
  if( link )
 
199
  {
 
200
    return new QtGMenuModel( link, linkType, parent, index );
 
201
  }
 
202
 
 
203
  return nullptr;
 
204
}
 
205
 
 
206
void QtGMenuModel::MenuItemsChangedCallback( GMenuModel* model, gint index, gint removed,
 
207
    gint added, gpointer user_data )
 
208
{
 
209
  QtGMenuModel* self = reinterpret_cast< QtGMenuModel* >( user_data );
 
210
  self->ChangeMenuItems( index, added, removed );
 
211
}
 
212
 
 
213
void QtGMenuModel::ChangeMenuItems( int index, int added, int removed )
 
214
{
 
215
  if( removed > 0 )
 
216
  {
 
217
    for( int i = 0; i < removed; ++i )
 
218
    {
 
219
      if( index < m_menu->actions().size() )
 
220
      {
 
221
        QAction* at_action = m_menu->actions().at( index );
 
222
        m_menu->removeAction( at_action );
 
223
      }
 
224
    }
 
225
 
 
226
    for( int i = index; i < m_size; ++i )
 
227
    {
 
228
      if( i <= ( index + removed ) )
 
229
      {
 
230
        delete m_children.take( i );
 
231
      }
 
232
      else if( m_children.contains( i ) )
 
233
      {
 
234
        m_children.insert( i - removed, m_children.take( i ) );
 
235
      }
 
236
    }
 
237
 
 
238
    m_size -= removed;
 
239
  }
 
240
 
 
241
  if( added > 0 )
 
242
  {
 
243
    // shift items up
 
244
    for( int i = ( m_size + added ) - 1; i >= index; --i )
 
245
    {
 
246
      if( m_children.contains( i ) )
 
247
      {
 
248
        m_children.insert( i + added, m_children.take( i ) );
 
249
      }
 
250
    }
 
251
 
 
252
    m_size += added;
 
253
 
 
254
    for( int i = index; i < ( index + added ); ++i )
 
255
    {
 
256
      QAction* at_action = nullptr;
 
257
      if( i < m_menu->actions().size() )
 
258
      {
 
259
        at_action = m_menu->actions().at( i );
 
260
      }
 
261
 
 
262
      QtGMenuModel* model = CreateChild( this, m_model, i );
 
263
 
 
264
      if( !model )
 
265
      {
 
266
        m_menu->insertAction( at_action, CreateAction( i ) );
 
267
      }
 
268
      else if( model->Type() == LinkType::Section )
 
269
      {
 
270
        m_menu->insertSeparator( at_action );
 
271
      }
 
272
      else if( model->Type() == LinkType::SubMenu )
 
273
      {
 
274
        m_menu->insertMenu( at_action, model->m_ext_menu );
 
275
      }
 
276
    }
 
277
  }
 
278
 
 
279
  // update external menu
 
280
  UpdateExtQMenu();
 
281
  if( m_link_type == LinkType::Section && m_parent )
 
282
  {
 
283
    m_parent->UpdateExtQMenu();
 
284
  }
 
285
 
 
286
  emit MenuItemsChanged( this, index, removed, added );
 
287
}
 
288
 
 
289
void QtGMenuModel::ConnectCallback()
 
290
{
 
291
  if( m_model && m_items_changed_handler == 0 )
 
292
  {
 
293
    m_items_changed_handler = g_signal_connect( m_model, "items-changed",
 
294
        G_CALLBACK( MenuItemsChangedCallback ), this );
 
295
  }
 
296
}
 
297
 
 
298
void QtGMenuModel::DisconnectCallback()
 
299
{
 
300
  if( m_model && m_items_changed_handler != 0 )
 
301
  {
 
302
    g_signal_handler_disconnect( m_model, m_items_changed_handler );
 
303
  }
 
304
 
 
305
  m_items_changed_handler = 0;
 
306
}
 
307
 
 
308
void QtGMenuModel::InsertChild( QtGMenuModel* child, int index )
 
309
{
 
310
  if( m_children.contains( index ) )
 
311
  {
 
312
    return;
 
313
  }
 
314
 
 
315
  child->m_parent = this;
 
316
  m_children.insert( index, child );
 
317
 
 
318
  connect( child, SIGNAL( MenuItemsChanged( QtGMenuModel*, int, int, int ) ), this,
 
319
      SIGNAL( MenuItemsChanged( QtGMenuModel*, int, int, int ) ) );
 
320
 
 
321
  connect( child, SIGNAL( ActionTriggered( QString, bool ) ), this,
 
322
      SIGNAL( ActionTriggered( QString, bool ) ) );
 
323
}
 
324
 
 
325
int QtGMenuModel::ChildIndex( QtGMenuModel* child )
 
326
{
 
327
  for( int i = 0; i < m_children.size(); ++i )
 
328
  {
 
329
    if( child == m_children[i] )
 
330
    {
 
331
      return i;
 
332
    }
 
333
  }
 
334
 
 
335
  return -1;
 
336
}
 
337
 
 
338
QAction* QtGMenuModel::CreateAction( int index )
 
339
{
 
340
  // action label
 
341
  QAction* action = new QAction( this );
 
342
 
 
343
  gchar* label = NULL;
 
344
  if( g_menu_model_get_item_attribute( m_model, index, G_MENU_ATTRIBUTE_LABEL, "s", &label ) ) {
 
345
    QString qlabel = QString::fromUtf8( label );
 
346
    qlabel.replace( '_', '&' );
 
347
    g_free( label );
 
348
 
 
349
    action->setText( qlabel );
 
350
  }
 
351
 
 
352
  // action name
 
353
  gchar* action_name = NULL;
 
354
  if( g_menu_model_get_item_attribute( m_model, index,
 
355
              G_MENU_ATTRIBUTE_ACTION, "s", &action_name ) )
 
356
  {
 
357
    QString qaction_name = QString::fromUtf8( action_name );
 
358
    g_free( action_name );
 
359
 
 
360
    int name_length = qaction_name.size() - qaction_name.indexOf( '.' ) - 1;
 
361
    qaction_name = qaction_name.right( name_length );
 
362
 
 
363
    action->setProperty( c_property_actionName, qaction_name );
 
364
  }
 
365
 
 
366
  // is parameterized (set false by default until signal received)
 
367
  action->setProperty( c_property_isParameterized, false );
 
368
 
 
369
  // dbus paths
 
370
  action->setProperty( c_property_busName, m_bus_name );
 
371
  action->setProperty( c_property_menuPath, m_menu_path );
 
372
  action->setProperty( c_property_actionsPath, m_actions_path );
 
373
 
 
374
  // action icon
 
375
  GVariant* icon = g_menu_model_get_item_attribute_value( m_model, index, G_MENU_ATTRIBUTE_ICON,
 
376
      G_VARIANT_TYPE_VARIANT );
 
377
 
 
378
  if( icon )
 
379
  {
 
380
    g_variant_unref( icon );
 
381
  }
 
382
 
 
383
  // action shortcut
 
384
  gchar* shortcut = NULL;
 
385
  if( g_menu_model_get_item_attribute( m_model, index, "accel", "s", &shortcut ) )
 
386
  {
 
387
    QString qshortcut = QString::fromUtf8( shortcut );
 
388
    g_free( shortcut );
 
389
 
 
390
    action->setShortcut( QtGMenuUtils::QStringToQKeySequence( qshortcut ) );
 
391
  }
 
392
 
 
393
  // action shortcut
 
394
  gchar* toolbar_item = NULL;
 
395
  if( g_menu_model_get_item_attribute( m_model, index, c_property_hud_toolbar_item, "s", &toolbar_item ) )
 
396
  {
 
397
    QString qtoolbar_item = QString::fromUtf8( toolbar_item );
 
398
    g_free( toolbar_item );
 
399
 
 
400
    action->setProperty( c_property_hud_toolbar_item, qtoolbar_item );
 
401
  }
 
402
 
 
403
  // action keywords
 
404
  gchar* keywords = NULL;
 
405
  if( g_menu_model_get_item_attribute( m_model, index, c_property_keywords, "s", &keywords ) )
 
406
  {
 
407
    QVariant qkeywords = QString::fromUtf8( keywords );
 
408
    g_free( keywords );
 
409
 
 
410
    action->setProperty( c_property_keywords, qkeywords );
 
411
  }
 
412
 
 
413
  // action trigger
 
414
  connect( action, SIGNAL( triggered( bool ) ), this, SLOT( ActionTriggered( bool ) ) );
 
415
 
 
416
  return action;
 
417
}
 
418
 
 
419
QAction* QtGMenuModel::FindAction( QString name )
 
420
{
 
421
  if( m_ext_menu->menuAction()->property( c_property_actionName ) == name )
 
422
  {
 
423
    return m_ext_menu->menuAction();
 
424
  }
 
425
 
 
426
  for( QAction* action : m_menu->actions() )
 
427
  {
 
428
    if( action->property( c_property_actionName ) == name )
 
429
    {
 
430
      return action;
 
431
    }
 
432
  }
 
433
 
 
434
  for( QtGMenuModel* child : m_children )
 
435
  {
 
436
    QAction* action = child->FindAction( name );
 
437
    if( action )
 
438
    {
 
439
      return action;
 
440
    }
 
441
  }
 
442
 
 
443
  return nullptr;
 
444
}
 
445
 
 
446
void QtGMenuModel::AppendQMenu( std::shared_ptr< QMenu > top_menu )
 
447
{
 
448
  if( m_link_type == LinkType::Root )
 
449
  {
 
450
    for( QAction* action : m_ext_menu->actions() )
 
451
    {
 
452
      if( !action->menu() )
 
453
      {
 
454
        top_menu->addAction( action );
 
455
      }
 
456
    }
 
457
  }
 
458
  else if( m_link_type == LinkType::SubMenu )
 
459
  {
 
460
    top_menu->addAction( m_ext_menu->menuAction() );
 
461
  }
 
462
 
 
463
  if( m_link_type != LinkType::SubMenu )
 
464
  {
 
465
    for( auto& child : m_children )
 
466
    {
 
467
      child->AppendQMenu( top_menu );
 
468
    }
 
469
  }
 
470
}
 
471
 
 
472
void QtGMenuModel::UpdateExtQMenu()
 
473
{
 
474
  m_ext_menu->clear();
 
475
 
 
476
  for( int i = 0; i < m_menu->actions().size(); ++i )
 
477
  {
 
478
    QAction* action = m_menu->actions().at( i );
 
479
 
 
480
    if( action->isSeparator() )
 
481
    {
 
482
      QtGMenuModel* child = Child( i );
 
483
      if( !child || child->Type() != LinkType::Section )
 
484
      {
 
485
        continue;
 
486
      }
 
487
      QMenu* section = child->m_ext_menu;
 
488
 
 
489
      for( QAction* sub_action : section->actions() )
 
490
      {
 
491
        m_ext_menu->addAction( sub_action );
 
492
      }
 
493
      m_ext_menu->addSeparator();
 
494
    }
 
495
    else
 
496
    {
 
497
      m_ext_menu->addAction( action );
 
498
    }
 
499
  }
 
500
 
 
501
  if( m_ext_menu->actions().size() > 0 )
 
502
  {
 
503
    QAction* last_action = m_ext_menu->actions().last();
 
504
    if( last_action && last_action->isSeparator() )
 
505
    {
 
506
      m_ext_menu->removeAction( last_action );
 
507
    }
 
508
  }
 
509
}