File: treenodeview.h

package info (click to toggle)
mysql-workbench 6.3.8%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 113,932 kB
  • ctags: 87,814
  • sloc: ansic: 955,521; cpp: 427,465; python: 59,728; yacc: 59,129; xml: 54,204; sql: 7,091; objc: 965; makefile: 638; sh: 613; java: 237; perl: 30; ruby: 6; php: 1
file content (477 lines) | stat: -rw-r--r-- 18,879 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
/* 
 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#pragma once

#include <mforms/view.h>
#include <boost/cstdint.hpp>

/**
 * Implementation of a control class for a treeview control based on node objects.
 */

namespace mforms {
  class TreeNodeView;
  class ContextMenu;
  
  /** Determines what type a column should have (mainly describing the column *editor*). */
  enum TreeColumnType
  {
    StringColumnType,      //!< simple string, with text entry editor
    StringLTColumnType,    //!< same as StringColumnType, but truncated at the left end if it doesn't fit
    IntegerColumnType,     //!< numeric field, with text entry editor
    LongIntegerColumnType, //!< 64bit numeric field, with text entry editor
    CheckColumnType,       //!< boolean field, with checkbox
    TriCheckColumnType,    //!< checkbox field (same as CheckColumnType) which also accepts -1 as mixed state
    IconColumnType,        //!< icon field, value is the icon path
    IconStringColumnType = IconColumnType,
    NumberWithUnitColumnType, //!< string type, representing numbers with a unit suffix (like KB, MB, ms etc) 
    FloatColumnType        //!< a double precision floating point number
  };
  
  /** Options used to customize what to show in the tree. */
  enum TreeOptions
  {
    TreeDefault          = 0,
    TreeNoColumns        = 1 << 3, //!< On non-Windows platforms columns are always on, so switch them on
                                   //! on Windows too by default and use this flag to switch them off, if really needed.
                                   //! At least gtk has problems with arbitrary items for a tree. Treeview in gtk is
                                   //! built on View-Source model, where source is a row/column based thing. That may
                                   //! require some hacking to support NoColums in gtk, so really think if that is worth it.
    TreeAllowReorderRows = 1 << 4, //!< Allows row reordering, sets TreeCanBeDragSource implicitly.
    TreeShowColumnLines  = 1 << 5, //!< show column separator lines
    TreeShowRowLines     = 1 << 6, //!< show row separator lines
    TreeNoBorder         = 1 << 7, //!< Switch off the border around the control. Default is to show the border.
    TreeSidebar          = 1 << 8, //!< sidebar style treeview
    TreeNoHeader         = 1 << 9, //!< Don't show a column header. Only meaningful if columns are used.
    TreeShowHeader       = 0,      //!< for backwards compatibility
    TreeFlatList         = 1 << 10, //!< no child items expected
    TreeAltRowColors     = 1 << 11, //!< enable alternating row colors
    TreeSizeSmall        = 1 << 12, //!< small text
    TreeIndexOnTag       = 1 << 13, //!< keep a node index on the tags (use with node_with_tag)

    TreeCanBeDragSource  = 1 << 14, //!< allow the tree to be a drag source, data used depends on actual tree
  };
  
#ifndef SWIG
  inline TreeOptions operator| (TreeOptions a, TreeOptions b)
  {
    return (TreeOptions) ((int) a | (int) b);
  }
#endif

  enum TreeSelectionMode
  {
    TreeSelectSingle, // 0 or 1 item selected
    TreeSelectMultiple // 0+ items selection
  };

  typedef struct TextAttributes TreeNodeTextAttributes;  

  // This struct represents the data comprising a node
  // including a collection of child nodes.
  struct MFORMS_EXPORT TreeNodeSkeleton
  {
  public:
    TreeNodeSkeleton() {};
    TreeNodeSkeleton(const std::string& caption, const std::string& icon, const std::string& tag);
    std::string caption;
    std::string icon;
    std::string tag;
    std::vector<TreeNodeSkeleton> children;
  };

  // This struct represents a collection of nodes sharing tag, icon and structure
  struct MFORMS_EXPORT TreeNodeCollectionSkeleton
  {
  public:
    TreeNodeCollectionSkeleton() {};
    TreeNodeCollectionSkeleton(const std::string& icon);
    std::string icon;
    std::vector<TreeNodeSkeleton> children;
    std::vector<std::string> captions;
  };

  class MFORMS_EXPORT TreeNodeData {
  protected:
    int _refcount;
  public:
    TreeNodeData() : _refcount(0) {}
    virtual ~TreeNodeData() {}
    void retain() { _refcount++; }
    void release() { _refcount--; if (_refcount == 0) delete this; }
  };


