cwidget 0.5.16
|
00001 // treeitem.h (this is -*-c++-*-) 00002 // 00003 // Copyright 1999-2001, 2004-2005, 2007 Daniel Burrows 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation; either version 2 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with this program; see the file COPYING. If not, write to 00017 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 // Boston, MA 02111-1307, USA. 00019 // 00020 // The basic tree item declaration (moved here to reduce the size of 00021 // tree.h) 00022 // 00023 // I think this is *TOO* general. A simplified version will probably be 00024 // introduced at some point -- but the API should be fairly stable and nothing 00025 // outside this file is likely to change significantly. Yeah, right. 00026 00027 #ifndef TREEITEM_H 00028 #define TREEITEM_H 00029 00030 #include <stdlib.h> 00031 00032 #include <cwidget/curses++.h> 00033 #include <cwidget/style.h> 00034 00035 #include "minibuf_win.h" 00036 00037 namespace cwidget 00038 { 00039 namespace widgets 00040 { 00041 class tree; 00042 class treeitem; 00043 class sortpolicy; 00044 00045 class tree_levelref 00046 // A generic way to iterate over a *single level* of a tree. Not really an 00047 // "iterator" since it doesn't do the operators and so on. 00048 { 00049 tree_levelref *parent; 00050 public: 00051 tree_levelref():parent(NULL) {} 00052 tree_levelref(const tree_levelref &x) 00053 :parent(x.parent?x.parent->clone():NULL) {} 00054 virtual ~tree_levelref() {} 00055 00056 virtual treeitem *get_item()=0; 00057 virtual void advance_next()=0; 00058 virtual void return_prev()=0; 00059 // Like ++ and --, sort of.. 00060 00061 virtual bool is_begin()=0; 00062 // Should return true if this iterator is at the front of a list (so going 00063 // back will do Really Bad Things) -- many STL containers need this.. 00064 virtual bool is_end()=0; 00065 // Should return true if this iterator no longer refers to something valid. 00066 00067 virtual tree_levelref *clone() const=0; 00068 00069 friend class treeiterator; 00070 }; 00071 00072 class tree_root_iterator:public tree_levelref 00073 // A dummy iterator for use on parent-less trees (all other iterators 00074 // assume that they have a valid parent -- er?) 00075 { 00076 treeitem *val; 00077 treeitem *prevval; 00078 00079 treeitem *get_item() {return val;} 00080 public: 00081 tree_root_iterator(treeitem *_val):val(_val), prevval(NULL) {} 00082 tree_root_iterator(const tree_root_iterator &x):tree_levelref(x), val(x.val), prevval(x.prevval) {} 00083 00084 void advance_next() {if(val) { prevval=val; val=NULL;} } 00085 void return_prev() {if(prevval) {val=prevval; prevval=NULL;} } 00086 00087 tree_root_iterator *clone() const {return new tree_root_iterator(*this);} 00088 00089 bool is_end() {return !val;} 00090 bool is_begin() {return prevval==NULL;} 00091 00092 // Returns an "end iterator" for this tree 00093 tree_root_iterator *end() 00094 { 00095 tree_root_iterator *rval=new tree_root_iterator(*this); 00096 rval->advance_next(); 00097 return rval; 00098 } 00099 }; 00100 00101 class treeitem 00102 // An abstracted item (could be a leaf node or a subtree) -- this isn't really 00103 // meant to be that useful in general, derive from the specialized children 00104 // instead. 00105 { 00106 int depth; 00107 bool selectable; 00108 protected: 00109 virtual void set_depth(int _depth) {depth=_depth;} 00110 virtual void set_selectable(bool _selectable) {selectable=_selectable;} 00111 public: 00112 treeitem(bool _selectable=true):depth(0),selectable(_selectable) {} 00113 00126 virtual void paint(tree *win, int y, bool hierarchical, 00127 const style &st)=0; 00128 00138 void paint(tree *win, int y, bool hierarchical, 00139 const std::wstring &str, int depth_shift=2); 00140 00141 virtual const wchar_t *tag()=0; 00142 // The tag that this item should be sorted by [for the trivial version of 00143 // the subtree object] 00144 virtual const wchar_t *label()=0; 00145 // The label to display when this item is "active" in non-hierarchical mode. 00146 00147 int get_depth() {return depth;} 00148 bool get_selectable() {return selectable;} 00149 00150 virtual style get_normal_style() {return style();} 00151 virtual style get_highlight_style() {return get_normal_style()+style_attrs_flip(A_REVERSE);} 00152 00153 virtual void sort(sortpolicy &sort_method) {} 00154 // Sorts an item's subtree using the given method. 00155 00156 virtual void sort() {} 00157 // Sorts an item's subtree (NOP for most items) -- provided to make it easy 00158 // to recursively sort the list. 00159 00169 00171 sigc::signal1<void, bool> highlighted_changed; 00172 00174 00175 virtual bool dispatch_key(const config::key &k, tree *owner) {return false;} 00176 // Called when a key is pressed while the item is highlighted. The return 00177 // value indicates whether a redraw of the screen is needed. 00178 // (not any more; now it indicates whether the item consumed the keystroke 00179 // -- this also triggers a screen repainting, but is a more useful semantic) 00180 virtual void dispatch_mouse(short id, int x, mmask_t bstate, tree *owner) 00181 { 00182 } 00183 // Called when a mouse event occurs at the y location assigned to this 00184 // item. 00185 00186 virtual tree_levelref *begin() {return NULL;} 00187 virtual tree_levelref *end() {return NULL;} 00188 // These can act like containers; these routines return a NEWLY ALLOCATED 00189 // POINTER, though. 00190 00191 virtual bool has_visible_children() {return false;} 00192 virtual bool has_children() {return false;} 00193 00194 virtual bool matches(const std::wstring &s) const {return false;} 00195 // Returns true if this item matches the given string. 00196 00197 // More hackery: do what's needed to expand the children of this item. 00198 virtual void expand() {} 00199 virtual void expand_all() {} 00200 virtual void collapse_all() {} 00201 00202 template<class childtype, class sorter> 00203 friend class subtree; 00204 00205 virtual ~treeitem() {} 00206 }; 00207 00208 class treeiterator 00209 { 00210 tree_levelref *curr; 00211 bool ignore_collapsed; 00212 00213 public: 00214 treeiterator(tree_levelref *_curr, bool _ignore_collapsed=false):curr(_curr),ignore_collapsed(_ignore_collapsed) {} 00215 treeiterator(const treeiterator &x):curr(x.curr?x.curr->clone():NULL),ignore_collapsed(x.ignore_collapsed) {} 00216 treeiterator(const treeiterator &x, bool _ignore_collapsed):curr(x.curr?x.curr->clone():NULL),ignore_collapsed(_ignore_collapsed) {} 00217 00218 bool is_root() {return curr->parent==NULL;} 00219 // Ugh, a really nasty hack. 00220 treeiterator get_up() 00221 { 00222 return treeiterator(curr->parent->clone()); 00223 } 00224 00225 void expand() 00226 { 00227 if(curr && curr->get_item()) 00228 curr->get_item()->expand(); 00229 } 00230 00231 treeitem &operator*() {return *curr->get_item();} 00232 const treeitem &operator*() const {return *curr->get_item();} 00233 treeitem *operator->() {return curr->get_item();} 00234 const treeitem *operator->() const {return curr->get_item();} 00235 00236 bool operator==(const treeiterator &x) 00237 { 00238 if(!curr) 00239 return !x.curr; 00240 else if(!x.curr) 00241 return false; 00242 else if(curr->is_end()) 00243 return x.curr->is_end() && curr->parent == x.curr->parent; 00244 else if(x.curr->is_end()) 00245 return false; 00246 else 00247 return curr->get_item()==x.curr->get_item(); 00248 } 00249 bool operator!=(const treeiterator &x) 00250 {return !(*this==x);} 00251 00252 treeiterator &operator=(const treeiterator &x) 00253 { 00254 while(curr) 00255 { 00256 tree_levelref *old=curr; 00257 curr=curr->parent; 00258 delete old; 00259 } 00260 00261 curr=x.curr?x.curr->clone():NULL; 00262 00263 return *this; 00264 } 00265 00266 treeiterator &operator++() 00267 { 00268 if(curr->get_item() && 00269 (ignore_collapsed?curr->get_item()->has_children():curr->get_item()->has_visible_children())) 00270 { 00271 tree_levelref *newref=curr->get_item()->begin(); 00272 newref->parent=curr; 00273 curr=newref; 00274 } 00275 else 00276 { 00277 curr->advance_next(); 00278 00279 while(curr->is_end() && curr->parent) 00280 { 00281 tree_levelref *old=curr; 00282 curr=curr->parent; 00283 curr->advance_next(); 00284 delete old; 00285 } 00286 } 00287 00288 return *this; 00289 } 00290 treeiterator operator++(int) 00291 { 00292 treeiterator oldval(curr?curr->clone():NULL); 00293 00294 ++*this; 00295 00296 return oldval; 00297 } 00298 00299 treeiterator &operator--() 00300 { 00301 if(curr->is_begin()) 00302 { 00303 if(curr->parent) 00304 { 00305 tree_levelref *old=curr; 00306 curr=curr->parent; 00307 delete old; 00308 } 00309 } 00310 else 00311 { 00312 curr->return_prev(); 00313 while(curr->get_item() && 00314 (ignore_collapsed?curr->get_item()->has_children():curr->get_item()->has_visible_children())) 00315 { 00316 tree_levelref *newref=curr->get_item()->end(); 00317 00318 newref->parent=curr; 00319 newref->return_prev(); 00320 curr=newref; 00321 } 00322 } 00323 return *this; 00324 } 00325 00326 treeiterator operator--(int) 00327 { 00328 treeiterator oldval(curr?curr->clone():NULL); 00329 00330 --*this; 00331 00332 return oldval; 00333 } 00334 00335 void move_forward_level() 00336 { 00337 if(!curr->is_end()) 00338 { 00339 tree_levelref *old=curr->clone(); 00340 curr->advance_next(); 00341 00342 if(curr->is_end()) 00343 { 00344 delete curr; 00345 curr=old; 00346 } 00347 else 00348 delete old; 00349 } 00350 } 00351 00352 void move_backward_level() 00353 { 00354 if(!curr->is_begin()) 00355 curr->return_prev(); 00356 } 00357 00358 ~treeiterator() 00359 { 00360 while(curr) 00361 { 00362 tree_levelref *old=curr; 00363 curr=curr->parent; 00364 delete old; 00365 } 00366 } 00367 }; 00368 00369 // A generic sorter. 00370 // 00371 // Making operator() virtual is a bit icky. 00372 class sortpolicy 00373 { 00374 public: 00375 sortpolicy() {} 00376 00377 virtual bool operator()(treeitem *item1, 00378 treeitem *item2)=0; 00379 00380 virtual ~sortpolicy() {} 00381 }; 00382 00383 // ack! How dare this be templated? 00384 //template<class childtype> 00385 class tag_sort_policy:public sortpolicy 00386 { 00387 public: 00388 bool operator()(treeitem *item1, treeitem *item2) 00389 { 00390 return (wcscmp(item1->tag(), item2->tag())<0); 00391 } 00392 }; 00393 00394 // Hack? hmm.. 00395 // 00396 // Here's the situation: STL sort passes the sort method by value, probably 00397 // to keep people from being horrendously inefficient like I'm about to. But 00398 // we can get around that with an inline wrapper: 00399 class sortpolicy_wrapper 00400 { 00401 sortpolicy &real_policy; 00402 public: 00403 sortpolicy_wrapper(sortpolicy &_real_policy):real_policy(_real_policy) 00404 { 00405 } 00406 00407 inline bool operator()(treeitem *item1, 00408 treeitem *item2) const 00409 { 00410 return real_policy(item1, item2); 00411 } 00412 }; 00413 } 00414 } 00415 00416 #endif