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

Generated on Fri Feb 8 12:54:56 2008 for cwidget by  doxygen 1.5.4