~ubuntu-branches/ubuntu/trusty/hud/trusty-proposed

« back to all changes in this revision

Viewing changes to libqtgmenu/internal/QtGMenuModel.cpp

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release, Pete Woods, Marcus Tomlinson
  • Date: 2014-04-25 08:48:46 UTC
  • mfrom: (1.1.34)
  • Revision ID: package-import@ubuntu.com-20140425084846-ou5d0qsm18g6lyrv
Tags: 13.10.1+14.04.20140425-0ubuntu1
[ Pete Woods ]
* Harden HUD against misbehaving applications Report the offending
  applications using Apport's recoverable problem tool. Switch to
  using shared pointers where possible for managing memory. (LP:
  #1298656)

[ Marcus Tomlinson ]
* Harden HUD against misbehaving applications Report the offending
  applications using Apport's recoverable problem tool. Switch to
  using shared pointers where possible for managing memory. (LP:
  #1298656)

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
#include <QtGMenuModel.h>
20
20
#include <QtGMenuUtils.h>
 
21
#include <QCoreApplication>
 
22
#include <QDBusConnection>
 
23
#include <QDBusConnectionInterface>
21
24
#include <QDebug>
 
25
#include <QProcess>
 
26
#include <QRegularExpression>
22
27
 
23
28
using namespace qtgmenu;
24
29
 
25
 
QtGMenuModel::QtGMenuModel( GMenuModel* model )
26
 
    : QtGMenuModel( model, LinkType::Root, nullptr, 0 )
27
 
{
28
 
}
 
30
static const QRegularExpression SINGLE_UNDERSCORE("(?<![_])[_](?![_])");
29
31
 
30
 
QtGMenuModel::QtGMenuModel( GMenuModel* model, const QString& bus_name, const QString& menu_path, const QMap<QString, QDBusObjectPath>& action_paths )
31
 
    : QtGMenuModel( model, LinkType::Root, nullptr, 0 )
 
32
QtGMenuModel::QtGMenuModel( QSharedPointer<GDBusConnection> connection, const QString& bus_name,
 
33
                            const QString& menu_path, const QMap<QString, QDBusObjectPath>& action_paths )
 
34
    : QtGMenuModel( QSharedPointer<GMenuModel>(G_MENU_MODEL( g_dbus_menu_model_get( connection.data(),
 
35
                                                         bus_name.toUtf8().constData(),
 
36
                                                         menu_path.toUtf8().constData() ) ), &g_object_unref ),
 
37
                    LinkType::Root, nullptr, 0 )
32
38
{
 
39
  m_connection = connection;
33
40
  m_bus_name = bus_name;
34
41
  m_menu_path = menu_path;
35
42
  m_action_paths = action_paths;
36
43
}
37
44
 
38
 
QtGMenuModel::QtGMenuModel( GMenuModel* model, LinkType link_type, QtGMenuModel* parent, int index )
 
45
QtGMenuModel::QtGMenuModel( QSharedPointer<GMenuModel> model, LinkType link_type, QtGMenuModel* parent, int index )
39
46
    : m_parent( parent ),
40
47
      m_model( model ),
41
 
      m_link_type( link_type )
 
48
      m_link_type( link_type ),
 
49
      m_menu( new QMenu() ),
 
50
      m_ext_menu( new QMenu() )
42
51
{
43
52
  ConnectCallback();
44
53
 
45
54
  if( m_parent )
46
55
  {
47
 
    m_parent->InsertChild( this, index );
48
 
 
 
56
    m_connection = m_parent->m_connection;
49
57
    m_bus_name = m_parent->m_bus_name;
50
58
    m_menu_path = m_parent->m_menu_path;
51
59
    m_action_paths = m_parent->m_action_paths;
52
60
 
53
61
    gchar* label = NULL;
54
 
    if( g_menu_model_get_item_attribute( m_parent->m_model, index,
 
62
    if( g_menu_model_get_item_attribute( m_parent->m_model.data(), index,
55
63
            G_MENU_ATTRIBUTE_LABEL, "s", &label ) )
56
64
    {
57
65
      QString qlabel = QString::fromUtf8( label );
58
 
      qlabel.replace( '_', '&' );
 
66
      qlabel.replace( SINGLE_UNDERSCORE, "&" );
59
67
      g_free( label );
60
68
 
61
69
      m_ext_menu->setTitle( qlabel );
63
71
 
64
72
    gchar* action_name = NULL;
65
73
    QString qaction_name;
66
 
    if( g_menu_model_get_item_attribute( m_parent->m_model, index,
 
74
    if( g_menu_model_get_item_attribute( m_parent->m_model.data(), index,
67
75
            G_MENU_ATTRIBUTE_ACTION, "s", &action_name ) )
68
76
    {
69
77
      qaction_name = QString::fromUtf8( action_name );
74
82
 
75
83
    // if this model has a "commitLabel" property, it is a libhud parameterized action
76
84
    gchar* commit_label = NULL;
77
 
    if( g_menu_model_get_item_attribute( m_parent->m_model, index,
 
85
    if( g_menu_model_get_item_attribute( m_parent->m_model.data(), index,
78
86
            "commitLabel", "s", &commit_label ) )
79
87
    {
80
88
      g_free( commit_label );
100
108
 
101
109
  if( m_model )
102
110
  {
103
 
    m_size = g_menu_model_get_n_items( m_model );
 
111
    m_size = g_menu_model_get_n_items( m_model.data() );
104
112
  }
105
113
 
106
114
  ChangeMenuItems( 0, m_size, 0 );
112
120
  {
113
121
    if( m_size > 0 )
114
122
    {
115
 
      MenuItemsChangedCallback( m_model, 0, m_size, 0, this );
 
123
      ChangeMenuItems( 0, 0, m_size );
116
124
    }
117
125
    DisconnectCallback();
118
 
    g_object_unref( m_model );
119
126
  }
120
127
 
121
 
  for( auto child : m_children )
122
 
  {
123
 
    delete child;
124
 
  }
125
128
  m_children.clear();
126
 
 
127
 
  delete m_menu;
128
 
  delete m_ext_menu;
129
129
}
130
130
 
131
 
GMenuModel* QtGMenuModel::Model() const
 
131
QSharedPointer<GMenuModel> QtGMenuModel::Model() const
132
132
{
133
133
  return m_model;
134
134
}
138
138
  return m_link_type;
139
139
}
140
140
 
141
 
int QtGMenuModel::Size() const
142
 
{
143
 
  return m_size;
144
 
}
145
 
 
146
141
QtGMenuModel* QtGMenuModel::Parent() const
147
142
{
148
143
  return m_parent;
149
144
}
150
145
 
151
 
QtGMenuModel* QtGMenuModel::Child( int index ) const
 
146
QSharedPointer<QtGMenuModel> QtGMenuModel::Child( int index ) const
152
147
{
153
148
  if( m_children.contains( index ) )
154
149
  {
155
150
    return m_children.value( index );
156
151
  }
157
152
 
158
 
  return nullptr;
 
153
  return QSharedPointer<QtGMenuModel>();
159
154
}
160
155
 
161
156
std::shared_ptr< QMenu > QtGMenuModel::GetQMenu()
178
173
  auto action_it = m_actions.find( action_name );
179
174
  if( action_it != end( m_actions ) )
180
175
  {
181
 
    action_it->second->setEnabled( enabled );
 
176
    action_it->second.second->setEnabled( enabled );
182
177
  }
183
178
}
184
179
 
187
182
  auto action_it = m_actions.find( action_name );
188
183
  if( action_it != end( m_actions ) )
189
184
  {
190
 
    action_it->second->setProperty( c_property_isParameterized, parameterized );
 
185
    action_it->second.second->setProperty( c_property_isParameterized, parameterized );
191
186
  }
192
187
}
193
188
 
194
 
QtGMenuModel* QtGMenuModel::CreateChild( QtGMenuModel* parent, GMenuModel* model, int index )
 
189
QSharedPointer<QtGMenuModel> QtGMenuModel::CreateChild( QtGMenuModel* parent_qtgmenu, QSharedPointer<GMenuModel> parent_gmenu, int child_index )
195
190
{
196
 
  LinkType linkType( LinkType::SubMenu );
197
 
  GMenuModel* link = g_menu_model_get_item_link( model, index, G_MENU_LINK_SUBMENU );
198
 
 
199
 
  if( !link )
200
 
  {
201
 
    linkType = LinkType::Section;
202
 
    link = g_menu_model_get_item_link( model, index, G_MENU_LINK_SECTION );
203
 
  }
204
 
 
205
 
  if( link )
206
 
  {
207
 
    return new QtGMenuModel( link, linkType, parent, index );
208
 
  }
209
 
 
210
 
  return nullptr;
 
191
  QSharedPointer<QtGMenuModel> new_child;
 
192
 
 
193
  GMenuLinkIter* link_it = g_menu_model_iterate_item_links( parent_gmenu.data(), child_index );
 
194
 
 
195
  // get the first link, if it exists, create the child accordingly
 
196
  if( link_it && g_menu_link_iter_next( link_it ) )
 
197
  {
 
198
    // if link is a sub menu
 
199
    if( strcmp( g_menu_link_iter_get_name( link_it ), G_MENU_LINK_SUBMENU ) == 0 )
 
200
    {
 
201
      new_child.reset(
 
202
                new QtGMenuModel(
 
203
                        QSharedPointer<GMenuModel>(
 
204
                                g_menu_link_iter_get_value(link_it),
 
205
                                &g_object_unref), LinkType::SubMenu,
 
206
                        parent_qtgmenu, child_index));
 
207
    }
 
208
    // else if link is a section
 
209
    else if( strcmp( g_menu_link_iter_get_name( link_it ), G_MENU_LINK_SECTION ) == 0 )
 
210
    {
 
211
      new_child.reset(
 
212
                    new QtGMenuModel(
 
213
                            QSharedPointer<GMenuModel>(
 
214
                                    g_menu_link_iter_get_value(link_it),
 
215
                                    &g_object_unref), LinkType::Section,
 
216
                            parent_qtgmenu, child_index));
 
217
    }
 
218
  }
 
219
 
 
220
  g_object_unref( link_it );
 
221
  return new_child;
211
222
}
212
223
 
213
224
void QtGMenuModel::MenuItemsChangedCallback( GMenuModel* model, gint index, gint removed,
214
225
    gint added, gpointer user_data )
215
226
{
216
227
  QtGMenuModel* self = reinterpret_cast< QtGMenuModel* >( user_data );
 
228
 
 
229
  if( self->m_model != model )
 
230
  {
 
231
    qWarning() << "\"items-changed\" signal received from an unrecognised menu model";
 
232
    return;
 
233
  }
 
234
 
217
235
  self->ChangeMenuItems( index, added, removed );
218
236
}
219
237
 
220
 
void QtGMenuModel::ChangeMenuItems( int index, int added, int removed )
 
238
void QtGMenuModel::ChangeMenuItems( const int index, const int added, const int removed )
221
239
{
 
240
  const int n_items = g_menu_model_get_n_items( m_model.data() );
 
241
  bool invalid_arguments = false;
 
242
 
 
243
  if( index < 0 || added < 0 || removed < 0 || index + added > n_items || index + removed > m_size )
 
244
  {
 
245
    ReportRecoverableError(index, added, removed);
 
246
    return;
 
247
  }
 
248
 
 
249
  // process removed items first (see "items-changed" on the GMenuModel man page)
222
250
  if( removed > 0 )
223
251
  {
 
252
    // remove QAction from 'index' of our QMenu, 'removed' times
224
253
    for( int i = 0; i < removed; ++i )
225
254
    {
226
255
      if( index < m_menu->actions().size() )
231
260
      }
232
261
    }
233
262
 
 
263
    // update m_children
234
264
    for( int i = index; i < m_size; ++i )
235
265
    {
236
 
      if( i <= ( index + removed ) )
 
266
      // remove children from index until ( index + removed )
 
267
      if( i < ( index + removed ) )
237
268
      {
238
 
        delete m_children.take( i );
 
269
        m_children.take( i );
239
270
      }
 
271
      // shift children from ( index + removed ) to m_size into the now empty positions
240
272
      else if( m_children.contains( i ) )
241
273
      {
242
274
        m_children.insert( i - removed, m_children.take( i ) );
243
275
      }
244
276
    }
245
277
 
 
278
    // update m_size
246
279
    m_size -= removed;
247
280
  }
248
281
 
 
282
  // now process added items
249
283
  if( added > 0 )
250
284
  {
251
 
    // shift items up
252
 
    for( int i = ( m_size + added ) - 1; i >= index; --i )
 
285
    // update m_children
 
286
    for( int i = index; i < ( index + added ); ++i )
253
287
    {
 
288
      // shift 'added' items up from their current index to ( index + added )
254
289
      if( m_children.contains( i ) )
255
290
      {
256
291
        m_children.insert( i + added, m_children.take( i ) );
257
292
      }
258
293
    }
259
294
 
 
295
    // update m_size
260
296
    m_size += added;
261
297
 
 
298
    // now add a new QAction to our QMenu for each new item
262
299
    for( int i = index; i < ( index + added ); ++i )
263
300
    {
264
301
      QAction* at_action = nullptr;
267
304
        at_action = m_menu->actions().at( i );
268
305
      }
269
306
 
270
 
      QtGMenuModel* model = CreateChild( this, m_model, i );
 
307
      // try first to create a child model
 
308
      QSharedPointer< QtGMenuModel > model = CreateChild( this, m_model, i );
271
309
 
 
310
      // if this is a menu item and not a model
272
311
      if( !model )
273
312
      {
274
313
        QAction* new_action = CreateAction( i );
275
314
        ActionAdded( new_action->property( c_property_actionName ).toString(), new_action );
276
315
        m_menu->insertAction( at_action, new_action );
277
316
      }
 
317
      // else if this is a section model
278
318
      else if( model->Type() == LinkType::Section )
279
319
      {
 
320
        InsertChild( model, i );
280
321
        m_menu->insertSeparator( at_action );
281
322
      }
 
323
      // else if this is a sub menu model
282
324
      else if( model->Type() == LinkType::SubMenu )
283
325
      {
284
 
        m_menu->insertMenu( at_action, model->m_ext_menu );
 
326
        InsertChild( model, i );
 
327
        ActionAdded( model->m_ext_menu->menuAction()->property( c_property_actionName ).toString(),
 
328
                     model->m_ext_menu->menuAction() );
 
329
        m_menu->insertMenu( at_action, model->m_ext_menu.data() );
285
330
      }
286
331
    }
287
332
  }
293
338
    m_parent->UpdateExtQMenu();
294
339
  }
295
340
 
 
341
  // now tell the outside world that items have changed
296
342
  emit MenuItemsChanged( this, index, removed, added );
297
343
}
298
344
 
300
346
{
301
347
  if( m_model && m_items_changed_handler == 0 )
302
348
  {
303
 
    m_items_changed_handler = g_signal_connect( m_model, "items-changed",
 
349
    m_items_changed_handler = g_signal_connect( m_model.data(), "items-changed",
304
350
        G_CALLBACK( MenuItemsChangedCallback ), this );
305
351
  }
306
352
}
309
355
{
310
356
  if( m_model && m_items_changed_handler != 0 )
311
357
  {
312
 
    g_signal_handler_disconnect( m_model, m_items_changed_handler );
 
358
    g_signal_handler_disconnect( m_model.data(), m_items_changed_handler );
313
359
  }
314
360
 
315
361
  m_items_changed_handler = 0;
316
362
}
317
363
 
318
 
void QtGMenuModel::InsertChild( QtGMenuModel* child, int index )
 
364
void QtGMenuModel::InsertChild( QSharedPointer<QtGMenuModel> child, int index )
319
365
{
320
366
  if( m_children.contains( index ) )
321
367
  {
325
371
  child->m_parent = this;
326
372
  m_children.insert( index, child );
327
373
 
328
 
  connect( child, SIGNAL( MenuItemsChanged( QtGMenuModel*, int, int, int ) ), this,
 
374
  connect( child.data(), SIGNAL( MenuItemsChanged( QtGMenuModel*, int, int, int ) ), this,
329
375
      SIGNAL( MenuItemsChanged( QtGMenuModel*, int, int, int ) ) );
330
376
 
331
 
  connect( child, SIGNAL( ActionTriggered( QString, bool ) ), this,
 
377
  connect( child.data(), SIGNAL( ActionTriggered( QString, bool ) ), this,
332
378
      SIGNAL( ActionTriggered( QString, bool ) ) );
333
 
}
334
 
 
335
 
int QtGMenuModel::ChildIndex( QtGMenuModel* child )
336
 
{
337
 
  for( int i = 0; i < m_children.size(); ++i )
338
 
  {
339
 
    if( child == m_children[i] )
340
 
    {
341
 
      return i;
342
 
    }
343
 
  }
344
 
 
345
 
  return -1;
 
379
 
 
380
  connect( child.data(), SIGNAL( MenuInvalid() ), this, SIGNAL( MenuInvalid() ) );
 
381
 
 
382
  // emit signal informing subscribers that this child has added all of its menu items
 
383
  emit MenuItemsChanged( child.data(), 0, 0, child->m_size );
346
384
}
347
385
 
348
386
QAction* QtGMenuModel::CreateAction( int index )
349
387
{
 
388
  QAction* action = new QAction( m_menu.data() );
 
389
 
350
390
  // action label
351
 
  QAction* action = new QAction( this );
352
 
 
353
391
  gchar* label = NULL;
354
 
  if( g_menu_model_get_item_attribute( m_model, index, G_MENU_ATTRIBUTE_LABEL, "s", &label ) ) {
 
392
  if( g_menu_model_get_item_attribute( m_model.data(), index, G_MENU_ATTRIBUTE_LABEL, "s", &label ) ) {
355
393
    QString qlabel = QString::fromUtf8( label );
356
 
    qlabel.replace( '_', '&' );
 
394
    qlabel.replace( SINGLE_UNDERSCORE, "&" );
357
395
    g_free( label );
358
396
 
359
397
    action->setText( qlabel );
361
399
 
362
400
  // action name
363
401
  gchar* action_name = NULL;
364
 
  if( g_menu_model_get_item_attribute( m_model, index,
 
402
  if( g_menu_model_get_item_attribute( m_model.data(), index,
365
403
              G_MENU_ATTRIBUTE_ACTION, "s", &action_name ) )
366
404
  {
367
405
    QString qaction_name = QString::fromUtf8( action_name );
378
416
  action->setProperty( c_property_menuPath, m_menu_path );
379
417
 
380
418
  // action icon
381
 
  GVariant* icon = g_menu_model_get_item_attribute_value( m_model, index, G_MENU_ATTRIBUTE_ICON,
 
419
  GVariant* icon = g_menu_model_get_item_attribute_value( m_model.data(), index, G_MENU_ATTRIBUTE_ICON,
382
420
      G_VARIANT_TYPE_VARIANT );
383
421
 
384
422
  if( icon )
388
426
 
389
427
  // action shortcut
390
428
  gchar* shortcut = NULL;
391
 
  if( g_menu_model_get_item_attribute( m_model, index, "accel", "s", &shortcut ) )
 
429
  if( g_menu_model_get_item_attribute( m_model.data(), index, "accel", "s", &shortcut ) )
392
430
  {
393
431
    QString qshortcut = QString::fromUtf8( shortcut );
394
432
    g_free( shortcut );
398
436
 
399
437
  // action shortcut
400
438
  gchar* toolbar_item = NULL;
401
 
  if( g_menu_model_get_item_attribute( m_model, index, c_property_hud_toolbar_item, "s", &toolbar_item ) )
 
439
  if( g_menu_model_get_item_attribute( m_model.data(), index, c_property_hud_toolbar_item, "s", &toolbar_item ) )
402
440
  {
403
441
    QString qtoolbar_item = QString::fromUtf8( toolbar_item );
404
442
    g_free( toolbar_item );
408
446
 
409
447
  // action keywords
410
448
  gchar* keywords = NULL;
411
 
  if( g_menu_model_get_item_attribute( m_model, index, c_property_keywords, "s", &keywords ) )
 
449
  if( g_menu_model_get_item_attribute( m_model.data(), index, c_property_keywords, "s", &keywords ) )
412
450
  {
413
451
    QVariant qkeywords = QString::fromUtf8( keywords );
414
452
    g_free( keywords );
458
496
 
459
497
    if( action->isSeparator() )
460
498
    {
461
 
      QtGMenuModel* child = Child( i );
 
499
      QSharedPointer<QtGMenuModel> child = Child( i );
462
500
      if( !child || child->Type() != LinkType::Section )
463
501
      {
464
502
        continue;
465
503
      }
466
 
      QMenu* section = child->m_ext_menu;
467
504
 
468
 
      for( QAction* sub_action : section->actions() )
 
505
      for( QAction* sub_action : child->m_ext_menu->actions() )
469
506
      {
470
507
        m_ext_menu->addAction( sub_action );
471
508
      }
494
531
  {
495
532
    m_parent->ActionAdded( name, action );
496
533
  }
497
 
 
498
 
  m_actions[name] = action;
 
534
  else
 
535
  {
 
536
    // check if this action is already in our map
 
537
    if( m_actions.find( name ) != m_actions.end() )
 
538
    {
 
539
      // increment the reference count for this action
 
540
      ++m_actions[name].first;
 
541
    }
 
542
    else
 
543
    {
 
544
      // otherwise insert the new action into the map
 
545
      m_actions.insert( std::make_pair( name, std::make_pair( 1, action ) ) );
 
546
    }
 
547
  }
499
548
}
500
549
 
501
550
void QtGMenuModel::ActionRemoved( const QString& name )
505
554
  {
506
555
    m_parent->ActionRemoved( name );
507
556
  }
508
 
 
509
 
  m_actions.erase( name );
 
557
  else
 
558
  {
 
559
    // check if this action is actually in our map
 
560
    if( m_actions.find( name ) != m_actions.end() )
 
561
    {
 
562
      // decrement the reference count for this action
 
563
      if( --m_actions[name].first == 0 )
 
564
      {
 
565
        // if there are no more references to this action, remove it from the map
 
566
        m_actions.erase( name );
 
567
      }
 
568
    }
 
569
  }
 
570
}
 
571
 
 
572
static void write_pair(QIODevice& device, const QString& key, const QString& value, bool last = false)
 
573
{
 
574
  device.write(key.toUtf8());
 
575
  device.write("", 1);
 
576
  device.write(value.toUtf8());
 
577
  if( !last )
 
578
  {
 
579
    device.write("", 1);
 
580
  }
 
581
 
 
582
  if( !value.isEmpty())
 
583
  {
 
584
    qWarning() << key << " =" << value;
 
585
  }
 
586
}
 
587
 
 
588
void QtGMenuModel::ReportRecoverableError(const int index, const int added, const int removed)
 
589
{
 
590
  if( m_error_reported )
 
591
  {
 
592
    return;
 
593
  }
 
594
 
 
595
  // gmenumodel properties
 
596
  int gmenu_item_count = 0;
 
597
  QString gmenu_action_names;
 
598
 
 
599
  gmenu_item_count = g_menu_model_get_n_items( m_model.data() );
 
600
 
 
601
  qWarning() << "Illegal arguments when updating GMenuModel: position ="
 
602
             << index << ", added =" << added << ", removed =" << removed
 
603
             << ", size =" << gmenu_item_count;
 
604
 
 
605
  for( int i = 0; i < gmenu_item_count; ++i )
 
606
  {
 
607
    gchar* action_name = NULL;
 
608
    if( g_menu_model_get_item_attribute( m_model.data(), i,
 
609
          G_MENU_ATTRIBUTE_ACTION, "s", &action_name ) )
 
610
    {
 
611
      gmenu_action_names += action_name;
 
612
      gmenu_action_names += ";";
 
613
      g_free( action_name );
 
614
    }
 
615
  }
 
616
 
 
617
  // parent model properties
 
618
  QString parent_menu_label;
 
619
  QString parent_menu_name;
 
620
  QString parent_action_names;
 
621
  QString parent_link_type;
 
622
 
 
623
  if( m_parent )
 
624
  {
 
625
    parent_menu_label = m_parent->m_menu->menuAction()->text();
 
626
    parent_menu_name = m_parent->m_menu->menuAction()->property( c_property_actionName ).toString();
 
627
 
 
628
    for( QAction* action : m_parent->m_menu->actions() )
 
629
    {
 
630
      parent_action_names += action->property( c_property_actionName ).toString() + ";";
 
631
    }
 
632
 
 
633
    switch( m_parent->m_link_type )
 
634
    {
 
635
    case LinkType::Root:
 
636
      parent_link_type = "root";
 
637
      break;
 
638
    case LinkType::Section:
 
639
      parent_link_type = "section";
 
640
      break;
 
641
    case LinkType::SubMenu:
 
642
      parent_link_type = "sub menu";
 
643
      break;
 
644
    }
 
645
  }
 
646
 
 
647
  // local model properties
 
648
  QString menu_label;
 
649
  QString menu_name;
 
650
  QString action_names;
 
651
  QString link_type;
 
652
  QString action_paths;
 
653
 
 
654
  menu_label = m_menu->menuAction()->text();
 
655
  menu_name = m_menu->menuAction()->property( c_property_actionName ).toString();
 
656
  for( QAction* action : m_menu->actions() )
 
657
  {
 
658
    action_names += action->property( c_property_actionName ).toString() + ";";
 
659
  }
 
660
 
 
661
  switch( m_link_type )
 
662
  {
 
663
  case LinkType::Root:
 
664
    link_type = "root";
 
665
    break;
 
666
  case LinkType::Section:
 
667
    link_type = "section";
 
668
    break;
 
669
  case LinkType::SubMenu:
 
670
    link_type = "sub menu";
 
671
    break;
 
672
  }
 
673
 
 
674
  for( auto const& action : m_action_paths )
 
675
  {
 
676
    action_paths += action.path() + ";";
 
677
  }
 
678
 
 
679
  uint sender_pid = QDBusConnection::sessionBus().interface()->servicePid(
 
680
            m_bus_name);
 
681
  if( sender_pid == 0 ) {
 
682
      qWarning() << "Failed to read PID, cannot report error";
 
683
      return;
 
684
  }
 
685
 
 
686
  QProcess recoverable;
 
687
  recoverable.setProcessChannelMode(QProcess::ForwardedChannels);
 
688
  recoverable.start("/usr/share/apport/recoverable_problem",
 
689
              QStringList() << "-p" << QString::number(sender_pid));
 
690
  if (recoverable.waitForStarted())
 
691
  {
 
692
    write_pair(recoverable, "DuplicateSignature", "GMenuModelItemsChangedInvalidIndex");
 
693
    write_pair(recoverable, "BusName", m_bus_name);
 
694
    write_pair(recoverable, "Position", QString::number(index));
 
695
    write_pair(recoverable, "Added", QString::number(added));
 
696
    write_pair(recoverable, "Removed", QString::number(removed));
 
697
    write_pair(recoverable, "ItemCount", QString::number(gmenu_item_count));
 
698
    write_pair(recoverable, "ActionNames", gmenu_action_names);
 
699
 
 
700
    if ( m_parent )
 
701
    {
 
702
      write_pair(recoverable, "ParentMenuLabel", parent_menu_label);
 
703
      write_pair(recoverable, "ParentMenuName", parent_menu_name);
 
704
      write_pair(recoverable, "ParentActionNames", parent_action_names);
 
705
      write_pair(recoverable, "ParentLinkType", parent_link_type);
 
706
    }
 
707
 
 
708
    write_pair(recoverable, "MenuLabel", menu_label);
 
709
    write_pair(recoverable, "MenuName", menu_name);
 
710
    write_pair(recoverable, "ActionNames", action_names);
 
711
    write_pair(recoverable, "LinkType", link_type);
 
712
 
 
713
    write_pair(recoverable, "MenuPath", m_menu_path);
 
714
    write_pair(recoverable, "ActionPaths", action_paths, true);
 
715
 
 
716
    recoverable.closeWriteChannel();
 
717
    recoverable.waitForFinished();
 
718
 
 
719
    m_error_reported = true;
 
720
  }
 
721
  else
 
722
  {
 
723
    qWarning() << "Failed to report recoverable error";
 
724
  }
 
725
 
 
726
  emit MenuInvalid();
510
727
}