~ubuntu-branches/ubuntu/quantal/mysql-workbench/quantal

« back to all changes in this revision

Viewing changes to frontend/linux/linux_utilities/listmodel_wrapper.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2012-03-01 21:57:30 UTC
  • Revision ID: package-import@ubuntu.com-20120301215730-o7y8av8y38n162ro
Tags: upstream-5.2.38+dfsg
ImportĀ upstreamĀ versionĀ 5.2.38+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "listmodel_wrapper.h"
 
2
#include "gtk_helpers.h"
 
3
#include <gtkmm/cellrenderercombo.h>
 
4
#include <gtkmm/icontheme.h>
 
5
#include "custom_renderers.h"
 
6
#include "grt/common.h"
 
7
 
 
8
//#define DEBUG
 
9
#undef DEBUG
 
10
 
 
11
#ifdef DEBUG
 
12
#define lmwdprint(...) fprintf(stderr, __VA_ARGS__)
 
13
#else
 
14
#define lmwdprint(...)
 
15
#endif
 
16
 
 
17
 
 
18
static void process_menu_actions(const std::string &command
 
19
                                , bec::ListModel* model
 
20
                                , const std::vector<bec::NodeId>& nodes
 
21
                                , const sigc::slot<void, const std::string&, const std::vector<bec::NodeId>&> fe_menu_handler
 
22
                                )
 
23
{
 
24
  if (!model->activate_popup_item_for_nodes(command, nodes) && !fe_menu_handler.empty())
 
25
    fe_menu_handler(command, nodes);
 
26
}
 
27
 
 
28
//------------------------------------------------------------------------------
 
29
static void run_menu_and_forward_action(const bec::MenuItemList& items
 
30
                                        ,const int x
 
31
                                        ,const int y
 
32
                                        ,const int time
 
33
                                        ,bec::ListModel* model
 
34
                                        ,const std::vector<bec::NodeId>& nodes
 
35
                                        ,const sigc::slot<void, const std::string&, const std::vector<bec::NodeId>&> fe_menu_handler
 
36
                                        ,Gtk::Menu *menu)
 
37
{
 
38
  if (items.size() > 0)
 
39
  {
 
40
    run_popup_menu(items
 
41
                   ,time
 
42
                   ,sigc::bind(sigc::ptr_fun(process_menu_actions), model, nodes, fe_menu_handler)
 
43
                   ,menu);
 
44
  }
 
45
}
 
46
 
 
47
 
 
48
 
 
49
Index::ExternalMap Index::_ext_map;
 
50
 
 
51
//------------------------------------------------------------------------------
 
52
Index::Index(GtkTreeIter* it, const bec::NodeId& node)
 
53
      : _raw_data((char *)it)
 
54
      , _ext(0)
 
55
{
 
56
  //memset(_raw_data, 0xff, sizeof(*it));
 
57
  //*_raw_data = 0;
 
58
  reset_iter(it);
 
59
 
 
60
  const int depth = node.depth();
 
61
 
 
62
  const Mode m = (depth < MaxDepth) ? (depth == 1 ? ListNode : Internal) : External;
 
63
  mode(m);
 
64
 
 
65
  if (m == External)
 
66
  {
 
67
    const std::string nrepr = node.repr();
 
68
    std::pair<ExternalMap::iterator, bool> res = _ext_map.insert(nrepr);
 
69
    _ext = const_cast<std::string*>(&(*(res.first)));
 
70
    it->user_data = (void*)_ext;
 
71
  }
 
72
  else if (m == Internal)
 
73
  {
 
74
    for (int i = 0; i < depth; ++i)
 
75
      word(i, node[i]);
 
76
  }
 
77
  else if (m == ListNode)
 
78
  {
 
79
    it->user_data = (void*)(node[0]);
 
80
  }
 
81
}
 
82
 
 
83
//------------------------------------------------------------------------------
 
84
Index::Index(const GtkTreeIter* it)
 
85
      : _raw_data((char *)it)
 
86
      , _ext(0)
 
87
{
 
88
  if (mode() == External)
 
89
    _ext = reinterpret_cast<std::string*>(((GtkTreeIter*)_raw_data)->user_data);
 
90
}
 
91
 
 
92
//------------------------------------------------------------------------------
 
93
void Index::stamp(const int st)
 
94
{
 
95
  ((Info*)_raw_data)->stamp = st % StampMax;
 
96
}
 
97
 
 
98
//------------------------------------------------------------------------------
 
99
int Index::stamp() const
 
100
{
 
101
  return ((Info*)_raw_data)->stamp;
 
102
}
 
103
 
 
104
//------------------------------------------------------------------------------
 
105
bool Index::cmp_stamp(const int st) const
 
106
{
 
107
  return ((Info*)_raw_data)->stamp == (st % StampMax);
 
108
}
 
109
 
 
110
//------------------------------------------------------------------------------
 
111
int Index::word(const int w) const
 
112
{
 
113
  int ret = 0;
 
114
 
 
115
  if (mode() == Internal)
 
116
  {
 
117
    char* dest = (char*)&ret;
 
118
    const int start_byte = (w * K) + 1;
 
119
 
 
120
    memcpy(dest, _raw_data + start_byte, K);
 
121
  }
 
122
 
 
123
  return ret;
 
124
}
 
125
 
 
126
//------------------------------------------------------------------------------
 
127
void Index::word(const int w, const int v)
 
128
{
 
129
  if (mode() == Internal)
 
130
  {
 
131
    int start_byte = (w * K) + 1;
 
132
    char* dest = _raw_data + start_byte;
 
133
    char* src = (char*)&v;
 
134
 
 
135
    memcpy(dest, src, K);
 
136
  }
 
137
  else
 
138
  {
 
139
    throw std::logic_error("Can't change external Node ref\n");
 
140
  }
 
141
}
 
