~ubuntu-branches/ubuntu/precise/gtkmm3.0/precise

« back to all changes in this revision

Viewing changes to gtk/src/treeiter.ccg

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2011-06-17 00:12:44 UTC
  • Revision ID: james.westby@ubuntu.com-20110617001244-9hl5an15hiaaahi6
Tags: upstream-3.0.1
ImportĀ upstreamĀ versionĀ 3.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- c++ -*-
 
2
/* $Id: treeiter.ccg,v 1.10 2006/04/12 08:23:29 murrayc Exp $ */
 
3
 
 
4
/* Copyright 1998-2002 The gtkmm Development Team
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2.1 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this library; if not, write to the Free
 
18
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 */
 
20
 
 
21
#include <gtkmm/treemodel.h>
 
22
#include <gtk/gtk.h>
 
23
 
 
24
 
 
25
namespace Gtk
 
26
{
 
27
 
 
28
/**** Gtk::TreeIter ********************************************************/
 
29
 
 
30
TreeIter::TreeIter()
 
31
:
 
32
  TreeIterBase(),
 
33
  model_      (0),
 
34
  is_end_     (false)
 
35
{}
 
36
 
 
37
TreeIter::TreeIter(TreeModel* model)
 
38
:
 
39
  TreeIterBase(),
 
40
  model_      (model),
 
41
  is_end_     (false)
 
42
{}
 
43
 
 
44
TreeIter::TreeIter(GtkTreeModel* model, const GtkTreeIter* iter)
 
45
:
 
46
  TreeIterBase(iter),
 
47
  model_      (dynamic_cast<TreeModel*>(Glib::wrap_auto((GObject*) model))),
 
48
  is_end_     (iter == 0)
 
49
{}
 
50
 
 
51
TreeIter& TreeIter::operator++()
 
52
{
 
53
  g_assert(!is_end_);
 
54
 
 
55
  GtkTreeIter previous = gobject_;
 
56
 
 
57
  if(!gtk_tree_model_iter_next(model_->gobj(), &gobject_))
 
58
  {
 
59
    is_end_ = true;
 
60
    gtk_tree_model_iter_parent(Glib::unwrap(model_), &gobject_, &previous);
 
61
  }
 
62
 
 
63
  return *this;
 
64
}
 
65
 
 
66
const TreeIter TreeIter::operator++(int)
 
67
{
 
68
  g_assert(!is_end_);
 
69
 
 
70
  TreeIter previous (*this);
 
71
 
 
72
  if(!gtk_tree_model_iter_next(model_->gobj(), &gobject_))
 
73
  {
 
74
    is_end_ = true;
 
75
    gtk_tree_model_iter_parent(Glib::unwrap(model_), &gobject_, &previous.gobject_);
 
76
  }
 
77
 
 
78
  return previous;
 
79
}
 
80
 
 
81
TreeIter& TreeIter::operator--()
 
82
{
 
83
  if(!is_end_)
 
84
  {
 
85
    gtk_tree_model_iter_previous(Glib::unwrap(model_), &gobject_);
 
86
  }
 
87
  else // --end yields last
 
88
  {
 
89
    GtkTreeIter next = gobject_;
 
90
    GtkTreeIter *const parent = (next.stamp != 0) ? &next : 0;
 
91
 
 
92
    const int index = gtk_tree_model_iter_n_children(Glib::unwrap(model_), parent) - 1;
 
93
    is_end_ = !gtk_tree_model_iter_nth_child(Glib::unwrap(model_), &gobject_, parent, index);
 
94
 
 
95
    g_assert(!is_end_);
 
96
  }
 
97
 
 
98
  return *this;
 
99
}
 
100
 
 
101
const TreeIter TreeIter::operator--(int)
 
102
{
 
103
  TreeIter next (*this);
 
104
 
 
105
  if(!is_end_)
 
106
  {
 
107
    gtk_tree_model_iter_previous(Glib::unwrap(model_), &gobject_);
 
108
  }
 
109
  else // --end yields last
 
110
  {
 
111
    GtkTreeIter *const parent = (next.gobject_.stamp != 0) ? &next.gobject_ : 0;
 
112
 
 
113
    const int index = gtk_tree_model_iter_n_children(model_->gobj(), parent) - 1;
 
114
    is_end_ = !gtk_tree_model_iter_nth_child(model_->gobj(), &gobject_, parent, index);
 
115
 
 
116
    g_assert(!is_end_);
 
117
  }
 
118
 
 
119
  return next;
 
120
}
 
121
 
 
122
/* There is no public gtk_tree_iter_equal(), so we must write our own.
 
123
 */
 
124
bool TreeIter::equal(const TreeIter& other) const
 
125
{
 
126
  g_assert(model_ == other.model_);
 
127
 
 
128
  // A GtkTreeIter has the same stamp value as its model.
 
129
  g_assert(gobject_.stamp == other.gobject_.stamp || is_end_ || other.is_end_);
 
130
 
 
131
  // If all user_data pointers are equal we can assume the iterators to be
 
132
  // equal.  This should be safe since GtkTreeIter lacks destroy notification,
 
133
  // thus there is no way to attach more data fields to the iterator.
 
134
  return (is_end_ == other.is_end_) &&
 
135
         (gobject_.user_data  == other.gobject_.user_data)  &&
 
136
         (gobject_.user_data2 == other.gobject_.user_data2) &&
 
137
         (gobject_.user_data3 == other.gobject_.user_data3);
 
138
}
 
139
 
 
140
TreeIter::operator const void*() const
 
141
{
 
142
  // Test whether the GtkTreeIter is valid and not an end iterator.  This check
 
143
  // is almost the same as the private VALID_ITER() macro in gtkliststore.c and
 
144
  // gtktreestore.c.
 
145
  return (!is_end_ && gobject_.stamp) ? GINT_TO_POINTER(1) : 0;
 
146
}
 
147
 
 
148
void TreeIter::setup_end_iterator(const TreeIter& last_valid)
 
149
{
 
150
  g_assert(model_ == last_valid.model_);
 
151
 
 
152
  if(last_valid.is_end_)
 
153
    gobject_ = last_valid.gobject_;
 
154
  else
 
155
    gtk_tree_model_iter_parent(model_->gobj(), &gobject_, const_cast<GtkTreeIter*>(&last_valid.gobject_));
 
156
 
 
157
  is_end_ = true;
 
158
}
 
159
 
 
160
void TreeIter::set_model_refptr(const Glib::RefPtr<TreeModel>& model)
 
161
{
 
162
  model_ = model.operator->();
 
163
}
 
164
 
 
165
void TreeIter::set_model_gobject(GtkTreeModel* model)
 
166
{
 
167
  model_ = dynamic_cast<TreeModel*>(Glib::wrap_auto((GObject*) model));
 
168
}
 
169
 
 
170
GtkTreeModel* TreeIter::get_model_gobject() const
 
171
{
 
172
  return (model_) ? model_->gobj() : 0;
 
173
}
 
174
 
 
175
 
 
176
int TreeIter::get_stamp() const
 
177
{
 
178
  return gobj()->stamp;
 
179
}
 
180
 
 
181
void TreeIter::set_stamp(int stamp)
 
182
{
 
183
  gobj()->stamp = stamp;
 
184
 
185
 
 
186
 
 
187
/**** Gtk::TreeRow *********************************************************/
 
188
 
 
189
const TreeNodeChildren& TreeRow::children() const
 
190
{
 
191
  g_assert(!is_end_);
 
192
 
 
193
  return static_cast<const TreeNodeChildren&>(static_cast<const TreeIter&>(*this));
 
194
}
 
195
 
 
196
TreeIter TreeRow::parent() const
 
197
{
 
198
  TreeIter iter (model_);
 
199
 
 
200
  if(is_end_)
 
201
    iter.gobject_ = gobject_;
 
202
  else
 
203
    gtk_tree_model_iter_parent(model_->gobj(), iter.gobj(), const_cast<GtkTreeIter*>(&gobject_));
 
204
 
 
205
  return iter;
 
206
}
 
207
 
 
208
void TreeRow::set_value_impl(int column, const Glib::ValueBase& value) const
 
209
{
 
210
  model_->set_value_impl(*this, column, value);
 
211
}
 
212
 
 
213
void TreeRow::get_value_impl(int column, Glib::ValueBase& value) const
 
214
{
 
215
  model_->get_value_impl(*this, column, value);
 
216
}
 
217
 
 
218
TreeRow::operator const void*() const
 
219
{
 
220
  return TreeIter::operator const void*();
 
221
}
 
222
 
 
223
 
 
224
/**** Gtk::TreeNodeChildren ************************************************/
 
225
 
 
226
TreeNodeChildren::iterator TreeNodeChildren::begin()
 
227
{
 
228
  iterator iter (model_);
 
229
 
 
230
  // If the iterator is invalid (stamp == 0), assume a 'virtual' toplevel
 
231
  // node.  This behaviour is needed to implement Gtk::TreeModel::children().
 
232
 
 
233
  if(gobject_.stamp != 0)
 
234
  {
 
235
    if(!gtk_tree_model_iter_children(model_->gobj(), iter.gobj(), const_cast<GtkTreeIter*>(&gobject_)))
 
236
    {
 
237
      // Assign the already known parent, in order to create an end iterator.
 
238
      iter.gobject_ = gobject_;
 
239
      iter.is_end_ = true;
 
240
    }
 
241
  }
 
242
  else
 
243
  {
 
244
    if(!gtk_tree_model_get_iter_first(model_->gobj(), iter.gobj()))
 
245
    {
 
246
      // No need to copy the GtkTreeIter, since iter.gobject_ is already empty.
 
247
      iter.is_end_ = true;
 
248
    }
 
249
  }
 
250
 
 
251
  return iter;
 
252
}
 
253
 
 
254
TreeNodeChildren::const_iterator TreeNodeChildren::begin() const
 
255
{
 
256
  //TODO: Reduce the copy/paste from the non-const begin()?
 
257
  
 
258
  const_iterator iter (model_);
 
259
 
 
260
  // If the iterator is invalid (stamp == 0), assume a 'virtual' toplevel
 
261
  // node.  This behaviour is needed to implement Gtk::TreeModel::children().
 
262
 
 
263
  if(gobject_.stamp != 0)
 
264
  {
 
265
    if(!gtk_tree_model_iter_children(model_->gobj(), iter.gobj(), const_cast<GtkTreeIter*>(&gobject_)))
 
266
    {
 
267
      // Assign the already known parent, in order to create an end iterator.
 
268
      iter.gobject_ = gobject_;
 
269
      iter.is_end_ = true;
 
270
    }
 
271
  }
 
272
  else
 
273
  {
 
274
    if(!gtk_tree_model_get_iter_first(model_->gobj(), iter.gobj()))
 
275
    {
 
276
      // No need to copy the GtkTreeIter, since iter.gobject_ is already empty.
 
277
      iter.is_end_ = true;
 
278
    }
 
279
  }
 
280
 
 
281
  return iter;
 
282
}
 
283
 
 
284
TreeNodeChildren::iterator TreeNodeChildren::end()
 
285
{
 
286
  // Just copy the parent, and turn it into an end iterator.
 
287
  iterator iter (*this);
 
288
  iter.is_end_ = true;
 
289
  return iter;
 
290
}
 
291
 
 
292
TreeNodeChildren::const_iterator TreeNodeChildren::end() const
 
293
{
 
294
  // Just copy the parent, and turn it into an end iterator.
 
295
  const_iterator iter (*this);
 
296
  iter.is_end_ = true;
 
297
  return iter;
 
298
}
 
299
 
 
300
TreeNodeChildren::value_type TreeNodeChildren::operator[](TreeNodeChildren::size_type index) const
 
301
{
 
302
  iterator iter (model_);
 
303
 
 
304
  GtkTreeIter *const parent = const_cast<GtkTreeIter*>(get_parent_gobject());
 
305
 
 
306
  if(!gtk_tree_model_iter_nth_child(model_->gobj(), iter.gobj(), parent, index))
 
307
  {
 
308
    // Assign the already known parent, in order to create an end iterator.
 
309
    iter.gobject_ = gobject_;
 
310
    iter.is_end_ = true;
 
311
  }
 
312
 
 
313
  return *iter;
 
314
}
 
315
 
 
316
TreeNodeChildren::size_type TreeNodeChildren::size() const
 
317
{
 
318
  GtkTreeIter *const parent = const_cast<GtkTreeIter*>(get_parent_gobject());
 
319
 
 
320
  return gtk_tree_model_iter_n_children(model_->gobj(), parent);
 
321
}
 
322
 
 
323
bool TreeNodeChildren::empty() const
 
324
{
 
325
  // If the iterator is invalid (stamp == 0), assume a 'virtual' toplevel
 
326
  // node.  This behaviour is needed to implement Gtk::TreeModel::children().
 
327
 
 
328
  if(gobject_.stamp == 0)
 
329
  {
 
330
    GtkTreeIter dummy;
 
331
    return !gtk_tree_model_get_iter_first(model_->gobj(), &dummy);
 
332
  }
 
333
 
 
334
  return !gtk_tree_model_iter_has_child(model_->gobj(), const_cast<GtkTreeIter*>(&gobject_));
 
335
}
 
336
 
 
337
} // namespace Gtk
 
338