  class TreeNode;
  struct MFORMS_EXPORT TreeNodeRef
  {
  private:
    TreeNode *node;

  public:
    // following methods are private, but need to be made public for the platform implementation
#ifndef SWIG
    TreeNodeRef(TreeNode *anode);
    TreeNode *ptr() { return node; }
#endif
  public:
    TreeNodeRef() : node(0) {}
    TreeNodeRef(const TreeNodeRef &other);
    ~TreeNodeRef();
#ifndef SWIG
    TreeNodeRef &operator= (const TreeNodeRef &other);
#endif
    TreeNode *operator->() const;
    TreeNode *operator->();

    operator bool () const { return node !=0; }
    bool operator == (const TreeNodeRef &other) const;
    bool operator != (const TreeNodeRef &other) const;

    bool is_valid();
  };

  class MFORMS_EXPORT TreeNode
  {
    friend struct TreeNodeRef;

  protected:
    virtual void release() = 0;
    virtual void retain() = 0;
  public:
    virtual ~TreeNode() {};
    
    virtual bool equals(const TreeNode &other) = 0;
#ifndef SWIG
    virtual bool is_valid() const = 0;
#endif
    virtual int level() const = 0; // 0 for root, 1 for top level etc.

    virtual void set_icon_path(int column, const std::string &icon) = 0;

    virtual void set_string(int column, const std::string &value) = 0;
    virtual void set_int(int column, int value) = 0;
    virtual void set_long(int column, boost::int64_t value) = 0;
    virtual void set_bool(int column, bool value) = 0;
    virtual void set_float(int column, double value) = 0;

    virtual void set_attributes(int column, const TreeNodeTextAttributes &attrs) = 0;

    virtual std::string get_string(int column) const = 0;
    virtual int get_int(int column) const = 0;
    virtual boost::int64_t get_long(int column) const = 0;
    virtual bool get_bool(int column) const = 0;
    virtual double get_float(int column) const = 0;
    
    virtual int count() const = 0;
    virtual TreeNodeRef add_child() { return insert_child(-1); }
    virtual TreeNodeRef insert_child(int index) = 0;
    virtual void remove_from_parent() = 0;
    virtual void remove_children(); // default impl provided, subclasses may override to provide faster impl
    virtual TreeNodeRef get_child(int index) const = 0;
    virtual int get_child_index(TreeNodeRef child) const = 0;
    virtual TreeNodeRef get_parent() const = 0;
    virtual TreeNodeRef find_child_with_tag(const std::string &tag); // This will search the sub nodes sequentially.
    virtual TreeNodeRef previous_sibling() const = 0;
    virtual TreeNodeRef next_sibling() const = 0;

    // Moves this node to a different place relative to the given node (which must be in the same tree).
    virtual void move_node(TreeNodeRef node, bool before) = 0;

    // This is a very special function and I'm not sure it should be here.
    // It creates nodes out of the collection's captions and adds the same child nodes to each of those nodes
    // as given in the children member. This works iteratively.
    virtual std::vector<mforms::TreeNodeRef> add_node_collection(const TreeNodeCollectionSkeleton &nodes, int position = -1) = 0;

    virtual void expand() = 0;
    virtual void collapse() = 0;
    virtual bool is_expanded() = 0;

    // Primitive check. Use TreeNodeView::can_expand() instead for potentially more sophisticated checks.
    virtual bool can_expand() { return count() > 0; };
    virtual void toggle();

    virtual void set_tag(const std::string &tag) = 0;
    virtual std::string get_tag() const = 0;

    virtual void set_data(TreeNodeData *data) = 0;
    virtual TreeNodeData *get_data() const = 0;
  };
  

#ifndef DOXYGEN_SHOULD_SKIP_THIS
#ifndef SWIG
  struct TreeNodeViewImplPtrs
  {
    bool (*create)(TreeNodeView *self, TreeOptions options);
    
#if defined(_WIN32)
    int (*add_column)(TreeNodeView *self, TreeColumnType type, const std::string &name, int initial_width, bool editable);
#else
    int (*add_column)(TreeNodeView *self, TreeColumnType type, const std::string &name, int initial_width, bool editable, bool attributed);
#endif
    void (*end_columns)(TreeNodeView *self);
    
    void (*clear)(TreeNodeView *self);

    TreeNodeRef (*root_node)(TreeNodeView *self);

    void (*set_row_height)(TreeNodeView *self, int height);
    
    void (*set_allow_sorting)(TreeNodeView *self, bool);
    