142
 
 
143
//------------------------------------------------------------------------------
 
144
bec::NodeId Index::to_node() const
 
145
{
 
146
  bec::NodeId node;
 
147
  if (mode() == Internal)
 
148
  {
 
149
    int v;
 
150
    char* dst = (char*)&v;
 
151
    char* src = _raw_data + 1;
 
152
 
 
153
    for (int i = 0; i < MaxDepth; ++i)
 
154
    {
 
155
      v = MaxValue;
 
156
      memcpy(dst, src, K);
 
157
      src += K;
 
158
      if (v != MaxValue)
 
159
        node.append(v);
 
160
      else
 
161
        break;
 
162
    }
 
163
  }
 
164
  else if (mode() == External)
 
165
  {
 
166
    if (_ext)
 
167
      node = bec::NodeId(*_ext);
 
168
  }
 
169
  else if (mode() == ListNode)
 
170
    node.append((long)(((GtkTreeIter*)_raw_data)->user_data));
 
171
 
 
172
  return node;
 
173
}
 
174
 
 
175
//------------------------------------------------------------------------------
 
176
void Index::reset_iter(GtkTreeIter* it)
 
177
{
 
178
  memset(it, 0xff, sizeof(*it));
 
179
  *((char*)it) = 0;
 
180
}
 
181
 
 
182
 
 
183
 
 
184
//------------------------------------------------------------------------------
 
185
Gtk::TreeModel::Path node2path(const ::bec::NodeId& node)
 
186
{
 
187
  const int depth = node.depth();
 
188
  Gtk::TreeModel::Path path;
 
189
 
 
190
  for ( int i = 0; i < depth; i++ )
 
191
    path.append_index(node[i]);
 
192
 
 
193
  return path;
 
194
}
 
195
 
 
196
//------------------------------------------------------------------------------
 
197
ColumnsModel::~ColumnsModel()
 
198
{
 
199
  reset(true); // true means clean up only self, and do not touch tree view
 
200
}
 
201
 
 
202
//------------------------------------------------------------------------------
 
203
void ColumnsModel::reset(const bool cleanup_only_self)
 
204
{
 
205
  if (!cleanup_only_self)
 
206
    _treeview->remove_all_columns();
 
207
 
 
208
  std::list<Gtk::TreeModelColumnBase*>::iterator         it = _columns.begin();
 
209
  std::list<Gtk::TreeModelColumnBase*>::const_iterator last = _columns.end();
 
210
 
 
211
  for ( ; last != it; ++it )
 
212
    delete *it;
 
213
 
 
214
  _columns.clear();
 
215
}
 
216
 
 
217
//------------------------------------------------------------------------------
 
218
void ColumnsModel::add_bec_index_mapping(const int bec_tm_index)
 
219
{
 
220
  _ui2bec.push_back(bec_tm_index);
 
221
}
 
222
 
 
223
//------------------------------------------------------------------------------
 
224
int ColumnsModel::ui2bec(const int index_of_ui_column) const
 
225
{
 
226
  g_assert((size_t)index_of_ui_column < _ui2bec.size());
 
227
 
 
228
  return _ui2bec[index_of_ui_column];
 
229
}
 
230
 
 
231
//------------------------------------------------------------------------------
 
232
const StringColumn&
 
233
ColumnsModel::set_text_column(const int          bec_tm_idx
 
234
                                ,const bool         editable
 
235
                                ,Gtk::IconView     *iv
 
236
                                )
 
237
{
 
238
  // Create columns
 
239
  // add mapping from ui to bec
 
240
  // add them with add() to the model
 
241
  // add columns to the IconView
 
242
  // check if editable and bind signals
 
243
 
 
244
  Gtk::TreeModelColumn<Glib::ustring> *text = new Gtk::TreeModelColumn<Glib::ustring>;
 
245
  Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > *icon = new Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> >;
 
246
 
 
247
  _columns.push_back(text);
 
248
  _columns.push_back(icon);
 
249
 
 
250
  add_bec_index_mapping(bec_tm_idx);
 
251
  add_bec_index_mapping(bec_tm_idx);
 
252
 
 
253
  add(*text);
 
254
  add(*icon);
 
255
 
 
256
  iv->set_text_column(*text);
 
257
  iv->set_pixbuf_column(*icon);
 
258
 
 
259
  return *text;
 
260
}
 
261
 
 
262
 
 
263
//------------------------------------------------------------------------------
 
264
void ColumnsModel::add_tooltip_column(int bec_tm_idx)
 
265
{
 
266
  Gtk::TreeModelColumn<Glib::ustring> *col = new Gtk::TreeModelColumn<Glib::ustring>;
 
267
  add(*col);
 
268
  add_bec_index_mapping(-bec_tm_idx); // negative means pick description
 
269
 
 
270
  _columns.push_back(col);
 
271
}
 
272
 
 
273
//------------------------------------------------------------------------------
 
274
const IntColumn&
 
275
ColumnsModel::append_int_column(const int bec_tm_idx, const std::string& name, const Editable editable)
 
276
{
 
277
  Gtk::TreeModelColumn<int> *col = new Gtk::TreeModelColumn<int>;
 
278
 
 
279
  add(*col);
 
280
  add_bec_index_mapping(bec_tm_idx);
 
281
 
 
282
  int nr_of_cols;
 
283
  if ( editable == EDITABLE )
 
284
  {
 
285
    nr_of_cols= _treeview->append_column_editable(bec::replace_string(name, "_", "__"), *col);
 
286
 
 
287
    Gtk::CellRendererText *cell = (Gtk::CellRendererText*)(_treeview->get_column_cell_renderer(nr_of_cols - 1));
 
288
    cell->signal_edited().connect(sigc::bind
 
289
                                  (sigc::mem_fun(*_tmw
 
290
                                                ,&ListModelWrapper::after_cell_edit<int>
 
291
                                                )
 
292
                                                , sigc::ref(*col)
 
293
                                  )
 
294
                                 );
 
295
  }
 
296
  else
 
297
    nr_of_cols= _treeview->append_column(bec::replace_string(name, "_", "__"), *col);
 
298
 
 
299
  _treeview->get_column(nr_of_cols-1)->set_resizable(true);
 
300
 
 
301
  _columns.push_back(col);
 
302
 
 
303
  return *col;
 
304
}
 
