File: tree_model.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 (442 lines) | stat: -rw-r--r-- 14,579 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
/* 
 * Copyright (c) 2007, 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
 */

#ifndef _TREE_MODEL_H_
#define _TREE_MODEL_H_

/*
 * TreeModel is the base class for all list or tree based
 * backend classes. 
 */
#include <algorithm>

#include <grtpp.h>
#include "grt/icon_manager.h"
#include "grt/common.h"
#include "base/ui_form.h" // for menu stuff
#include "base/trackable.h"
#include "base/threading.h"

#include "wbpublic_public_interface.h"
#include <boost/shared_ptr.hpp>
#include <ctype.h>

#include <set>
#include <algorithm>

namespace mforms {
  class MenuBase;
}

namespace bec
{
  /** A tree node index.
   * Used to index nodes in a tree or list backend that inherits from ListModel or TreeModel.
   * A nodeId is like an index, in the simplest case of a flat list, it will contain
   * a single integer index. For trees, it will contain one index for each parent node
   * until the leaf node it refers to.
   * 
   * Since nodeIds are just indices, a nodeId may not point to the same item after
   * the list/tree contents change.
   * 
   * @ingroup begrt
   */ 

  /**
  */  
  // TODO: Add threshold so we do not accumulate megabytes of allocated index vectors
  template <typename T>
  class WBPUBLICBACKEND_PUBLIC_FUNC Pool
  {
    private:
      Pool(const Pool&)
      {
        throw std::runtime_error("Copy of Pool forbidden");
      }
      Pool& operator=(const Pool&)
      {
        throw std::runtime_error("Assignment of Pool forbidden");
      }
    public:
      static void delete_object(T* obj)
      {
        delete obj;
      }
  
      Pool()
          : _pool(4)
      {}
    
      ~Pool()
      {
        {
          base::MutexLock lock(_sync);
          std::for_each(_pool.begin(), _pool.end(), Pool::delete_object);
        }
      }
    
      T* get()
      {
        T* item = 0;
        try
        {
          base::MutexLock lock(_sync);
          if ( _pool.size() > 0 )
          { 
            item = _pool.back();
            _pool.pop_back();
          }
        }
        catch (...)
        {
          //TODO: check when pop may throw
        }
      
        if ( !item )
        {
          item = new T;
        }
      
        return item;
      }
    
      void put(T* item)
      {
        base::MutexLock lock(_sync);
        _pool.push_back(item);
      }
  
    private:
      std::vector<T*>  _pool;
      base::Mutex          _sync; //! Protect against concurrent access within threads
  };

  /**
    \class NodeId
    \brief descibes path to a node starting from root for a Tree or it will contain an index (single entry) for List

    Imagine we have a tree with a two root nodes and two children of each root. So to address first child of the
    first root node we need to have a path like that: "0.0". To address the second child of the first root node:
    "0.1"
  */
  struct WBPUBLICBACKEND_PUBLIC_FUNC NodeId 
  {
    typedef std::string*                uid;   //!< To map short-living NodeId path to a persistent value
                                               //!< This is needed for Gtk::TreeModel iterators
    typedef std::vector<size_t>        Index; 
    static Pool<Index>                 *_pool; //!< Pool of allocated std::vectors (Index)
    Index                              *index; //!< Path itself

    static Pool<Index>* pool()
    {
      return _pool ? _pool : (_pool = new Pool<Index>);
    }


    NodeId();
    NodeId(const NodeId &copy);
    NodeId(size_t i);
    NodeId(const std::string &str);
    ~NodeId();

    inline NodeId &operator = (const NodeId &node)
    {
      *index = *node.index;
      
      return *this;
    }

    bool operator < (const NodeId &r) const;

    inline bool operator == (const NodeId &node) const
    {
      return equals(node);
    }

    bool equals(const NodeId &node) const;

    inline size_t depth() const
    {
      return index->size();
    }

    size_t& operator[] (size_t i) const;

    size_t end() const;    
    inline size_t back() const
    {
      return end();
    }
    
    bool previous() const;
    bool next() const;

    inline bool is_valid() const
    {
      return index->size() != 0;
    }
    
    NodeId parent() const;
    std::string description() const;
    std::string toString(const char separator = '.') const;

    NodeId &append(size_t i);
    NodeId &prepend(size_t i);
  };

  //----------------------------------------------------------------------------

