GNOME Bugzilla – Bug 87241
TextBuffer needs extra iterators
Last modified: 2004-12-22 21:47:04 UTC
Gtk::TextBuffer (used by Gtk::TextView) has an iterator (GtkTextIter) and we need to make this more STL-like. In GtkTreeModel, which is similar, we have a TreeNodeChildren TreeModel::children() method that returns a separate STL-style API object. I guess that we need to do something like that again because we need to store extra information such as whether the iterator is invalid. At the moment, TextBuffer::end() probably returns the last iter, instead of the one after the end, so "!= buffer->end()" would not work as expected.
I'm working on this, using the same technique as TreeIterBase/TreeIter to hold an extra bool is_end_.
Created attachment 9644 [details] [review] textbuffer_stl.patch
Here's a partial patch to make TextBuffer more STL-like. 1. We don't seem to need a separate class, like TreeModelChildren. 2. We probably need 4 different iterators, for characters, words, sentences, and lines. But then what would TextBuffer::size() return? What STL container is analogous to this situation? 3. insert_with_tag(iter, text, tag) should probably also return an iterator and not modify the input iterator. This is obvious when you look at the patched example. This is for Daniel to look over before I go further with it.
I was wrong. GtkTextIter does have the end() concept. Havoc knew what he was doing. So there wasn't so much to do. This revised patch just changes the insert() methods to return the new iterator and not modify the input iterator, like an STL-style insert() should. I'm confident that this patch is OK.
Created attachment 9680 [details] [review] textview_stl2.patch
Created attachment 9681 [details] [review] textbuffer_stl3.patch
Ignore the 2nd patch - it was only half built. Here's another.
I don't know any of the GTK+ TextBuffer internals - but I'd like to comment on the question you raise about whether to have characters/words/lines iterators. As a programmer who use the STL quite a bit, I'd expect just a character iterator and then let my algorithms go on to a word, line etc... or is this character/word/line thing a "feature"?
GtkTextBuffer allows iteration through words, sentences and lines as well as characters. We just want to make that more STL-like.
OK. Looking quickly through the index in The C++ Programming Language, I don't think any other STL container has this issue. I would be fine if size() just returned the number of characters, and then perhaps add specialized versions, so that: cout << myTextBuf.<Gtk::TextBuffer::LineIterator>size() << endl; would return the number of lines.
I don't think that's a very pleasant syntax. And it's not just size(). There is also the question of what iterator is returned by the insert*() methods. I think that the normal iterator should just be a char-based iterator used by most things. And we could have extra iterators for use when they are wanted. I guess we would need to have automatic conversions between them, so that we could insert at a word as well as at a character offset.
Applied my insert() patch.
It's not very clear to me how we should do this. 1. There can be only one begin() and end(), though we could have overriden erase() and insert(). 2. I suppose we could allow a char iterator to be converted to a word iterator, but then we would need to choose to jump to the start or end of the current word when converting. Althogh Gtk::TreeModel::iterator is mostly character-based, people can still use iter->forward_*() to do the word/sentence/line-based stuff, so the functionality is already there. Unless someone comes up with a good solution/patch then I feel like punting this to a future incompatible gtkmm version when we've had time to get feedback on a prototype.
<mbp> murrayc, wild suggestion to TextBuffer, what about a class inside TextBuffer called 'Lines', 'Words', 'Sentences'? <mbp> so you could do Gtk::TextBuffer::Words::iterator worditer = textbuffer->words.begin(); <murrayc> mbp: Yes, that would be like our current use of items(), children(), etc, for STL-interfaces. <murrayc> It's important to remember that people want to iterate in several different ways with one iterator though. For instance, they want to step over 4 lines, then 3 words, then 6 characters. <mbp> ah.. <mbp> would it be possible to convert between them? <mbp> so eg., you could say Gtk::TextBuffer::Lines::iterator line = myworditer; line++; <murrayc> Yes, that's what I was thinking of. <murrayc> Although that would be more code and might seem less convenient than iter->forward_words(3). <mbp> though it would lead the way to something like, for_each(words.begin(), words.end(), functorObjectToDoStuffWithWords) <murrayc> mbp: Yes, that would be nice. <murrayc> Still, it sounds like something that needs to be looked at thoroughly before a freeze.
Punted, unless someone does the work real fast.
This isn't actually _needed_. It's just that it might be nice. And it looks like nobody wants it enough to actually implement it any time soon, so I'm closing this bug.