305
 
 
306
//------------------------------------------------------------------------------
 
307
const DoubleColumn&
 
308
ColumnsModel::append_double_column(const int bec_tm_idx, const std::string& name, const Editable editable)
 
309
{
 
310
  Gtk::TreeModelColumn<double> *col = new Gtk::TreeModelColumn<double>;
 
311
  add_bec_index_mapping(bec_tm_idx);
 
312
  add(*col);
 
313
 
 
314
  _columns.push_back(col);
 
315
 
 
316
  return *col;
 
317
}
 
318
 
 
319
//------------------------------------------------------------------------------
 
320
const StringColumn&
 
321
ColumnsModel::append_string_column(const int bec_tm_idx, const std::string& name, const Editable editable, const Iconic have_icon)
 
322
{
 
323
  Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > *icon= 0;
 
324
 
 
325
  Gtk::TreeViewColumn *column= Gtk::manage(new Gtk::TreeViewColumn(bec::replace_string(name, "_", "__")));
 
326
 
 
327
  if ( have_icon == WITH_ICON )
 
328
  {
 
329
    icon = new Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> >;
 
330
    add(*icon);
 
331
    add_bec_index_mapping(bec_tm_idx);
 
332
    column->pack_start(*icon, false);
 
333
 
 
334
    _columns.push_back(icon);
 
335
  }
 
336
 
 
337
  Gtk::TreeModelColumn<Glib::ustring> *col = new Gtk::TreeModelColumn<Glib::ustring>;
 
338
  add(*col);
 
339
  add_bec_index_mapping(bec_tm_idx);
 
340
  column->pack_start(*col);
 
341
 
 
342
  _columns.push_back(col);
 
343
 
 
344
  int nr_of_cols= _treeview->append_column(*column);
 
345
  _treeview->get_column(nr_of_cols-1)->set_resizable(true);
 
346
 
 
347
  if (editable == EDITABLE)
 
348
  {
 
349
    std::vector<Gtk::CellRenderer*> rends= column->get_cell_renderers();
 
350
 
 
351
    Gtk::CellRendererText *cell = (Gtk::CellRendererText*)rends[icon ? 1 : 0];
 
352
    cell->property_editable()= true;
 
353
    cell->signal_edited().connect(sigc::bind
 
354
                                  (sigc::mem_fun(*_tmw
 
355
                                                ,&ListModelWrapper::after_cell_edit<Glib::ustring>
 
356
                                                )
 
357
                                                , sigc::ref(*col)
 
358
                                  )
 
359
                                 );
 
360
  }
 
361
 
 
362
  return *col;
 
363
}
 
364
 
 
365
//------------------------------------------------------------------------------
 
366
const StringColumn&
 
367
ColumnsModel::append_markup_column(const int bec_tm_idx, const std::string& name, const Iconic have_icon)
 
368
{
 
369
  Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > *icon= 0;
 
370
 
 
371
  Gtk::TreeViewColumn *column= Gtk::manage(new Gtk::TreeViewColumn(bec::replace_string(name, "_", "__")));
 
372
 
 
373
  if ( have_icon == WITH_ICON )
 
374
  {
 
375
    icon = new Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> >;
 
376
    add(*icon);
 
377
    add_bec_index_mapping(bec_tm_idx);
 
378
    column->pack_start(*icon, false);
 
379
 
 
380
    _columns.push_back(icon);
 
381
  }
 
382
 
 
383
  Gtk::TreeModelColumn<Glib::ustring> *col = new Gtk::TreeModelColumn<Glib::ustring>;
 
384
  Gtk::CellRendererText *cell = Gtk::manage(new Gtk::CellRendererText());
 
385
  add(*col);
 
386
  add_bec_index_mapping(bec_tm_idx);
 
387
  column->pack_start(*cell);
 
388
  column->add_attribute(cell->property_markup(), *col);
 
389
 
 
390
  _columns.push_back(col);
 
391
 
 
392
  int nr_of_cols= _treeview->append_column(*column);
 
393
  _treeview->get_column(nr_of_cols-1)->set_resizable(true);
 
394
 
 
395
  return *col;
 
396
}
 
397
 
 
398
 
 
399
//------------------------------------------------------------------------------
 
400
const StringColumn&
 
401
ColumnsModel::append_combo_column(const int bec_tm_idx
 
402
                                     ,const std::string            &name
 
403
                                     ,Glib::RefPtr<Gtk::ListStore>  list_w
 
404
                                     ,const Editable                editable
 
405
                                     ,bool popup_only)
 
