libyui-ncurses  2.44.1
 All Classes Functions Variables
NCTree.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: NCTree.cc
20 
21  Author: Michael Andres <ma@suse.de>
22 
23 /-*/
24 
25 #define YUILogComponent "ncurses"
26 #include <yui/YUILog.h>
27 #include "NCTree.h"
28 
29 #include <yui/TreeItem.h>
30 #include <yui/YSelectionWidget.h>
31 
32 
33 class NCTreeLine : public NCTableLine
34 {
35 
36 private:
37 
38  YTreeItem * yitem;
39  const unsigned level;
40 
41  NCTreeLine * parent;
42  NCTreeLine * nsibling;
43  NCTreeLine * fchild;
44 
45  mutable chtype * prefix;
46  bool multiSel;
47  unsigned prefixLen() const { return level + 3; }
48 
49 public:
50 
51  NCTreeLine( NCTreeLine * p, YTreeItem * item, bool multiSelection )
52  : NCTableLine( 0 )
53  , yitem( item )
54  , level( p ? p->level + 1 : 0 )
55  , parent( p )
56  , nsibling( 0 )
57  , fchild( 0 )
58  , prefix( 0 )
59  , multiSel( multiSelection )
60  {
61  if ( parent )
62  {
63  if ( parent->fchild )
64  {
65  NCTreeLine * s = parent->fchild;
66 
67  for ( ; s->nsibling; s = s->nsibling )
68  ;
69 
70  s->nsibling = this;
71  }
72  else
73  {
74  parent->fchild = this;
75  }
76 
77  if ( !parent->yitem->isOpen() )
78  {
79  SetState( S_HIDDEN );
80  }
81  }
82 
83  if ( !multiSel )
84  {
85  Append( new NCTableCol( NCstring( std::string( prefixLen(), ' ' )
86  + yitem->label() ) ) );
87  }
88  else
89  {
90  Append( new NCTableCol( NCstring( std::string( prefixLen(), ' ' ) + "[ ] "
91  + yitem->label() ) ) );
92  }
93  }
94 
95  virtual ~NCTreeLine() { delete [] prefix; }
96 
97 public:
98 
99  YTreeItem * YItem() const { return yitem; }
100 
101  unsigned Level() const { return level; }
102 
103  virtual bool isVisible() const
104  {
105  return !parent || ( !isHidden() && parent->isVisible() );
106  }
107 
108 
109  virtual int ChangeToVisible()
110  {
111  if ( isVisible() )
112  return 0;
113 
114  if ( parent )
115  {
116  parent->ChangeToVisible();
117 
118  for ( NCTreeLine * c = parent->fchild; c; c = c->nsibling )
119  {
120  c->ClearState( S_HIDDEN );
121  c->YItem()->setOpen( true );
122  }
123  }
124  else
125  {
126  ClearState( S_HIDDEN );
127  yitem->setOpen( true );
128  }
129 
130  return 1;
131  }
132 
133 
134  virtual unsigned Hotspot( unsigned & at ) const
135  {
136  at = Level();
137  return 6;
138  }
139 
140 
141  virtual int handleInput( wint_t key )
142  {
143  if ( !fchild )
144  return 0;
145 
146  switch ( key )
147  {
148  case KEY_IC:
149  case '+':
150  if ( fchild->isVisible() )
151  return 0;
152 
153  break;
154 
155  case KEY_DC:
156  case '-':
157  if ( !fchild->isVisible() )
158  return 0;
159 
160  break;
161 
162  case KEY_SPACE:
163  // case KEY_RETURN: see bug 67350
164 
165  break;
166 
167  default:
168  return 0;
169 
170  break;
171  }
172 
173  if ( fchild->isVisible() )
174  {
175  yitem->setOpen( false );
176  yuiMilestone() << "Closing item " << yitem->label() << std::endl;
177 
178  for ( NCTreeLine * c = fchild; c; c = c->nsibling )
179  c->SetState( S_HIDDEN );
180  }
181  else
182  {
183  yitem->setOpen( true );
184  yuiMilestone() << "Opening item " << yitem->label() << std::endl;
185 
186  for ( NCTreeLine * c = fchild; c; c = c->nsibling )
187  c->ClearState( S_HIDDEN );
188  }
189 
190  return 1;
191  }
192 
193 
194  virtual void DrawAt( NCursesWindow & w, const wrect at,
195  NCTableStyle & tableStyle,
196  bool active ) const
197  {
198 
199  NCTableLine::DrawAt( w, at, tableStyle, active );
200 
201  if ( !isSpecial() )
202  w.bkgdset( tableStyle.getBG( vstate, NCTableCol::SEPARATOR ) );
203 
204  if ( ! prefix )
205  {
206  prefix = new chtype[prefixLen()];
207  chtype * tagend = &prefix[prefixLen()-1];
208  *tagend-- = ACS_HLINE;
209  *tagend-- = fchild ? ACS_TTEE : ACS_HLINE;
210 
211  if ( parent )
212  {
213  *tagend-- = nsibling ? ACS_LTEE : ACS_LLCORNER;
214 
215  for ( NCTreeLine * p = parent; p; p = p->parent )
216  {
217  *tagend-- = p->nsibling ? ACS_VLINE : ( ' '&A_CHARTEXT );
218  }
219  }
220  else
221  {
222  *tagend-- = ACS_HLINE;
223  }
224  }
225 
226  w.move( at.Pos.L, at.Pos.C );
227 
228  unsigned i = 0;
229 
230  for ( ; i < prefixLen(); ++i )
231  w.addch( prefix[i] );
232 
233  w.move( at.Pos.L, at.Pos.C + prefixLen() - 2 );
234 
235  if ( fchild && !isSpecial() )
236  w.bkgdset( tableStyle.highlightBG( vstate, NCTableCol::HINT,
237  NCTableCol::SEPARATOR ) );
238 
239  if ( fchild && !fchild->isVisible() )
240  w.addch( '+' );
241  else
242  w.addch( prefix[prefixLen() - 2] );
243  }
244 };
245 
246 
247 
248 
249 
250 
251 NCTree::NCTree( YWidget * parent, const std::string & nlabel, bool multiselection, bool recursiveselection )
252  : YTree( parent, nlabel, multiselection, recursiveselection )
253  , NCPadWidget( parent )
254  , multiSel ( multiselection )
255 {
256  yuiDebug() << std::endl;
257 
258  if ( multiselection && recursiveselection )
259  yuiMilestone() << "NCTree recursive multi selection ON" << std::endl;
260  else if ( multiselection )
261  yuiMilestone() << "NCTree multi selection ON" << std::endl;
262 
263  setLabel( nlabel );
264 }
265 
266 
267 
268 NCTree::~NCTree()
269 {
270  yuiDebug() << std::endl;
271 }
272 
273 
274 
275 
276 // Return pointer to tree line at given index
277 inline const NCTreeLine * NCTree::getTreeLine( unsigned idx ) const
278 {
279  if ( myPad() )
280  return dynamic_cast<const NCTreeLine *>( myPad()->GetLine( idx ) );
281  else
282  return 0;
283 }
284 
285 
286 
287 
288 // Modify tree line at given index
289 inline NCTreeLine * NCTree::modifyTreeLine( unsigned idx )
290 {
291  if ( myPad() )
292  {
293  return dynamic_cast<NCTreeLine *>( myPad()->ModifyLine( idx ) );
294  }
295 
296  return 0;
297 }
298 
299 
300 
301 
302 // Set preferred width
303 int NCTree::preferredWidth()
304 {
305  wsze sze = wsze::max( defsze, wsze( 0, labelWidth() + 2 ) );
306  return sze.W;
307 }
308 
309 
310 
311 
312 // Set preferred height
313 int NCTree::preferredHeight()
314 {
315  wsze sze = wsze::max( defsze, wsze( 0, labelWidth() + 2 ) );
316  return sze.H;
317 }
318 
319 
320 
321 
322 // Enable/disable widget
323 void NCTree::setEnabled( bool do_bv )
324 {
325  NCWidget::setEnabled( do_bv );
326  YWidget::setEnabled( do_bv );
327 }
328 
329 
330 
331 
332 void NCTree::setSize( int newwidth, int newheight )
333 {
334  wRelocate( wpos( 0 ), wsze( newheight, newwidth ) );
335 }
336 
337 
338 
339 
340 // Return YTreeItem pointer for a current line
341 // (under the cursor)
342 YTreeItem * NCTree::getCurrentItem() const
343 {
344  YTreeItem * yitem = 0;
345 
346  if ( myPad() )
347  {
348  const NCTreeLine * cline = dynamic_cast<const NCTreeLine *>( myPad()->GetCurrentLine() );
349 
350  if ( cline )
351  yitem = cline->YItem();
352  }
353 
354  yuiDebug() << "-> " << ( yitem ? yitem->label().c_str() : "noitem" ) << std::endl;
355 
356  return yitem;
357 }
358 
359 void NCTree::deselectAllItems()
360 {
361  if ( multiSel)
362  {
363  YItemCollection selectedItems = YTree::selectedItems();
364 
365  for ( YItemConstIterator it = selectedItems.begin(); it != selectedItems.end(); ++it )
366  {
367  selectItem( *it, false );
368  }
369  }
370 
371  YTree::deselectAllItems();
372 }
373 
374 
375 // Set current item (under the cursor) to selected
376 void NCTree::selectItem( YItem *item, bool selected )
377 {
378  if ( !myPad() )
379  return;
380 
381  YTreeItem * treeItem = dynamic_cast<YTreeItem *>( item );
382  YUI_CHECK_PTR( treeItem );
383  YTreeItem *citem = getCurrentItem();
384 
385  //retrieve position of item
386  int at = treeItem->index();
387 
388  NCTreeLine * cline = 0; // current line
389  NCTableCol * ccol = 0; // current column
390 
391  if ( multiSel )
392  {
393  cline = modifyTreeLine( at );
394  if ( cline )
395  {
396  ccol = cline->GetCol(0);
397  }
398  }
399 
400  if ( !selected )
401  {
402  if ( !multiSel && (treeItem == citem) )
403  {
404  YTree::deselectAllItems();
405  }
406  else
407  {
408  YTree::selectItem ( treeItem, false );
409  if ( ccol )
410  {
411  ccol->SetLabel( NCstring( std::string( cline->Level() + 3, ' ' ) + "[ ] "
412  + item->label() ) );
413  }
414  }
415  }
416  else
417  {
418  YTree::selectItem( treeItem, selected );
419 
420  if ( multiSel && ccol )
421  {
422  ccol->SetLabel( NCstring( std::string( cline->Level() + 3, ' ' ) + "[x] "
423  + item->label() ) );
424  }
425 
426  //this highlights selected item, possibly unpacks the tree
427  //should it be in currently hidden branch
428  myPad()->ShowItem( getTreeLine( at ) );
429  }
430 }
431 
432 
433 
434 
435 // Set current item (at given index) to selected
436 // (overloaded for convenience)
437 void NCTree::selectItem( int index )
438 {
439  YItem * item = YTree::itemAt( index );
440 
441  if ( item )
442  {
443  selectItem( item, true );
444  }
445  else
446  YUI_THROW( YUIException( "Can't find selected item" ) );
447 }
448 
449 
450 
451 void NCTree::setLabel( const std::string & nlabel )
452 {
453  YTree::setLabel( nlabel );
454  NCPadWidget::setLabel( NCstring( nlabel ) );
455 }
456 
457 
458 
459 void NCTree::rebuildTree()
460 {
461  DelPad();
462  Redraw();
463 }
464 
465 
466 
467 
468 // Creates empty pad
469 NCPad * NCTree::CreatePad()
470 {
471  wsze psze( defPadSze() );
472  NCPad * npad = new NCTreePad( psze.H, psze.W, *this );
473  npad->bkgd( listStyle().item.plain );
474  return npad;
475 }
476 
477 
478 // Creates tree lines and appends them to TreePad
479 // (called recursively for each child of an item)
480 void NCTree::CreateTreeLines( NCTreeLine * parentLine, NCTreePad * pad, YItem * item )
481 {
482  //set item index explicitely, it is set to -1 by default
483  //which makes selecting items painful
484  item->setIndex( idx++ );
485 
486  YTreeItem * treeItem = dynamic_cast<YTreeItem *>( item );
487  YUI_CHECK_PTR( treeItem );
488 
489  NCTreeLine * line = new NCTreeLine( parentLine, treeItem, multiSel );
490  pad->Append( line );
491 
492  // iterate over children
493 
494  for ( YItemIterator it = item->childrenBegin(); it < item->childrenEnd(); ++it )
495  {
496  CreateTreeLines( line, pad, *it );
497  }
498 }
499 
500 // Returns current item (pure virtual in YTree)
501 YTreeItem * NCTree::currentItem()
502 {
503  return getCurrentItem();
504 }
505 
506 // Fills TreePad with lines (uses CreateTreeLines to create them)
507 void NCTree::DrawPad()
508 {
509  if ( !myPad() )
510  {
511  yuiWarning() << "PadWidget not yet created" << std::endl;
512  return;
513  }
514 
515  idx = 0;
516  // YItemIterator iterates over the toplevel items
517  for ( YItemIterator it = itemsBegin(); it < itemsEnd(); ++it )
518  {
519  CreateTreeLines( 0, myPad(), *it );
520  }
521 
522  idx = 0;
523  NCPadWidget::DrawPad();
524 }
525 
526 
527 
528 NCursesEvent NCTree::wHandleInput( wint_t key )
529 {
530  NCursesEvent ret = NCursesEvent::none;
531  YTreeItem * oldCurrentItem = getCurrentItem();
532 
533  bool handled = handleInput( key ); // NCTreePad::handleInput()
534  const YItem * currentItem = getCurrentItem();
535 
536  if ( !currentItem )
537  return ret;
538 
539  if ( multiSel )
540  {
541  if ( ! handled )
542  {
543  switch ( key )
544  {
545  // KEY_SPACE is handled in NCTreeLine::handleInput
546  case KEY_RETURN:
547 
548  if ( currentItem->selected() )
549  selectItem( const_cast<YItem *>(currentItem), false );
550  else
551  selectItem( const_cast<YItem *>(currentItem), true );
552 
553  if ( notify() )
554  {
555  return NCursesEvent::ValueChanged;
556  }
557  break;
558  }
559  }
560  }
561  else
562  {
563  if ( ! handled )
564  {
565  switch ( key )
566  {
567  // KEY_SPACE is handled in NCTreeLine::handleInput
568  case KEY_RETURN:
569 
570  if ( notify() )
571  {
572  return NCursesEvent::Activated;
573  }
574  break;
575  }
576  }
577 
578  YTree::selectItem( const_cast<YItem *>( currentItem ), true );
579  }
580 
581  if ( notify() && immediateMode() && ( oldCurrentItem != currentItem ) )
582  ret = NCursesEvent::SelectionChanged;
583 
584  yuiDebug() << "Notify: " << ( notify() ? "true" : "false" ) <<
585  " Return event: " << ret.reason << std::endl;
586 
587  return ret;
588 }
589 
590 
591 
592 
593 
594 // clears the table and the lists holding
595 // the values
596 void NCTree::deleteAllItems()
597 {
598  YTree::deleteAllItems();
599  myPad()->ClearTable();
600 }
C++ class for windows.
Definition: ncursesw.h:904
virtual NCTreePad * myPad() const
Definition: NCTree.h:53
int bkgd(const chtype ch)
Definition: ncursesw.h:1443
void bkgdset(chtype ch)
Definition: ncursesw.h:1448
Definition: NCPad.h:93
Definition: position.h:109
int addch(const char ch)
Definition: ncursesw.h:1228
int move(int y, int x)
Definition: ncursesw.h:1155
virtual void setEnabled(bool do_bv)=0
Definition: NCWidget.cc:391
virtual void setEnabled(bool do_bv)
Definition: NCTree.cc:323
Definition: position.h:154