~indicator-applet-developers/hud/trunk.14.04

« back to all changes in this revision

Viewing changes to libqtgmenu/internal/QtGMenuModel.cpp

  • Committer: CI bot
  • Author(s): Pete Woods, Marcus Tomlinson
  • Date: 2014-06-04 14:04:03 UTC
  • mfrom: (390.1.44 trunk)
  • Revision ID: ps-jenkins@lists.canonical.com-20140604140403-a70c33snru5b6k4x
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. Fixes: 1298656, 1316473, 1322050, 1325538

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
    for( auto& action : action_it->second )
 
177
    {
 
178
      action->setEnabled( enabled );
 
179
    }
182
180
  }
183
181
}
184
182
 
187
185
  auto action_it = m_actions.find( action_name );
188
186
  if( action_it != end( m_actions ) )
189
187
  {
190
 
    action_it->second->setProperty( c_property_isParameterized, parameterized );
 
188
    for( auto& action : action_it->second )
 
189
    {
 
190
      action->setProperty( c_property_isParameterized, parameterized );
 
191
    }
191
192
  }
192
193
}
193
194
 
194
 
QtGMenuModel* QtGMenuModel::CreateChild( QtGMenuModel* parent, GMenuModel* model, int index )
 
195
QSharedPointer<QtGMenuModel> QtGMenuModel::CreateChild( QtGMenuModel* parent_qtgmenu, QSharedPointer<GMenuModel> parent_gmenu, int child_index )
195
196
{
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;
 
197
  QSharedPointer<QtGMenuModel> new_child;
 
198
 
 
199
  GMenuLinkIter* link_it = g_menu_model_iterate_item_links( parent_gmenu.data(), child_index );
 
200
 
 
201
  // get the first link, if it exists, create the child accordingly
 
202
  if( link_it && g_menu_link_iter_next( link_it ) )
 
203
  {
 
204
    // if link is a sub menu
 
205
    if( strcmp( g_menu_link_iter_get_name( link_it ), G_MENU_LINK_SUBMENU ) == 0 )
 
206
    {
 
207
      new_child.reset(
 
208
                new QtGMenuModel(
 
209
                        QSharedPointer<GMenuModel>(
 
210
                                g_menu_link_iter_get_value(link_it),
 
211
                                &g_object_unref), LinkType::SubMenu,
 
212
                        parent_qtgmenu, child_index));
 
213
    }
 
214
    // else if link is a section
 
215
    else if( strcmp( g_menu_link_iter_get_name( link_it ), G_MENU_LINK_SECTION ) == 0 )
 
216
    {
 
217
      new_child.reset(
 
218
                    new QtGMenuModel(
 
219
                            QSharedPointer<GMenuModel>(
 
220
                                    g_menu_link_iter_get_value(link_it),
 
221
                                    &g_object_unref), LinkType::Section,
 
222
                            parent_qtgmenu, child_index));
 
223
    }
 
224
  }
 
225
 
 
226
  g_object_unref( link_it );
 
227
  return new_child;
211
228
}
212
229
 
213
230
void QtGMenuModel::MenuItemsChangedCallback( GMenuModel* model, gint index, gint removed,
214
231
    gint added, gpointer user_data )
215
232
{
216
233
  QtGMenuModel* self = reinterpret_cast< QtGMenuModel* >( user_data );
 
234
 
 
235
  if( self->m_model != model )
 
236
  {
 
237
    qWarning() << "\"items-changed\" signal received from an unrecognised menu model";
 
238
    return;
 
239
  }
 
240
 
217
241
  self->ChangeMenuItems( index, added, removed );
218
242
}
219
243
 
220
 
void QtGMenuModel::ChangeMenuItems( int index, int added, int removed )
 