406
{
 
407
  Gtk::TreeModelColumn<Glib::ustring> *choosen = new Gtk::TreeModelColumn<Glib::ustring>;
 
408
  _columns.push_back(choosen);
 
409
  add(*choosen);
 
410
  add_bec_index_mapping(bec_tm_idx);
 
411
 
 
412
  Gtk::TreeView::Column   *col = Gtk::manage(new Gtk::TreeViewColumn(bec::replace_string(name, "_", "__")));
 
413
  Gtk::CellRendererCombo *cell = Gtk::manage(new Gtk::CellRendererCombo);
 
414
  col->pack_start(*cell);
 
415
 
 
416
  col->add_attribute(cell->property_text(), *choosen);
 
417
  cell->property_model() = list_w;
 
418
  cell->property_text_column() = 0;
 
419
  cell->property_editable() = editable;
 
420
  cell->property_has_entry() = !popup_only;
 
421
  
 
422
  Gtk::TreeModelColumn<Glib::RefPtr<Gtk::TreeModel> > *model_col = new Gtk::TreeModelColumn<Glib::RefPtr<Gtk::TreeModel> >();
 
423
  add_bec_index_mapping(bec_tm_idx);
 
424
  add(*model_col);
 
425
  const int nr_of_cols = _treeview->append_column(*col);
 
426
 
 
427
  _columns.push_back(model_col);
 
428
 
 
429
  _treeview->get_column(nr_of_cols-1)->set_resizable(true);
 
430
 
 
431
  if ( editable == EDITABLE )
 
432
  {
 
433
    Gtk::CellRendererText *cell = (Gtk::CellRendererText*)(_treeview->get_column_cell_renderer(nr_of_cols - 1));
 
434
    cell->signal_edited().connect(sigc::bind
 
435
                                    (sigc::mem_fun(*_tmw
 
436
                                                  ,&ListModelWrapper::after_cell_edit<Glib::ustring>
 
437
                                                  )
 
438
                                                  , sigc::ref(*choosen)
 
439
                                   )
 
440
                                 );
 
441
  }
 
442
 
 
443
  return *choosen;
 
444
}
 
445
 
 
446
//------------------------------------------------------------------------------
 
447
int
 
448
ColumnsModel::append_check_column(const int bec_tm_idx
 
449
                                 ,const std::string         &name
 
450
                                 ,const Editable             editable
 
451
                                 ,const ToggleAction         action
 
452
                                 )
 
453
{
 
454
  Gtk::TreeModelColumn<bool> *col = new Gtk::TreeModelColumn<bool>;
 
455
  _columns.push_back(col);
 
456
  add(*col);
 
457
  add_bec_index_mapping(bec_tm_idx);
 
458
 
 
459
  int nr_of_cols;
 
460
  // If we have bec_tm_idx set to negative value it means that column added is not
 
461
  // directly mapped to a model. Handling of values set/get are done through
 
462
  // ListModelWrapper::_fake_column_value_getter/setter slot
 
463
  if ( editable == EDITABLE  )
 
464
  {
 
465
    nr_of_cols= _treeview->append_column_editable(bec::replace_string(name, "_", "__"), *col);
 
466
 
 
467
    Gtk::CellRendererToggle *cell = (Gtk::CellRendererToggle*)(_treeview->get_column_cell_renderer(nr_of_cols - 1));
 
468
    cell->property_activatable() = true;
 
469
    if ( action == TOGGLE_BY_WRAPPER /* && bec_tm_idx >= 0 */)
 
470
    {
 
471
      cell->signal_toggled().connect(sigc::bind
 
472
                                    (sigc::mem_fun(*_tmw
 
473
                                                  ,&ListModelWrapper::after_cell_toggle/*<bool>*/
 
474
                                                  )
 
475
                                                  , sigc::ref(*col)
 
476
                                    )
 
477
                                    );
 
478
    }
 
479
  }
 
480
  else
 
481
    nr_of_cols= _treeview->append_column(bec::replace_string(name, "_", "__"), *col);
 
482
 
 
483
  _treeview->get_column(nr_of_cols-1)->set_resizable(true);
 
484
 
 
485
  return nr_of_cols;
 
486
}
 
487
 
 
488
//------------------------------------------------------------------------------
 
489
 
 
490
int ColumnsModel::add_generic_column(const int bec_tm_idx, Gtk::TreeModelColumnBase *column,
 
491
                                     Gtk::TreeViewColumn *vcolumn)
 
492
{
 
493
  add(*column);
 
494
  add_bec_index_mapping(bec_tm_idx);
 
495
 
 
496
  return _treeview->append_column(*vcolumn);
 
497
}
 
498
 
 
499
//------------------------------------------------------------------------------
 
500
void ColumnsModel::add_model_column(Gtk::TreeModelColumnBase *col, int bec_tm_idx)
 
501
{
 
502
  add(*col);
 
503
  add_bec_index_mapping(bec_tm_idx);
 
504
  _columns.push_back(col);
 
505
}
 
506
 
 
507
//------------------------------------------------------------------------------
 
508
//------------------------------------------------------------------------------
 
509
ListModelWrapper::ListModelWrapper(bec::ListModel* tm, Gtk::TreeView *treeview, const std::string& name)
 
510
                    : Glib::ObjectBase(typeid(ListModelWrapper))
 
511
                    , Glib::Object()
 
512
                    , Gtk::TreeModel()
 
513
                    , _tm(tm)
 
514
                    , _treeview(treeview)
 
515
                    , _iconview(0)
 
516
                    , _context_menu(0)
 
517
                    , _stamp(1)
 
518
                    , _columns(this, treeview)
 
519
                    , _icon_size(bec::Icon16)
 
520
                    , _self_ref(new ListModelWrapper*(this))
 
521
                    , _name(name)
 
522
{
 
523
  scoped_connect(tm->tree_changed_signal(), boost::bind(&::ListModelWrapper::model_changed, this, _1, _2));
 
524
  tm->add_destroy_notify_callback(_self_ref, &ListModelWrapper::on_bec_model_destroyed);
 
525
  #ifndef NO_MENU_MANAGER
 
526
  if (_treeview)
 
527
    _treeview->signal_event().connect(sigc::mem_fun(this, &ListModelWrapper::handle_popup_event));
 
528
  #endif
 
529
}
 
530
 
 
531
//------------------------------------------------------------------------------
 
532
void* ListModelWrapper::on_bec_model_destroyed(void* data)
 
533
{
 
534
  ListModelWrapper** self = (ListModelWrapper**)data;
 
535
  if (self && *self)
 
536
  {
 
537
    (*self)->_tm = 0;
 
538
  }
 
539
  delete self;
 
540
  return 0;
 
541
}
 