    void (*freeze_refresh)(TreeNodeView *self, bool);
    
    void (*set_selection_mode)(TreeNodeView *self, TreeSelectionMode mode);
    TreeSelectionMode (*get_selection_mode)(TreeNodeView *self);
    
    std::list<TreeNodeRef> (*get_selection)(TreeNodeView *self);
    TreeNodeRef (*get_selected_node)(TreeNodeView *self);

    void (*clear_selection)(TreeNodeView *self);
    void (*set_selected)(TreeNodeView *self, TreeNodeRef node, bool state);
    
    int (*row_for_node)(TreeNodeView *self, TreeNodeRef node);
    TreeNodeRef (*node_at_row)(TreeNodeView *self, int row);
    TreeNodeRef(*node_at_position)(TreeNodeView *self, base::Point position);
    TreeNodeRef (*node_with_tag)(TreeNodeView *self, const std::string &tag);

    void (*set_column_title)(TreeNodeView *self, int column, const std::string &title);
    
    void (*set_column_visible)(TreeNodeView *self, int column, bool flag);
    bool (*get_column_visible)(TreeNodeView *self, int column);
      
    void (*set_column_width)(TreeNodeView *self, int column, int width);
    int (*get_column_width)(TreeNodeView *self, int column);
  };
#endif
#endif
  
  class ContextMenu;
  
  /** Control to show nodes in multiple columns in the form of a tree. 
   
   Before adding items, you must first define the columns and the content types with
   add_column() and end_columns()
   */
  class MFORMS_EXPORT TreeNodeView : public View
  {
  public:
    TreeNodeView(TreeOptions options);
    ~TreeNodeView();

    /** Adds a column to be displayed in the tree.
     
     @param type - type of value to be displayed in column
     @param name - name/caption to show in header
     @param initia_width - width in pixels of the column
     @param editable - whether editing is allowed for rows in this column
     */
    int add_column(TreeColumnType type, const std::string &name, int initial_width, bool editable = false, bool attributed = false);
    /** Must be called after needed add_column() calls are finished. */
    void end_columns();
    
    /** Sets the title of the given column */
    void set_column_title(int column, const std::string &title);

    /** Sets a callback that's called when the mouse hovers on a row.
     
     Callback must return path to an icon if it wants it to be displayed. When the user clicks it,
     the node_activated() handler is called, with a negated, one-based index of the icon index (-1, -2 etc.).
     */
    void set_row_overlay_handler(const boost::function<std::vector<std::string> (TreeNodeRef)> &overlay_icon_for_node);

    int get_column_count() const { return (int)_column_types.size(); }
    TreeColumnType get_column_type(int column);
    
    /** Removes all nodes */
    void clear();
    TreeNodeRef root_node();

    TreeNodeRef add_node();

    /** Selects selection type */
    void set_selection_mode(TreeSelectionMode mode);
    /** Returns the current selection mode */
    TreeSelectionMode get_selection_mode();

    /** Returns a list of the selected nodes */
    std::list<TreeNodeRef> get_selection();
    /** Returns the selected node. In case multiple selected nodes exist, only the 1st is returned */
    TreeNodeRef get_selected_node();
    int get_selected_row();
    void clear_selection();
    
    /** Sets the selection state of the node */
    void select_node(TreeNodeRef node);
    void set_node_selected(TreeNodeRef node, bool flag);
    
    int row_for_node(TreeNodeRef node);
    TreeNodeRef node_at_row(int row);
    TreeNodeRef node_at_position(base::Point position); // TODO: Linux

    /** Requires TreeIndexOnTag */
    TreeNodeRef node_with_tag(const std::string &tag);

    /** Sets the height of a row in pixels */
    void set_row_height(int height);
    
    /** Toggles sorting of rows when the user clicks on a column header
     
     Be careful with the get_selected() and set_selected() methods when sorting is enabled,
     as the index of a row will change depending on the sorting. Use get_row_tag() for
     an immutable identifier for rows.
     
     \warning When sorting is enabled, you must use freeze_refresh()/thaw_refresh() when making changes to tree,
     otherwise the contents will become corrupted.
     */
    void set_allow_sorting(bool flag);

    /** Freezes refresh of tree display. Use when updating a large number of rows or when sorting is enabled. */
    void freeze_refresh();
    
    /** Unfreezes a previously done freeze_refresh() */
    void thaw_refresh();

    void set_column_visible(int column, bool flag);