244
void QtGMenuModel::ChangeMenuItems( const int index, const int added, const int removed )
221
245
{
 
246
  const int n_items = g_menu_model_get_n_items( m_model.data() );
 
247
 
 
248
  if( index < 0 || added < 0 || removed < 0 || index + added > n_items || index + removed > m_size )
 
249
  {
 
250
    ReportRecoverableError(index, added, removed);
 
251
    return;
 
252
  }
 
253
 
 
254
  // process removed items first (see "items-changed" on the GMenuModel man page)
222
255
  if( removed > 0 )
223
256
  {
 
257
    // remove QAction from 'index' of our QMenu, 'removed' times
224
258
    for( int i = 0; i < removed; ++i )
225
259
    {
226
260
      if( index < m_menu->actions().size() )
227
261
      {
228
262
        QAction* at_action = m_menu->actions().at( index );
229
 
        ActionRemoved( at_action->property( c_property_actionName ).toString() );
 
263
        ActionRemoved( at_action->property( c_property_actionName ).toString(), at_action );
230
264
        m_menu->removeAction( at_action );
231
265
      }
232
266
    }
233
267
 
 
268
    // update m_children
234
269
    for( int i = index; i < m_size; ++i )
235
270
    {
236
 
      if( i <= ( index + removed ) )
 
271
      // remove children from index until ( index + removed )
 
272
      if( i < ( index + removed ) )
237
273
      {
238
 
        delete m_children.take( i );
 
274
        m_children.take( i );
239
275
      }
 
276
      // shift children from ( index + removed ) to m_size into the now empty positions
240
277
      else if( m_children.contains( i ) )
241
278
      {
242
279
        m_children.insert( i - removed, m_children.take( i ) );
243
280
      }
244
281
    }
245
282
 
 
283
    // update m_size
246
284
    m_size -= removed;
247
285
  }
248
286
 
 
287
  // now process added items
249
288
  if( added > 0 )
250
289
  {
251
 
    // shift items up
252
 
    for( int i = ( m_size + added ) - 1; i >= index; --i )
 
290
    // update m_children (start from the end and work backwards as not to overlap items as we shift them up)
 
291
    for( int i = m_size - 1; i >= index; --i )
253
292
    {
 
293
      // shift 'added' items up from their current index to ( index + added )
254
294
      if( m_children.contains( i ) )
255
295
      {
256
296
        m_children.insert( i + added, m_children.take( i ) );
257
297
      }
258
298
    }
259
299
 
 
300
    // update m_size
260
301
    m_size += added;
261
302
 
 
303
    // now add a new QAction to our QMenu for each new item
262
304
    for( int i = index; i < ( index + added ); ++i )
263
305
    {
264
306
      QAction* at_action = nullptr;
267
309
        at_action = m_menu->actions().at( i );
268
310
      }
269
311
 
270
 
      QtGMenuModel* model = CreateChild( this, m_model, i );
 
312
      // try first to create a child model
 
313
      QSharedPointer< QtGMenuModel > model = CreateChild( this, m_model, i );
271
314
 
 
315
      // if this is a menu item and not a model
272
316
      if( !model )
273
317
      {
274
318
        QAction* new_action = CreateAction( i );
275
319
        ActionAdded( new_action->property( c_property_actionName ).toString(), new_action );
276
320
        m_menu->insertAction( at_action, new_action );
277
321
      }
 
322
      // else if this is a section model
278
323
      else if( model->Type() == LinkType::Section )
279
324
      {
 
325
        InsertChild( model, i );
280
326
        m_menu->insertSeparator( at_action );
281
327
      }
 
328
      // else if this is a sub menu model
282
329
      else if( model->Type() == LinkType::SubMenu )
283
330
      {
284
 
        m_menu->insertMenu( at_action, model->m_ext_menu );
 
331
        InsertChild( model, i );
 
332
        ActionAdded( model->m_ext_menu->menuAction()->property( c_property_actionName ).toString(),
 
333
                     model->m_ext_menu->menuAction() );
 
334
        m_menu->insertMenu( at_action, model->m_ext_menu.data() );
285
335
      }
286
336
    }
287
337
  }
288
338
 
289
339
  // update external menu
290
340
  UpdateExtQMenu();
291
 
  if( m_link_type == LinkType::Section && m_parent )
292
 
  {
293
 
    m_parent->UpdateExtQMenu();
294
 
  }
295
341
 
 
342
  // now tell the outside world that items have changed
296
343
  emit MenuItemsChanged( this, index, removed, added );
297
344
}
298
345
 