542
 
 
543
//------------------------------------------------------------------------------
 
544
ListModelWrapper::~ListModelWrapper()
 
545
{
 
546
  delete _context_menu;
 
547
  if (_tm)
 
548
    _tm->remove_destroy_notify_callback(_self_ref);
 
549
  *_self_ref= 0;
 
550
 
 
551
  _tm= 0;
 
552
}
 
553
 
 
554
//------------------------------------------------------------------------------
 
555
void ListModelWrapper::set_iconview(Gtk::IconView* iv)
 
556
{
 
557
  _iconview = iv;
 
558
  #ifndef NO_MENU_MANAGER
 
559
  if (_iconview)
 
560
    _iconview->signal_event().connect(sigc::mem_fun(this, &ListModelWrapper::handle_popup_event));
 
561
  #endif
 
562
}
 
563
 
 
564
//------------------------------------------------------------------------------
 
565
ListModelWrapper::NodeIdArray ListModelWrapper::get_selection() const
 
566
{
 
567
  NodeIdArray                 nodes;
 
568
  std::vector<Gtk::TreePath>  paths;
 
569
 
 
570
  if (_treeview)
 
571
    paths = _treeview->get_selection()->get_selected_rows();
 
572
  else if (_iconview)
 
573
    paths = _iconview->get_selected_items();
 
574
 
 
575
  const int size = paths.size();
 
576
  nodes.reserve(size);
 
577
  for (int i = 0; i < size; ++i)
 
578
    nodes.push_back(get_node_for_path(paths[i]));
 
579
 
 
580
  return nodes;
 
581
}
 
582
 
 
583
//------------------------------------------------------------------------------
 
584
void ListModelWrapper::set_be_model(bec::ListModel* tm)
 
585
{
 
586
  if (_tm)
 
587
    _tm->remove_destroy_notify_callback(_self_ref);
 
588
  _tm = tm;
 
589
  if (_tm)
 
590
    _tm->add_destroy_notify_callback(_self_ref, &ListModelWrapper::on_bec_model_destroyed);
 
591
}
 
592
 
 
593
#ifndef NO_MENU_MANAGER
 
594
//------------------------------------------------------------------------------
 
595
void ListModelWrapper::handle_popup(const int x, const int y, const int time, GdkEventButton* evb)
 
596
{
 
597
  Gtk::TreeModel::Path   path;
 
598
  Gtk::TreeView::Column *column(0);
 
599
  int                    cell_x(-1);
 
600
  int                    cell_y(-1);
 
601
 
 
602
  ListModelWrapper::NodeIdArray list = get_selection();
 
603
 
 
604
  bool there_is_path_at_pos = false;
 
605
  if (_treeview)
 
606
    there_is_path_at_pos = _treeview->get_path_at_pos(x, y, path, column, cell_x, cell_y);
 
607
  else if (_iconview)
 
608
  {
 
609
    path = _iconview->get_path_at_pos(x, y);
 
610
    there_is_path_at_pos = path.gobj() && !path.empty();
 
611
  }
 
612
 
 
613
  if ( !there_is_path_at_pos )
 
614
    list.clear();
 
615
  else
 
616
  {
 
617
    // Check that @path is on selection, otherwise add @path to selection
 
618
    bec::NodeId node = get_node_for_path(path);
 
619
    // list stores current selection
 
620
    bool path_at_pos_is_in_selection = false;
 
621
    for (int i = list.size() - 1; i >= 0; --i)
 
622
    {
 
623
      if (node == list[i])
 
624
      {
 
625
        path_at_pos_is_in_selection = true;
 
626
        break;
 
627
      }
 
628
    }
 
629
 
 
630
    if (!path_at_pos_is_in_selection)
 
631
    {
 
632
      // Add it, if user holds Ctrl while clicking right mouse btn
 
633
      // Otherwise clear selection, and select only @path
 
634
      const bool clear_selection = evb ? (!(evb->state & GDK_CONTROL_MASK)) : false;
 
635
      if (clear_selection)
 
636
      {
 
637
        if (_treeview)
 
638
          _treeview->get_selection()->unselect_all();
 
639
        if (_iconview)
 
640
          _iconview->unselect_all();
 
641
      }
 
642
 
 
643
      if (_treeview)
 
644
        _treeview->get_selection()->select(path);
 
645
      if (_iconview)
 
646
        _iconview->select_path(path);
 
647
 
 
648
      list = get_selection();
 
649
    }
 
650
 
 
651
    if (!_context_menu)
 
652
      _context_menu = new Gtk::Menu();
 
653
 
 
654
    run_menu_and_forward_action(_tm->get_popup_items_for_nodes(list), x, y, time, _tm, list, _fe_menu_handler, _context_menu);
 
655
  }
 
656
}
 
657
 
 
658
//------------------------------------------------------------------------------
 
659
bool ListModelWrapper::handle_popup_event(GdkEvent* event)
 
660
{
 
661
  bool ret = false;
 
662
  if ( event->type == GDK_BUTTON_PRESS && event->button.button == 3 )
 
663
  {
 
664
    GdkEventButton* evb = (GdkEventButton*)event;
 
665
    handle_popup((int)event->button.x, (int)event->button.y, event->button.time, evb);
 
666
    // Return true to preserve selection. In handle_popup check that popup is requested
 
667
    // on selection.
 
668
    ret = true;
 
669
  }
 
670
  return ret;
 
671
}
 
672
#endif
 
673
 
 
674
//------------------------------------------------------------------------------
 
675
Gtk::TreeModelFlags ListModelWrapper::get_flags_vfunc() const
 
676
{
 
677
  return Gtk::TREE_MODEL_ITERS_PERSIST | Gtk::TREE_MODEL_LIST_ONLY;
 
678
}
 