  /**
    \class NodeIds
    \brief Mapper of short-living NodeId to a persistent item

    This class was added cause GtkTreeIter which is used in TreeModel for Gtk::TreeView
    has only three int-size fields describing iterator state. And it is not possible to fit entire NodeId
    there, moreover GtkTreeIter along with Gtk::TreeIter have no indication when iterator is
    destroyed. So the was a need to have something small which can be fit into those fields.
    Lifetime of the items named 'uid' is defined by the initial mapping when the uid is created
    and the issue of NodeIds::flush call. The mapped entity 'uid' is a pointer to a std::string stored
    in the std::set. For example if we need to have an item which lifetime is longer that NodeId("1.2.3")
    we should obtain mapped uid of the NodeId("1.2.3"). That mapped item - uid will be a pointer
    to a string in the std::set and the string itself will store "1.2.3". Having that uid allows us to get back
    path which can be stored between NodeId creations. That is used for example when we obtain Gtk::TreeIter
    and need to move to the next node in the Tree thus advance iterator.
    It is not advisable to dereference 'uid' to obtain std::string from std::string*, as future implementation
    may change that.
  */
  class NodeIds
  {
    public:
      NodeIds() {}

      //! Resets map of NodeId paths to uid
      void flush();

      //! Maps path with type of std::string from NodeId. This function is used for
      //! convenience. See map_node_id(const NodeId&)
      NodeId::uid map_node_id(const std::string& path_from_nodeid);
      NodeId::uid map_node_id(const NodeId& nid)
      {
        return map_node_id(nid.toString());
      }

      //! Reverse mapping from 'uid' to a path
      const std::string& map_node_id(const NodeId::uid nodeid);

    private:
      typedef std::set<std::string> Map;

      Map          _map;
  };

  //------------------------------------------------------------------------------
  inline void NodeIds::flush()
  {
    _map.clear();
  }

  //------------------------------------------------------------------------------
  inline NodeId::uid NodeIds::map_node_id(const std::string& path_from_nodeid)
  {
    const Map::const_iterator it = _map.find(path_from_nodeid);
    if ( _map.end() != it )
      return (const NodeId::uid)&(*it);
    else
    {
      //TODO: make a faster way. Probably we can use item from insert
      _map.insert(path_from_nodeid);
      return map_node_id(path_from_nodeid);
    }
  }

  //------------------------------------------------------------------------------
  inline const std::string& NodeIds::map_node_id(const NodeId::uid nodeid)
  {
    // Note that dereference of nodeid is dangerous after flush was called
    // That should be protected by stamp approach in TreeModel wrapper.
    static std::string empty;
    return nodeid ? *nodeid : empty;
  }
  
  /** Base list model class.
   */
  class WBPUBLICBACKEND_PUBLIC_FUNC ListModel : public base::trackable
  {
   private:
    NodeIds _nodeid_map;
    boost::signals2::signal<void (bec::NodeId, int)> _tree_changed_signal;
    
   public:
     typedef size_t ColumnId;
     typedef size_t RowId;
     
     virtual ~ListModel() {};

    virtual size_t count() = 0;
    virtual NodeId get_node(size_t index);
    virtual bool has_next(const NodeId &node);
    virtual NodeId get_next(const NodeId &node);

    boost::signals2::signal<void (bec::NodeId, int)>* tree_changed_signal(){return &_tree_changed_signal;}

    void tree_changed(int old_child_count = -1, const bec::NodeId &parent = bec::NodeId())
    {
      _tree_changed_signal(parent, old_child_count);
      _nodeid_map.flush();
    }

    NodeId::uid nodeid_to_uid(const NodeId& nodeid)
    {
      return _nodeid_map.map_node_id(nodeid);
    }

    NodeId::uid nodeid_path_to_uid(const std::string& path)
    {
      return _nodeid_map.map_node_id(path);
    }

    const std::string& nodeuid_to_path(const NodeId::uid nodeuid)
    {
      return _nodeid_map.map_node_id(nodeuid);
    }
    virtual bool get_field(const NodeId &node, ColumnId column, std::string &value);
    virtual bool get_field(const NodeId &node, ColumnId column, ssize_t &value);
    virtual bool get_field(const NodeId &node, ColumnId column, bool &value);
    virtual bool get_field(const NodeId &node, ColumnId column, double &value);

    virtual bool get_field_repr(const NodeId &node, ColumnId column, std::string &value) { return get_field(node, column, value); }

    // representation of the field as a GRT value
    virtual grt::ValueRef get_grt_value(const NodeId &node, ColumnId column);

    virtual std::string get_field_description(const NodeId &node, ColumnId column);
    virtual IconId get_field_icon(const NodeId &node, ColumnId column, IconSize size);

