subtree.h

00001 // subtree.h  (this is -*-c++-*-)
00002 //
00003 //  Copyright 1999-2003, 2005 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 //  Subtrees for trees.
00021 
00022 #ifndef SUBTREE_H
00023 #define SUBTREE_H
00024 
00025 #include <list>
00026 #include "treeitem.h"
00027 #include "tree.h"
00028 
00029 namespace cwidget
00030 {
00031   namespace widgets
00032   {
00033     template<class childtype, class default_sorter=tag_sort_policy>
00034     class subtree:virtual public treeitem
00035     // A tree-item which can contain other tree items.  Still abstract -- the
00036     // display routines have to be filled in, and you may want to add more behavior
00037     // on keypresses -- but we're getting there :)
00038     {
00039     protected:
00040 
00041       typedef std::list<childtype *> child_list;
00042       typedef typename std::list<childtype *>::iterator child_iterator;
00043 
00044       class levelref:public tree_levelref
00045       {
00046         child_iterator realitem;
00047 
00048         child_list *parent_list;
00049       public:
00050         levelref(const levelref &x)
00051           :tree_levelref(x), realitem(x.realitem), parent_list(x.parent_list) {}
00052         levelref(const child_iterator &_realitem, child_list *_parent_list)
00053           :realitem(_realitem), parent_list(_parent_list)
00054         {
00055         }
00056 
00057         treeitem *get_item() {eassert(realitem!=parent_list->end()); return *realitem;}
00058         virtual void advance_next() {++realitem;}
00059         virtual void return_prev() {--realitem;}
00060         bool is_begin() {return realitem==parent_list->begin();}
00061         bool is_end() {return realitem==parent_list->end();}
00062         levelref *clone() const {return new levelref(*this);}
00063       };
00064 
00065     private:
00066       bool expanded;
00067 
00068       child_list children;
00069 
00070     protected:
00071       child_iterator get_children_begin() {return children.begin();}
00072       child_iterator get_children_end() {return children.end();}
00073 
00074     public:
00075       typedef treeiterator iterator;
00076       typedef default_sorter default_sort;
00077 
00078       subtree(bool _expanded):treeitem(),expanded(_expanded) {}
00079 
00080       bool get_expanded() {return expanded;}
00081 
00082       void expand() {expanded=true;}
00083 
00084       void expand_all()
00085       {
00086         expanded=true;
00087         for(child_iterator i=children.begin(); i!=children.end(); i++)
00088           (*i)->expand_all();
00089       }
00090 
00091       void collapse_all()
00092       {
00093         expanded=false;
00094         for(child_iterator i=children.begin(); i!=children.end(); i++)
00095           (*i)->collapse_all();
00096       }
00097 
00098       void paint(tree *win, int y, bool hierarchical,
00099                  const std::wstring &str, int depth_shift=2)
00100       {
00101         int width, height;
00102         int basex=hierarchical?depth_shift*get_depth():0;
00103         win->getmaxyx(height,width);
00104 
00105         win->move(y,0);
00106 
00107         int x=0;
00108         while(x<basex && x<width)
00109           {
00110             win->add_wch(L' ');
00111             x+=wcwidth(L' ');
00112           }
00113 
00114         if(basex>width)
00115           return;
00116 
00117         const wchar_t *ws;
00118         if(hierarchical)
00119           ws=get_expanded()?L"--\\ ":L"--- ";
00120         else
00121           ws=L"-> ";
00122 
00123         while(*ws!=0 && x<width)
00124           {
00125             win->add_wch(*ws);
00126             x+=wcwidth(*ws);
00127             ++ws;
00128           }
00129 
00130         if(x>=width)
00131           return;
00132 
00133         size_t i=0;
00134         while(i<str.size() && x<width)
00135           {
00136             wchar_t ch=str[i];
00137 
00138             win->add_wch(ch);
00139             x+=wcwidth(ch);
00140             ++i;
00141           }
00142 
00143         while(x<width)
00144           {
00145             win->add_wch(L' ');
00146             x+=wcwidth(L' ');
00147           }
00148       }
00149 
00150       void set_depth(int _depth)
00151       {
00152         for(child_iterator i=children.begin(); i!=children.end(); i++)
00153           (*i)->set_depth(_depth+1);
00154 
00155         treeitem::set_depth(_depth);
00156       }
00157 
00158       void add_child(childtype *newchild)
00159       {
00160         newchild->set_depth(get_depth()+1);
00161 
00162         children.push_back(newchild);
00163       }
00164 
00165       // Adds a new child item at an unspecified location -- you should call sort()
00166       // after adding children or the tree will have an undetermined order.  (yes,
00167       // you can deduce the real order.  Don't.)
00168       void sort(sortpolicy &sort_method)
00169       {
00170         for(child_iterator i=children.begin(); i!=children.end(); i++)
00171           (*i)->sort(sort_method);
00172 
00173         children.sort(sortpolicy_wrapper(sort_method));
00174       }
00175 
00176       void sort()
00177       {
00178         default_sort sorter;
00179         sort(sorter);
00180       }
00181 
00182       virtual bool dispatch_key(const config::key &k, tree *owner)
00183       {
00184         if(tree::bindings->key_matches(k, "ToggleExpanded"))
00185           {
00186             expanded=!expanded;
00187             return true;
00188           }
00189         else if(tree::bindings->key_matches(k, "ExpandTree"))
00190           {
00191             if(!expanded)
00192               {
00193                 expanded=true;
00194                 return true;
00195               }
00196             else
00197               return false;
00198           }
00199         else if(tree::bindings->key_matches(k, "CollapseTree"))
00200           {
00201             if(expanded)
00202               {
00203                 expanded=false;
00204                 return true;
00205               } else
00206               return false;
00207           }
00208         else if(tree::bindings->key_matches(k, "ExpandAll"))
00209           {
00210             expand_all();
00211             return true;
00212           }
00213         else if(tree::bindings->key_matches(k, "CollapseAll"))
00214           {
00215             collapse_all();
00216             return true;
00217           }
00218         return false;
00219       }
00220       // The default action is to expand or shrink the tree when Enter is pressed.
00221       // FIXME: should I use '+' and '-' here?  That would appear to conflict with
00222       // the other keybindings I need.  Hm.
00223 
00224       virtual void dispatch_mouse(short id, int x, mmask_t bstate, tree *owner)
00225       {
00226         if(bstate & (BUTTON1_DOUBLE_CLICKED | BUTTON2_DOUBLE_CLICKED |
00227                      BUTTON3_DOUBLE_CLICKED | BUTTON4_DOUBLE_CLICKED |
00228                      BUTTON1_TRIPLE_CLICKED | BUTTON2_TRIPLE_CLICKED |
00229                      BUTTON3_TRIPLE_CLICKED | BUTTON4_TRIPLE_CLICKED))
00230           expanded=!expanded;
00231       }
00232 
00233       virtual levelref *begin() {return new levelref(children.begin(), &children);}
00234       virtual levelref *end() {return new levelref(children.end(), &children);}
00235 
00236       bool has_visible_children() {return expanded && children.size()>0;}
00237       bool has_children() {return children.size()>0;}
00238 
00239       virtual ~subtree()
00240       {
00241         child_iterator i,j;
00242         for(i=children.begin(); i!=children.end(); i=j)
00243           {
00244             j=i;
00245             j++;
00246             delete *i;
00247           }
00248       }
00249     };
00250 
00251     class subtree_generic:public subtree<treeitem>
00252     {
00253     public:
00254       subtree_generic(int _expanded):subtree<treeitem>(_expanded) {}
00255     };
00256   }
00257 }
00258 
00259 #endif

Generated on Fri Nov 16 03:33:05 2007 for cwidget by  doxygen 1.5.1