679
 
 
680
//------------------------------------------------------------------------------
 
681
bec::NodeId ListModelWrapper::get_node_for_path(const Gtk::TreeModel::Path &path) const
 
682
{
 
683
  if (path.empty())
 
684
    return bec::NodeId();
 
685
  return bec::NodeId(path.to_string());
 
686
}
 
687
 
 
688
//------------------------------------------------------------------------------
 
689
bool ListModelWrapper::init_gtktreeiter(GtkTreeIter *it, const bec::NodeId &node) const
 
690
{
 
691
  if ( _tm && it && node.is_valid() )
 
692
  {
 
693
    Index id(it, node);
 
694
    id.stamp(_stamp);
 
695
  }
 
696
  return it && node.is_valid();
 
697
}
 
698
 
 
699
 
 
700
//------------------------------------------------------------------------------
 
701
bec::NodeId ListModelWrapper::node_for_iter(const iterator &iter) const
 
702
{
 
703
  const GtkTreeIter* it = iter.gobj();
 
704
  bec::NodeId  node;
 
705
 
 
706
  if ( it )
 
707
  {
 
708
    const Index id(it);
 
709
    if (id.cmp_stamp(_stamp))
 
710
      node = id.to_node();
 
711
  }
 
712
 
 
713
  return node;
 
714
}
 
715
 
 
716
//------------------------------------------------------------------------------
 
717
void ListModelWrapper::refresh()
 
718
{
 
719
  if (_tm) _tm->refresh();
 
720
  model_changed(bec::NodeId(), -1);
 
721
}
 
722
 
 
723
 
 
724
//------------------------------------------------------------------------------
 
725
void ListModelWrapper::note_row_added()
 
726
{
 
727
  if (_tm)
 
728
  {
 
729
    _tm->refresh();
 
730
    Gtk::TreePath path(_tm->count()-1);
 
731
 
 
732
    row_inserted(path, get_iter(path));
 
733
  }
 
734
}
 
735
 
 
736
//------------------------------------------------------------------------------
 
737
void ListModelWrapper::set_fake_column_value_getter(FakeColumnValueGetter fake_getter)
 
738
{
 
739
  _fake_column_value_getter = fake_getter;
 
740
}
 
741
 
 
742
//------------------------------------------------------------------------------
 
743
void ListModelWrapper::set_fake_column_value_setter(FakeColumnValueSetter fake_setter)
 
744
{
 
745
  _fake_column_value_setter = fake_setter;
 
746
}
 
747
 
 
748
//------------------------------------------------------------------------------
 
749
void ListModelWrapper::reset_iter(iterator& iter) const throw()
 
750
{
 
751
  GtkTreeIter *it = iter.gobj();
 
752
  Index::reset_iter(it);
 
753
}
 
754
 
 
755
//------------------------------------------------------------------------------
 
756
int ListModelWrapper::get_n_columns_vfunc() const
 
757
{
 
758
  return _columns.size();
 
759
}
 
760
 
 
761
//------------------------------------------------------------------------------
 
762
GType ListModelWrapper::get_column_type_vfunc(int index) const
 
763
{
 
764
  return *(_columns.types() + index);
 
765
}
 
766
 
 
767
//------------------------------------------------------------------------------
 
768
bool ListModelWrapper::iter_next_vfunc(const iterator& iter, iterator& iter_next) const
 
769
{
 
770
  bool ret = false;
 
771
  bec::NodeId current_node= node_for_iter(iter);
 
772
 
 
773
  //g_message("LMW::iter_next_vfunc: %s", _name.c_str());
 
774
 
 
775
  // Invalidate iter_next
 
776
  reset_iter(iter_next);
 
777
 
 
778
  if (_tm)
 
779
  {
 
780
    if (current_node.is_valid() && _tm->has_next(current_node))
 
781
    {
 
782
      try
 
783
      {
 
784
        // Obtain parent of the current node to get number of children of the parent node
 
785
        current_node = _tm->get_next(current_node);
 
786
      }
 
787
      catch (...)
 
788
      {
 
789
        current_node= bec::NodeId();
 
790
      }
 
791
      // Check if the resulted nodeid is valid and setup iter_next with values pointing to the nodeid
 
792
      if ( current_node.is_valid() )
 
793
        ret = init_gtktreeiter(iter_next.gobj(), current_node);
 
794
    }
 
795
  }
 
796
  return ret;
 
797
}
 
798
 
 
799
//------------------------------------------------------------------------------
 
800
bool ListModelWrapper::get_iter_vfunc(const Path& path, iterator& iter) const
 
801
{
 
802
  bool ret = false;
 
803
  GtkTreeIter* it = iter.gobj();
 
804
 
 
805
  // Invalidate iter_next
 
806
  reset_iter(iter);
 
807
 
 
808
  if (_tm)
 
809
  {
 
810
    bec::NodeId node(path.to_string());
 
811
 
 
812
    if ( node.is_valid() && node.back() < _tm->count() )
 
813
      ret = init_gtktreeiter(it, node);
 
814
  }
 
815
  return ret;
 
816
}
 
817
 
 
818
//------------------------------------------------------------------------------
 
819
bool ListModelWrapper::iter_children_vfunc(const iterator& parent, iterator& iter) const
 
820
{
 
821
  return false;
 
822
}
 
823
 
 
824
//------------------------------------------------------------------------------
 
825
bool ListModelWrapper::iter_parent_vfunc(const iterator& child, iterator& iter) const
 
826
{
 
827
  return false;
 
828
}
 
829
 
 
830
//------------------------------------------------------------------------------
 
831
bool ListModelWrapper::iter_nth_child_vfunc(const iterator& parent, int n, iterator& iter) const
 
832
{
 
833
  return false;
 
834
}
 