    bool get_column_visible(int column);
    
#ifndef SWIG
    /** Signal emitted when the selected row is changed 
     
     In Python use add_changed_callback()
     */
    boost::signals2::signal<void ()>* signal_changed() {return &_signal_changed;}
    /** Signal emitted when the user double-clicks a cell.
     
     Arguments passed are row node and column index.
     
     In Python use add_activated_callback()
     */
    boost::signals2::signal<void (TreeNodeRef, int)>* signal_node_activated() {return &_signal_activated;}

    boost::signals2::signal<void (TreeNodeRef, bool)>* signal_expand_toggle() {return &_signal_expand_toggle;}
    
    boost::signals2::signal<void (int)>* signal_column_resized() {return &_signal_column_resized;}
    
    /** Sets a callback to handle changed made by user to tree cells.
     
     if this handler is set, it must call set() itself whenever a cell is edited
     otherwise changes will not be committed.
     */
    void set_cell_edit_handler(const boost::function<void (TreeNodeRef, int, std::string)> &handler);
#endif
    /** Sets a context menu to be attached to the treeview, to be shown on right click
     
     Note: Ownership of the context menu remains with the caller and it will not be freed
     when this object is deleted. */
    void set_context_menu(ContextMenu *menu);
    
    /** Sets a context menu to be attached to the treeviews header, to be shown on right click
     
     You can use the get_clicked_header_column() from the menu's will_show handler to get the column
     that was right clicked.
     
     Note: Ownership of the context menu remains with the caller and it will not be freed
     when this object is deleted. */
    void set_header_menu(ContextMenu *menu);
    
    /** Returns the context menu object attached to the treeview */
    ContextMenu *get_context_menu() { return _context_menu; }
    
    /** Returns the context menu object attached to the treeview header */
    ContextMenu *get_header_menu() { return _header_menu; }
    
    int get_clicked_header_column() { return _clicked_header_column; }
    
    /** Returns the current width of a column */
    int get_column_width(int column);
      
    /** Sets the widths of a column */
    void set_column_width(int column, int width);
      
  public:
    // backwards compatibility with TreeView
    
    int count() { return root_node()->count(); }
    
#ifndef DOXYGEN_SHOULD_SKIP_THIS   
#ifndef SWIG
  public: 
    // Following methods are for internal use.
    virtual void changed();
    virtual void node_activated(TreeNodeRef row, int column);
    virtual bool can_expand(TreeNodeRef row);
    
    // to be called BEFORE a node is expanded or AFTER its collapsed
    virtual void expand_toggle(TreeNodeRef row, bool expanded);

    // for use when sorting NumericWithUnitColumns in platform code
    static double parse_string_with_unit(const char *s);

    // To be called when user edits a cell. If this returns true, the cell value should be
    // updated by the caller, otherwise it should be left unchanged.
    virtual bool cell_edited(TreeNodeRef row, int column, const std::string &value);

    // Drag/drop support. The treeview has a different handling as dragging is initiated by the platform
    // and we call back to get data and formats (pull request). The general handling, in opposition,
    // is using a push request, initiating the drag in the backend.

    // Return format, data and other details for a drag operation that is about to start.
    // Called only if this tree can be a drag source at all (see create flags).
    // If the result of this call is false then no native drag operation is started.
    virtual bool get_drag_data(DragDetails &details, void **data, std::string &format);

    // Called only if get_drag_data returned true (and the tree can be a drag source).
    // The given operation tells what happened.
    virtual void drag_finished(DragOperation operation);
    
    virtual void column_resized(int column);

    // Called when the mouse hovers on a row
    std::vector<std::string> overlay_icons_for_node(TreeNodeRef row);

    // Called when mouse clicks on a overlay icon
    void overlay_icon_for_node_clicked(TreeNodeRef row, int index);

    // Called when right clicking on a header/title of a column, so that the context menu handler can know
    // what column is it being shown for
    void header_clicked(int column);
#endif
#endif

  private:
    TreeNodeViewImplPtrs *_treeview_impl;
    boost::signals2::signal<void ()>  _signal_changed;
    boost::signals2::signal<void (TreeNodeRef, int)>  _signal_activated;
    boost::signals2::signal<void (TreeNodeRef, bool)> _signal_expand_toggle;
    boost::function<void (TreeNodeRef, int, std::string)> _cell_edited;
    boost::signals2::signal<void (int)> _signal_column_resized;
    boost::function<std::vector<std::string> (TreeNodeRef)> _overlay_icons_for_node;
    ContextMenu *_context_menu;
    ContextMenu *_header_menu;
    std::vector<TreeColumnType> _column_types;
    int _update_count;
    int _clicked_header_column;
    bool _index_on_tag;
    bool _end_column_called;
  };
}