300
347
{
301
348
  if( m_model && m_items_changed_handler == 0 )
302
349
  {
303
 
    m_items_changed_handler = g_signal_connect( m_model, "items-changed",
 
350
    m_items_changed_handler = g_signal_connect( m_model.data(), "items-changed",
304
351
        G_CALLBACK( MenuItemsChangedCallback ), this );
305
352
  }
306
353
}
309
356
{
310
357
  if( m_model && m_items_changed_handler != 0 )
311
358
  {
312
 
    g_signal_handler_disconnect( m_model, m_items_changed_handler );
 
359
    g_signal_handler_disconnect( m_model.data(), m_items_changed_handler );
313
360
  }
314
361
 
315
362
  m_items_changed_handler = 0;
316
363
}
317
364
 
318
 
void QtGMenuModel::InsertChild( QtGMenuModel* child, int index )
 
365
void QtGMenuModel::InsertChild( QSharedPointer<QtGMenuModel> child, int index )
319
366
{
320
367
  if( m_children.contains( index ) )
321
368
  {
325
372
  child->m_parent = this;
326
373
  m_children.insert( index, child );
327
374
 
328
 
  connect( child, SIGNAL( MenuItemsChanged( QtGMenuModel*, int, int, int ) ), this,
 
375
  connect( child.data(), SIGNAL( MenuItemsChanged( QtGMenuModel*, int, int, int ) ), this,
329
376
      SIGNAL( MenuItemsChanged( QtGMenuModel*, int, int, int ) ) );
330
377
 
331
 
  connect( child, SIGNAL( ActionTriggered( QString, bool ) ), this,
 
378
  connect( child.data(), SIGNAL( ActionTriggered( QString, bool ) ), this,
332
379
      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;
 
380
 
 
381
  connect( child.data(), SIGNAL( MenuInvalid() ), this, SIGNAL( MenuInvalid() ) );
 
382
 
 
383
  // emit signal informing subscribers that this child has added all of its menu items
 
384
  emit MenuItemsChanged( child.data(), 0, 0, child->m_size );
346
385
}
347
386
 
348
387
QAction* QtGMenuModel::CreateAction( int index )
349
388
{
 
389
  QAction* action = new QAction( m_menu.data() );
 
390
 
350
391
  // action label
351
 
  QAction* action = new QAction( this );
352
 
 
353
392
  gchar* label = NULL;
354
 
  if( g_menu_model_get_item_attribute( m_model, index, G_MENU_ATTRIBUTE_LABEL, "s", &label ) ) {
 
393
  if( g_menu_model_get_item_attribute( m_model.data(), index, G_MENU_ATTRIBUTE_LABEL, "s", &label ) ) {
355
394
    QString qlabel = QString::fromUtf8( label );
356
 
    qlabel.replace( '_', '&' );
 
395
    qlabel.replace( SINGLE_UNDERSCORE, "&" );
357
396
    g_free( label );
358
397
 
359
398
    action->setText( qlabel );
361
400
 
362
401
  // action name
363
402
  gchar* action_name = NULL;
364
 
  if( g_menu_model_get_item_attribute( m_model, index,
 
403
  if( g_menu_model_get_item_attribute( m_model.data(), index,
365
404
              G_MENU_ATTRIBUTE_ACTION, "s", &action_name ) )
366
405
  {
367
406
    QString qaction_name = QString::fromUtf8( action_name );
378
417
  action->setProperty( c_property_menuPath, m_menu_path );
379
418
 
380
419
  // action icon
381
 
  GVariant* icon = g_menu_model_get_item_attribute_value( m_model, index, G_MENU_ATTRIBUTE_ICON,
 
420
  GVariant* icon = g_menu_model_get_item_attribute_value( m_model.data(), index, G_MENU_ATTRIBUTE_ICON,
382
421
      G_VARIANT_TYPE_VARIANT );
383
422
 
384
423
  if( icon )
388
427
 
389
428
  // action shortcut
390
429
  gchar* shortcut = NULL;
391
 
  if( g_menu_model_get_item_attribute( m_model, index, "accel", "s", &shortcut ) )
 
430
  if( g_menu_model_get_item_attribute( m_model.data(), index, "accel", "s", &shortcut ) )
392
431
  {
393
432
    QString qshortcut = QString::fromUtf8( shortcut );
394
433
    g_free( shortcut );
398
437
 
399
438
  // action shortcut
400
439
  gchar* toolbar_item = NULL;
401
 
  if( g_menu_model_get_item_attribute( m_model, index, c_property_hud_toolbar_item, "s", &toolbar_item ) )
 
440
  if( g_menu_model_get_item_attribute( m_model.data(), index, c_property_hud_toolbar_item, "s", &toolbar_item ) )
402
441
  {
403
442
    QString qtoolbar_item = QString::fromUtf8( toolbar_item );
404
443
    g_free( toolbar_item );
408
447
 
409
448
  // action keywords
410
449
  gchar* keywords = NULL;
411
 
  if( g_menu_model_get_item_attribute( m_model, index, c_property_keywords, "s", &keywords ) )
 
450
  if( g_menu_model_get_item_attribute( m_model.data(), index, c_property_keywords, "s", &keywords ) )
412
451
  {
413
452
    QVariant qkeywords = QString::fromUtf8( keywords );
414
453
    g_free( keywords );
458
497
 
459
498
    if( action->isSeparator() )
460
499
    {
461
 
      QtGMenuModel* child = Child( i );
 
500
      QSharedPointer<QtGMenuModel> child = Child( i );
462
501
      if( !child || child->Type() != LinkType::Section )
463
502
      {
464
503
        continue;
465
504
      }
466
 
      QMenu* section = child->m_ext_menu;
467
505
 
468
 
      for( QAction* sub_action : section->actions() )
 
506
      for( QAction* sub_action : child->m_ext_menu->actions() )
469
507
      {
470
508
        m_ext_menu->addAction( sub_action );
471
509
      }
485
523
      m_ext_menu->removeAction( last_action );
486
524
    }
487
525
  }
 
526
 
 
527
  // if this is a section within a parent menu, we need to update the parent menu as well
 
528
  if( m_link_type == LinkType::Section && m_parent )
 
529
  {
 
530
    m_parent->UpdateExtQMenu();
 
531
  }
488
532
}
489
533
 
490
534
void QtGMenuModel::ActionAdded( const QString& name, QAction* action )
494
538
  {
495
539
    m_parent->ActionAdded( name, action );
496
540
  }
497
 
 
498
 
  m_actions[name] = action;
 
541
  else
 
542
  {
 
543
    // check if the action name is already in our map
 
544
    if( m_actions.find( name ) != m_actions.end() )
 
545
    {
 
546
      // add the QAction pointer to the list of actions under this name
 
547
      m_actions[name].push_back( action );
 
548
    }
 
549
    else
 
550
    {
 
551
      // otherwise insert the new action into the map
 
552
      m_actions.insert( std::make_pair( name, std::vector< QAction* >{ action } ) );
 
553
    }
 
554
  }
499
555
}
500
556
 
501
 
void QtGMenuModel::ActionRemoved( const QString& name )
 
557
void QtGMenuModel::ActionRemoved( const QString& name, QAction* action )
502
558
{
503
559
  // remove action from top menu's m_actions
504
560
  if( m_parent )
505
561
  {
506
 
    m_parent->ActionRemoved( name );
507
 
  }
508
 
 
509
 
  m_actions.erase( name );
 
562
    m_parent->ActionRemoved( name, action );
 
563
  }
 
564
  else
 
565
  {
 
566
    // check if this action is actually in our map
 
567
    if( m_actions.find( name ) != m_actions.end() )
 
568
    {
 
569
      // remove the QAction pointer from the list of actions under this name
 
570
      auto& actionList = m_actions[name];
 
571
      auto actionIt = std::find( actionList.begin(), actionList.end(), action );
 
572
 
 
573
      if( actionIt != actionList.end())
 
574
      {
 
575
        actionList.erase( actionIt );
 
576
      }
 
577
 
 
578
      // if there are no more references to this action, remove it from the map
 
579
      if( actionList.size() == 0 )
 
580
      {
 
581
        m_actions.erase( name );
 
582
      }
 
583
    }
 
584
  }
 
585
}
 
586
 
 
587
static void write_pair(QIODevice& device, const QString& key, const QString& value, bool last = false)
 
588
{
 
589
  device.write(key.toUtf8());
 
590
  device.write("", 1);
 
591
  device.write(value.toUtf8());
 
592
  if( !last )
 
593
  {
 
594
    device.write("", 1);
 
595
  }
 
596
 
 
597
  if( !value.isEmpty())
 
598
  {
 
599
    qWarning() << key << " =" << value;
 
600
  }
 
601
}
 
602
 
 
603
void QtGMenuModel::ReportRecoverableError(const int index, const int added, const int removed)
 
604
{
 
605
  if( m_error_reported )
 
606
  {
 
607
    return;
 
608
  }
 
609
 
 
610
  // gmenumodel properties
 
611
  int gmenu_item_count = 0;
 
612
  QString gmenu_action_names;
 
613
 
 
614
  gmenu_item_count = g_menu_model_get_n_items( m_model.data() );
 
615
 
 
616
  qWarning() << "Illegal arguments when updating GMenuModel: position ="
 
617
             << index << ", added =" << added << ", removed =" << removed
 
618
             << ", size =" << gmenu_item_count;
 
619
 
 
620
  for( int i = 0; i < gmenu_item_count; ++i )
 
621
  {
 
622
    gchar* action_name = NULL;
 
623
    if( g_menu_model_get_item_attribute( m_model.data(), i,
 
624
          G_MENU_ATTRIBUTE_ACTION, "s", &action_name ) )
 
625
    {
 
626
      gmenu_action_names += action_name;
 
627
      gmenu_action_names += ";";
 
628
      g_free( action_name );
 
629
    }
 
630
  }
 
631
 
 
632
  // parent model properties
 
633
  QString parent_menu_label;
 
634
  QString parent_menu_name;
 
635
  QString parent_action_names;
 
636
  QString parent_link_type;
 
637
 
 
638
  if( m_parent )
 
639
  {
 
640
    parent_menu_label = m_parent->m_menu->menuAction()->text();
 
641
    parent_menu_name = m_parent->m_menu->menuAction()->property( c_property_actionName ).toString();
 
642
 
 
643
    for( QAction* action : m_parent->m_menu->actions() )
 
644
    {
 
645
      parent_action_names += action->property( c_property_actionName ).toString() + ";";
 
646
    }
 
647
 
 
648
    switch( m_parent->m_link_type )
 
649
    {
 
650
    case LinkType::Root:
 
651
      parent_link_type = "root";
 
652
      break;
 
653
    case LinkType::Section:
 
654
      parent_link_type = "section";
 
655
      break;
 
656
    case LinkType::SubMenu:
 
657
      parent_link_type = "sub menu";
 
658
      break;
 
659
    }
 
660
  }
 
661
 
 
662
  // local model properties
 
663
  QString menu_label;
 
664
  QString menu_name;
 
665
  QString action_names;
 
666
  QString link_type;
 
667
  QString action_paths;
 
668
 
 
669
  menu_label = m_menu->menuAction()->text();
 
670
  menu_name = m_menu->menuAction()->property( c_property_actionName ).toString();
 
671
  for( QAction* action : m_menu->actions() )
 
672
  {
 
673
    action_names += action->property( c_property_actionName ).toString() + ";";
 
674
  }
 
675
 
 
676
  switch( m_link_type )
 
677
  {
 
678
  case LinkType::Root:
 
679
    link_type = "root";
 
680
    break;
 
681
  case LinkType::Section:
 
682
    link_type = "section";
 
683
    break;
 
684
  case LinkType::SubMenu:
 
685
    link_type = "sub menu";
 
686
    break;
 
687
  }
 
688
 
 
689
  for( auto const& action : m_action_paths )
 
690
  {
 
691
    action_paths += action.path() + ";";
 
692
  }
 
693
 
 
694
  uint sender_pid = QDBusConnection::sessionBus().interface()->servicePid(
 
695
            m_bus_name);
 
696
  if( sender_pid == 0 ) {
 
697
      qWarning() << "Failed to read PID, cannot report error";
 
698
      return;
 
699
  }
 
700
 
 
701
  QProcess recoverable;
 
702
  recoverable.setProcessChannelMode(QProcess::ForwardedChannels);
 
703
  recoverable.start("/usr/share/apport/recoverable_problem",
 
704
              QStringList() << "-p" << QString::number(sender_pid));
 
705
  if (recoverable.waitForStarted())
 
706
  {
 
707
    write_pair(recoverable, "DuplicateSignature", "GMenuModelItemsChangedInvalidIndex");
 
708
    write_pair(recoverable, "BusName", m_bus_name);
 
709
    write_pair(recoverable, "Position", QString::number(index));
 
710
    write_pair(recoverable, "Added", QString::number(added));
 
711
    write_pair(recoverable, "Removed", QString::number(removed));
 
712
    write_pair(recoverable, "ItemCount", QString::number(gmenu_item_count));
 
713
    write_pair(recoverable, "ActionNames", gmenu_action_names);
 
714
 
 
715
    if ( m_parent )
 
716
    {
 
717
      write_pair(recoverable, "ParentMenuLabel", parent_menu_label);
 
718
      write_pair(recoverable, "ParentMenuName", parent_menu_name);
 
719
      write_pair(recoverable, "ParentActionNames", parent_action_names);
 
720
      write_pair(recoverable, "ParentLinkType", parent_link_type);
 
721
    }
 
722
 
 
723
    write_pair(recoverable, "MenuLabel", menu_label);
 
724
    write_pair(recoverable, "MenuName", menu_name);
 
725
    write_pair(recoverable, "ActionNames", action_names);
 
726
    write_pair(recoverable, "LinkType", link_type);
 
727
 
 
728
    write_pair(recoverable, "MenuPath", m_menu_path);
 
729
    write_pair(recoverable, "ActionPaths", action_paths, true);
 
730
 
 
731
    recoverable.closeWriteChannel();
 
732
    recoverable.waitForFinished();
 
733
 
 
734
    m_error_reported = true;
 
735
  }
 
736
  else
 
737
  {
 
738
    qWarning() << "Failed to report recoverable error";
 
739
  }
 
740
 
 
741
  emit MenuInvalid();
510
742
}