835
 
 
836
//------------------------------------------------------------------------------
 
837
bool ListModelWrapper::iter_nth_root_child_vfunc(int n, iterator& iter) const
 
838
{
 
839
  bool ret = false;
 
840
  //Sets @a iter to be the child of at the root level using the given index.  The first
 
841
  //index is 0.  If @a n is too big, or if there are no children, @a iter is set
 
842
  //to an invalid iterator and false is returned.
 
843
  //See also iter_nth_child_vfunc().
 
844
  if ( _tm && n >= 0 && n < iter_n_root_children_vfunc() )
 
845
  {
 
846
    bec::NodeId node = _tm->get_node(n);
 
847
    init_gtktreeiter(iter.gobj(), node);
 
848
    ret = true;
 
849
  }
 
850
 
 
851
  return ret;
 
852
}
 
853
 
 
854
//------------------------------------------------------------------------------
 
855
bool ListModelWrapper::iter_has_child_vfunc(const iterator& iter) const
 
856
{
 
857
  return iter_n_children_vfunc(iter) != 0;
 
858
}
 
859
 
 
860
//------------------------------------------------------------------------------
 
861
int ListModelWrapper::iter_n_children_vfunc(const iterator& iter) const
 
862
{
 
863
  return 0;
 
864
}
 
865
 
 
866
//------------------------------------------------------------------------------
 
867
int ListModelWrapper::iter_n_root_children_vfunc() const
 
868
{
 
869
  const int ret = _tm ? _tm->count() : 0;
 
870
  return ret;
 
871
}
 
872
 
 
873
//------------------------------------------------------------------------------
 
874
Gtk::TreeModel::Path ListModelWrapper::get_path_vfunc(const iterator& iter) const
 
875
{
 
876
  const bec::NodeId node = node_for_iter(iter);
 
877
  Gtk::TreeModel::Path path;
 
878
 
 
879
  if ( node.is_valid() )
 
880
  {
 
881
    const int node_depth = node.depth();
 
882
 
 
883
    for ( int i = 0; i < node_depth; i++ )
 
884
      path.push_back(node[i]);
 
885
  }
 
886
 
 
887
  return path;
 
888
}
 
889
 
 
890
//------------------------------------------------------------------------------
 
891
void ListModelWrapper::get_icon_value(const iterator& iter, int column, const bec::NodeId &node, Glib::ValueBase& value) const
 
892
{
 
893
  if (!_tm)
 
894
    return;
 
895
 
 
896
  static ImageCache       *pixbufs      =  ImageCache::get_instance();
 
897
  static Glib::RefPtr<Gtk::IconTheme> icon_theme= Gtk::IconTheme::get_default();
 
898
  GValue *gval = value.gobj();
 
899
 
 
900
  bec::IconId               icon_id = _tm->get_field_icon(node, column, get_icon_size());
 
901
 
 
902
  g_value_init(gval, GDK_TYPE_PIXBUF);
 
903
  if (icon_id != 0)
 
904
  {
 
905
    Glib::RefPtr<Gdk::Pixbuf>  pixbuf = pixbufs->image(icon_id);
 
906
 
 
907
    if ( pixbuf )
 
908
    {
 
909
      g_value_set_object(gval, pixbuf->gobj());
 
910
    }
 
911
  }
 
912
}
 
913
 
 
914
//------------------------------------------------------------------------------
 
915
void ListModelWrapper::get_value_vfunc(const iterator& iter, int column, Glib::ValueBase& value) const
 
916
{
 
917
  if (!_tm)
 
918
    return;
 
919
 
 
920
  bec::NodeId node= node_for_iter(iter);
 
921
 
 
922
  if ( node.is_valid() )
 
923
  {
 
924
    const GType type = *(_columns.types() + column);
 
925
 
 
926
    column = _columns.ui2bec(column);
 
927
 
 
928
    if ( column < 0 )
 
929
    {
 
930
      if ( !_fake_column_value_getter.empty() )
 
931
        _fake_column_value_getter(iter, column, type, value);
 
932
    }
 
933
    else if ( type == GDK_TYPE_PIXBUF )
 
934
    {
 
935
      get_icon_value(iter, column, node, value);
 
936
    }
 
937
    else
 
938
    {
 
939
      switch ( type )
 
940
      {
 
941
      case G_TYPE_BOOLEAN:
 
942
        {
 
943
          bool bv = false;
 
944
          _tm->get_field(node, column, bv);
 
945
          set_glib_bool(value, bv);
 
946
          lmwdprint("LMW::get_value_vfunc: %s: node %s, col %i: value: %i\n", _name.c_str(), node.repr().c_str(), column, bv);
 
947
          break;
 
948
        }
 
949
      case G_TYPE_INT:
 
950
      case G_TYPE_UINT:
 
951
        {
 
952
          int iv = 0;
 
953
          _tm->get_field(node, column, iv);
 
954
          set_glib_int(value, iv);
 
955
          lmwdprint("LMW::get_value_vfunc: %s: node %s, col %i: value: %i\n", _name.c_str(), node.repr().c_str(), column, iv);
 
956
          break;
 
957
        }
 
958
      case G_TYPE_LONG:
 
959
      case G_TYPE_ULONG:
 
960
      case G_TYPE_INT64:
 
961
      case G_TYPE_UINT64:
 
962
        {
 
963
          throw std::logic_error("Imlement long ints in get_value_func");
 
964
          break;
 
965
        }
 
966
      case G_TYPE_FLOAT:
 
967
      case G_TYPE_DOUBLE:
 
968
        {
 
969
          double dv = 0.0;
 
970
          _tm->get_field(node, column, dv);
 
971
          set_glib_double(value, dv);
 
972
          lmwdprint("LMW::get_value_vfunc: %s: node %s, col %i: value: %f\n", _name.c_str(), node.repr().c_str(), column, dv);
 
973
          break;
 
974
        }
 
975
      case G_TYPE_STRING:
 
976
        {
 
977
          std::string sv;
 
978
          if (column < 0)
 
979
            sv= _tm->get_field_description(node, -column);
 
980
          else
 
981
            _tm->get_field_repr(node, column, sv);
 
982
          set_glib_string(value, sv, true);
 
983
          lmwdprint("LMW::get_value_vfunc: %s: node %s, col %i: value: '%s'\n", _name.c_str(), node.repr().c_str(), column, sv.c_str());
 
984
          break;
 
985
        }
 
986
      default:
 
987
        set_glib_string(value, "<unkn>");
 
988
        break;
 
989
      }
 
990
    }
 
991
  }
 
992
}
 
