treeitem.h

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

Generated on Wed Jan 28 07:23:52 2009 for cwidget by  doxygen 1.5.6