    virtual void refresh() = 0;
    virtual void refresh_node(const NodeId &node) {}

    virtual void reset() {} //!

    virtual void reorder(const NodeId &node, size_t index) { throw std::logic_error("not implemented"); }
    void reorder_up(const NodeId &node);
    void reorder_down(const NodeId &node);

    virtual bool activate_node(const NodeId &node) { throw std::logic_error("not implemented"); return false; }

    // Parent can be NULL if the root node is meant.
    virtual void update_menu_items_for_nodes(mforms::MenuBase *parent, const std::vector<NodeId> &nodes) { };

    // Deprecated. Use update_menu_items_for_nodes for new code. MenuItemList and related code will go.
    virtual MenuItemList get_popup_items_for_nodes(const std::vector<NodeId> &nodes) { return MenuItemList(); }
    //! Returns true if item was processed by BE, false - BE is unable to process command and FE should do it
    virtual bool activate_popup_item_for_nodes(const std::string &name, const std::vector<NodeId> &nodes) { throw std::logic_error("not implemented"); }

    virtual bool can_delete_node(const NodeId &node) { return false; }
    virtual bool delete_node(const NodeId &node) { throw std::logic_error("not implemented"); }

    // for editable lists only
    virtual grt::Type get_field_type(const NodeId &node, ColumnId column);


    virtual bool set_field(const NodeId &node, ColumnId column, const std::string &value);
    virtual bool set_field(const NodeId &node, ColumnId column, ssize_t value);
    virtual bool set_field(const NodeId &node, ColumnId column, double value);

    virtual bool set_convert_field(const NodeId &node, ColumnId column, const std::string &value);

    //! By default we do not allow to edit items.
    //! This is a recently added method. It will replace occasionally used is_renameable
    virtual bool is_editable(const NodeId& node) const { return false; }
    virtual bool is_deletable(const NodeId& node) const { return false; }
    virtual bool is_copyable(const NodeId& node) const { return false; }

    // Indicates if a given node is to be visually exposed (e.g. an active schema in a schema tree).
    virtual bool is_highlighted(const NodeId& node) { return false; }

    virtual void dump(int show_field);
  protected:
    // for internal use only
    virtual bool get_field_grt(const NodeId &node, ColumnId column, grt::ValueRef &value);

    grt::ValueRef parse_value(grt::Type type, const std::string &value);
  };

  /** Base tree model class.
   */
  class WBPUBLICBACKEND_PUBLIC_FUNC TreeModel : public ListModel
  {
  public:
    virtual size_t count();
    virtual NodeId get_node(size_t index);

    virtual NodeId get_root() const;
    virtual size_t get_node_depth(const NodeId &node);
    inline NodeId get_parent(const NodeId &node) const { return node.parent(); }

    virtual size_t count_children(const NodeId &parent) = 0;
    virtual NodeId get_child(const NodeId &parent, size_t index) { return NodeId(parent).append(index); }
    virtual bool has_next(const NodeId &node);
    virtual NodeId get_next(const NodeId &node);

    virtual bool is_expandable(const NodeId &node_id);
    virtual bool expand_node(const NodeId &node);
    virtual void collapse_node(const NodeId &node);
    virtual bool is_expanded(const NodeId &node);

    void save_expand_info(const std::string &path);

    virtual void dump(int show_field);
  };

  class WBPUBLICBACKEND_PUBLIC_FUNC GridModel : public ListModel
  {
  public:
    typedef boost::shared_ptr<GridModel> Ref;

    enum ColumnType
    {
      UnknownType,
      StringType,
      NumericType,
      FloatType,
      DatetimeType,
      BlobType
    };

    virtual size_t get_column_count() const = 0;
    virtual std::string get_column_caption(ColumnId column)= 0;
    virtual ColumnType get_column_type(ColumnId column)= 0;
    virtual bool is_readonly() const { return false; } //!
    virtual std::string readonly_reason() const { return std::string(); } //!
    virtual bool is_field_null(const bec::NodeId &node, ColumnId column) { return false; } //!
    virtual bool set_field_null(const bec::NodeId &node, ColumnId column) { return set_convert_field(node, column, ""); } //!
    virtual void set_edited_field(RowId row_index, ColumnId col_index) { }

  public:
    typedef std::list<std::pair<ColumnId, int> > SortColumns;
    virtual void sort_by(ColumnId column, int direction, bool retaining) {}
    virtual SortColumns sort_columns() const { return SortColumns(); }

  public:
    virtual int floating_point_visible_scale() { return 3; }
  };

};

#endif // _TREE_MODEL_H_