993
 
 
994
//------------------------------------------------------------------------------
 
995
bool ListModelWrapper::iter_is_valid(const iterator& iter) const
 
996
{
 
997
  bec::NodeId node(node_for_iter(iter));
 
998
 
 
999
  return node.is_valid();
 
1000
}
 
1001
 
 
1002
//------------------------------------------------------------------------------
 
1003
void ListModelWrapper::set_value_impl(const iterator& row, int column, const Glib::ValueBase& value)
 
1004
{
 
1005
  if (!_tm)
 
1006
    return;
 
1007
 
 
1008
  bec::NodeId node(node_for_iter(row));
 
1009
 
 
1010
  if ( node.is_valid() )
 
1011
  {
 
1012
    const GType type = *(_columns.types() + column);
 
1013
    column = _columns.ui2bec(column);
 
1014
 
 
1015
    if ( column < 0 )
 
1016
    {
 
1017
      if ( !_fake_column_value_setter.empty() )
 
1018
        _fake_column_value_setter(row, column, type, value);
 
1019
    }
 
1020
    else
 
1021
    {
 
1022
      switch ( type )
 
1023
      {
 
1024
      case G_TYPE_BOOLEAN:
 
1025
        {
 
1026
          Glib::Value<bool>   v;
 
1027
          v.init(value.gobj());
 
1028
          lmwdprint("LMW::set_value_impl:%s node %s, column %i, value %i\n", _name.c_str(), node.repr().c_str(), column, v.get());
 
1029
          _tm->set_field(node, column, v.get());
 
1030
          break;
 
1031
        }
 
1032
      case G_TYPE_INT:
 
1033
      case G_TYPE_UINT:
 
1034
        {
 
1035
          Glib::Value<int>   v;
 
1036
          v.init(value.gobj());
 
1037
          lmwdprint("LMW::set_value_impl: node %s, column %i, value %i\n", node.repr().c_str(), column, v.get());
 
1038
          _tm->set_field(node, column, v.get());
 
1039
          break;
 
1040
        }
 
1041
      case G_TYPE_FLOAT:
 
1042
      case G_TYPE_DOUBLE:
 
1043
        {
 
1044
          Glib::Value<double>  v;
 
1045
          v.init(value.gobj());
 
1046
          _tm->set_field(node, column, v.get());
 
1047
          break;
 
1048
        }
 
1049
      case G_TYPE_STRING:
 
1050
        {
 
1051
          Glib::Value<std::string>   v;
 
1052
          v.init(value.gobj());
 
1053
          _tm->set_field(node, column, v.get());
 
1054
          lmwdprint("LMW::set_value: %s '%s'\n", _name.c_str(), v.get().c_str());
 
1055
          break;
 
1056
        }
 
1057
      default:
 
1058
        break;
 
1059
      }
 
1060
    }
 
1061
  }
 
1062
}
 
1063
 
 
1064
//------------------------------------------------------------------------------
 
1065
void ListModelWrapper::get_value_impl(const iterator& row, int column, Glib::ValueBase& value) const
 
1066
{
 
1067
  get_value_vfunc(row, column, value);
 
1068
}
 
1069
 
 
1070
//------------------------------------------------------------------------------
 
1071
void ListModelWrapper::set_row_draggable_slot(const sigc::slot<bool, Gtk::TreeModel::Path> &slot)
 
1072
{
 
1073
  _row_draggable= slot;
 
1074
}
 
1075
 
 
1076
//------------------------------------------------------------------------------
 
1077
bool ListModelWrapper::drag_data_get_vfunc(const Gtk::TreeModel::Path& path, Gtk::SelectionData& selection_data) const
 
1078
{
 
1079
  selection_data.set("text/path", path.to_string());
 
1080
  return true;
 
1081
}
 
1082
 
 
1083
//------------------------------------------------------------------------------
 
1084
bool ListModelWrapper::drag_data_delete_vfunc (const Gtk::TreeModel::Path& path)
 
1085
{
 
1086
  return true;
 
1087
}
 
1088
 
 
1089
//------------------------------------------------------------------------------
 
1090
bool ListModelWrapper::row_draggable_vfunc(const TreeModel::Path &path) const
 
1091
{
 
1092
  if (_row_draggable)
 
1093
    return _row_draggable(path);
 
1094
 
 
1095
  return true;
 
1096
}
 
1097
 
 
1098
//------------------------------------------------------------------------------
 
1099
bool ListModelWrapper::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& selection_data) const
 
1100
{
 
1101
  return true;
 
1102
}
 
1103
 
 
1104
//------------------------------------------------------------------------------
 
1105
bool ListModelWrapper::drag_data_received_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& selection_data)
 
1106
{
 
1107
  bool ret = false;
 
1108
  // Currently this works for linear lists
 
1109
  try
 
1110
  {
 
1111
    _tm->reorder(bec::NodeId((const char*)selection_data.get_data()), dest.front());
 
1112
    ret = true;
 
1113
  }
 
1114
  catch (const std::logic_error& e)
 
1115
  {}
 
1116
  return ret;
 
1117
}