libyui-ncurses  2.57.2
NCTree.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  Copyright (C) 2020 SUSE LLC
4  This library is free software; you can redistribute it and/or modify
5  it under the terms of the GNU Lesser General Public License as
6  published by the Free Software Foundation; either version 2.1 of the
7  License, or (at your option) version 3.0 of the License. This library
8  is distributed in the hope that it will be useful, but WITHOUT ANY
9  WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
11  License for more details. You should have received a copy of the GNU
12  Lesser General Public License along with this library; if not, write
13  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
14  Floor, Boston, MA 02110-1301 USA
15 */
16 
17 
18 /*-/
19 
20  File: NCTree.cc
21 
22  Authors: Michael Andres <ma@suse.de>
23  Stefan Hundhammer <shundhammer@suse.de>
24 
25 /-*/
26 
27 #define YUILogComponent "ncurses"
28 #include <yui/YUILog.h>
29 #include "NCTree.h"
30 #include "YNCursesUI.h"
31 
32 #include <yui/TreeItem.h>
33 #include <yui/YSelectionWidget.h>
34 
35 using std::string;
36 using std::endl;
37 
38 
39 NCTree::NCTree( YWidget * parent,
40  const string & nlabel,
41  bool multiselection,
42  bool recursiveselection )
43  : YTree( parent, nlabel, multiselection, recursiveselection )
44  , NCPadWidget( parent )
45  , _multiSelect( multiselection )
46  , _nextItemIndex( 0 )
47 {
48  // yuiDebug() << endl;
49 
50  if ( multiselection && recursiveselection )
51  yuiDebug() << "NCTree recursive multi selection ON" << endl;
52  else if ( multiselection )
53  yuiDebug() << "NCTree multi selection ON" << endl;
54 
55  setLabel( nlabel );
56 }
57 
58 
59 NCTree::~NCTree()
60 {
61 
62 }
63 
64 
65 inline const NCTreeLine *
66 NCTree::getTreeLine( unsigned idx ) const
67 {
68  if ( myPad() )
69  return dynamic_cast<const NCTreeLine *>( myPad()->GetLine( idx ) );
70  else
71  return 0;
72 }
73 
74 
75 inline NCTreeLine *
76 NCTree::modifyTreeLine( unsigned idx )
77 {
78  if ( myPad() )
79  return dynamic_cast<NCTreeLine *>( myPad()->ModifyLine( idx ) );
80  else
81  return 0;
82 }
83 
84 
86 {
87  wsze sze = wsze::max( defsze, wsze( 0, labelWidth() + 2 ) );
88  return sze.W;
89 }
90 
91 
93 {
94  wsze sze = wsze::max( defsze, wsze( 0, labelWidth() + 2 ) );
95  return sze.H;
96 }
97 
98 
99 void NCTree::setEnabled( bool do_bv )
100 {
101  NCWidget::setEnabled( do_bv );
102  YWidget::setEnabled( do_bv );
103 }
104 
105 
106 void NCTree::setSize( int newwidth, int newheight )
107 {
108  wRelocate( wpos( 0 ), wsze( newheight, newwidth ) );
109 }
110 
111 
112 YTreeItem * NCTree::getCurrentItem() const
113 {
114  YTreeItem * yitem = 0;
115 
116  if ( myPad() && myPad()->GetCurrentLine() )
117  {
118  const NCTreeLine * currentLine = dynamic_cast<const NCTreeLine *>( myPad()->GetCurrentLine() );
119 
120  if ( currentLine )
121  yitem = currentLine->YItem();
122  }
123 
124  // yuiDebug() << "-> " << ( yitem ? yitem->label().c_str() : "noitem" ) << endl;
125 
126  return yitem;
127 }
128 
129 
130 void NCTree::deselectAllItems()
131 {
132  if ( _multiSelect )
133  {
134  YItemCollection selectedItems = YTree::selectedItems();
135 
136  for ( YItemConstIterator it = selectedItems.begin(); it != selectedItems.end(); ++it )
137  {
138  selectItem( *it, false );
139  }
140  }
141 
142  YTree::deselectAllItems();
143 }
144 
145 
146 void NCTree::selectItem( YItem * item, bool selected )
147 {
148  if ( !myPad() )
149  return;
150 
151  YTreeItem * treeItem = dynamic_cast<YTreeItem *>( item );
152  YUI_CHECK_PTR( treeItem );
153 
154  YTreeItem * currentItem = getCurrentItem();
155 
156  // retrieve position of the item
157  int at = treeItem->index();
158 
159  NCTreeLine * currentLine = 0;
160  NCTableCol * currentCol = 0;
161 
162  if ( _multiSelect )
163  {
164  currentLine = modifyTreeLine( at );
165 
166  if ( currentLine )
167  {
168  currentCol = currentLine->GetCol(0);
169  }
170  }
171 
172  if ( !selected )
173  {
174  if ( !_multiSelect && ( treeItem == currentItem ) )
175  {
176  YTree::deselectAllItems();
177  }
178  else
179  {
180  YTree::selectItem( treeItem, false );
181 
182  if ( currentCol )
183  {
184  currentCol->setPrefix( currentLine->indentationStr() + "[ ] " );
185  }
186  }
187  }
188  else
189  {
190  YTree::selectItem( treeItem, selected );
191 
192  if ( _multiSelect && currentCol )
193  {
194  currentCol->setPrefix( currentLine->indentationStr() + "[x] " );
195  }
196 
197  // Highlight the selected item and possibly expand the tree if it is in
198  // a currently hidden branch
199 
200  myPad()->ShowItem( getTreeLine( at ) );
201  }
202 }
203 
204 
205 void NCTree::selectItem( int index )
206 {
207  YItem * item = YTree::itemAt( index );
208 
209  if ( item )
210  selectItem( item, true );
211  else
212  YUI_THROW( YUIException( "Can't find selected item" ) );
213 }
214 
215 
216 void NCTree::setLabel( const string & nlabel )
217 {
218  YTree::setLabel( nlabel );
219  NCPadWidget::setLabel( NCstring( nlabel ) );
220 }
221 
222 
224 {
225  DelPad();
226  Redraw();
227 }
228 
229 
231 {
232  wsze psze( defPadSze() );
233  NCPad * npad = new NCTreePad( psze.H, psze.W, *this );
234  npad->bkgd( listStyle().item.plain );
235 
236  return npad;
237 }
238 
239 
241  NCTreePad * pad,
242  YItem * item )
243 {
244  // Set the item index explicitely: It is set to -1 by default which makes
245  // selecting items painful.
246 
247  item->setIndex( _nextItemIndex++ );
248 
249  YTreeItem * treeItem = dynamic_cast<YTreeItem *>( item );
250  YUI_CHECK_PTR( treeItem );
251 
252  NCTreeLine * line = new NCTreeLine( parentLine, treeItem, _multiSelect );
253  pad->Append( line );
254 
255  if ( item->selected() )
256  {
257  // Retrieve the position of the item
258  int at = treeItem->index();
259 
260  NCTreeLine * currentLine = 0;
261  NCTableCol * currentCol = 0;
262 
263  if ( _multiSelect )
264  {
265  currentLine = modifyTreeLine( at );
266 
267  if ( currentLine )
268  currentCol = currentLine->GetCol(0);
269 
270  if ( currentCol )
271  {
272  currentCol->setPrefix( currentLine->indentationStr() + "[x] " );
273  }
274  }
275 
276  // Highlight the selected item and expand the tree if it is in a
277  // currently hidden branch
278 
279  pad->ShowItem( getTreeLine( at ) );
280  }
281 
282  // Recursively create TreeLines for the children of this item
283 
284  for ( YItemIterator it = item->childrenBegin(); it < item->childrenEnd(); ++it )
285  {
286  CreateTreeLines( line, pad, *it );
287  }
288 }
289 
290 
291 YTreeItem * NCTree::currentItem()
292 {
293  return getCurrentItem();
294 }
295 
296 
298 {
299  if ( !myPad() )
300  {
301  yuiWarning() << "PadWidget not yet created" << endl;
302  return;
303  }
304 
305  _nextItemIndex = 0;
306 
307  // Iterate over the toplevel items
308 
309  for ( YItemIterator it = itemsBegin(); it < itemsEnd(); ++it )
310  {
311  // Create a TreeLine for this item.
312  // This will recurse into children if there are any.
313 
314  CreateTreeLines( 0, myPad(), *it );
315  }
316 
317  NCPadWidget::DrawPad();
318 }
319 
320 
322 {
323  NCursesEvent ret = NCursesEvent::none;
324  YTreeItem * oldCurrentItem = getCurrentItem();
325 
326  // Call the pad's input handler via NCPadWidget::handleInput()
327  // which may call its base pad class's input handler
328  // which may call the current item's input handler.
329  //
330  // Notice that most keys are handled on the level of the pad or the item,
331  // not here. See
332  // - NCTreePad::handleInput()
333  // - NCTablePadBase::handleInput()
334  // - NCTreeLine::handleInput()
335  // - NCTableLine::handleInput()
336 
337  bool handled = handleInput( key ); // NCTreePad::handleInput()
338 
339  const YItem * currentItem = getCurrentItem();
340 
341  if ( !currentItem )
342  return ret;
343 
344  if ( _multiSelect )
345  {
346  if ( ! handled )
347  {
348  switch ( key )
349  {
350  // KEY_SPACE is handled in NCTreeLine::handleInput()
351 
352  case KEY_RETURN:
353 
354  if ( currentItem->selected() )
355  selectItem( const_cast<YItem *>(currentItem), false );
356  else
357  selectItem( const_cast<YItem *>(currentItem), true );
358 
359  if ( notify() )
360  return NCursesEvent::ValueChanged;
361 
362  break;
363  }
364  }
365  }
366  else
367  {
368  if ( ! handled )
369  {
370  switch ( key )
371  {
372  // KEY_SPACE is handled in NCTreeLine::handleInput
373  case KEY_RETURN:
374 
375  if ( notify() )
376  return NCursesEvent::Activated;
377 
378  break;
379  }
380  }
381 
382  YTree::selectItem( const_cast<YItem *>( currentItem ), true );
383  }
384 
385  if ( notify() && immediateMode() && ( oldCurrentItem != currentItem ) )
386  ret = NCursesEvent::SelectionChanged;
387 
388  // yuiDebug() << "Notify: " << ( notify() ? "true" : "false" )
389  // << " Return event: " << ret.reason << endl;
390 
391  return ret;
392 }
393 
394 
396 {
397  // Send an activation event for this widget
398 
399  NCursesEvent event = NCursesEvent::Activated;
400  event.widget = this;
401  YNCursesUI::ui()->sendEvent(event);
402 }
403 
404 
406 {
407  YTree::deleteAllItems();
408  myPad()->ClearTable();
409 }
410 
411 
412 //
413 // ----------------------------------------------------------------------
414 //
415 
416 
417 NCTreeLine::NCTreeLine( NCTreeLine * parentLine,
418  YTreeItem * item,
419  bool multiSelection )
420  : NCTableLine( parentLine,
421  item,
422  0, // cols
423  item ? item->index() : -1, // idx
424  true, // nested
425  S_NORMAL ) // lineState
426  , _multiSelect( multiSelection )
427 {
428  if ( _multiSelect )
429  _prefixPlaceholder += item->selected() ? "[x] " : "[ ] ";
430 
431  NCTableCol * cell = new NCTableCol( NCstring( _yitem->label() ) );
432  cell->setPrefix( prefixPlaceholder() );
433  Append( cell );
434 }
435 
436 
437 NCTreeLine::~NCTreeLine()
438 {
439 
440 }
441 
442 
444 {
445  if ( isVisible() )
446  return false; // no status change
447 
448  if ( parent() )
449  {
450  // Make sure the parent is visible.
451  // This recurses upwards until the toplevel.
452 
453  parent()->ChangeToVisible();
454 
455 
456  // Make sure this line and all siblings on this level are visible
457 
458  for ( NCTreeLine * sibling = parent()->firstChild();
459  sibling;
460  sibling = sibling->nextSibling() )
461  {
462  sibling->ClearState( S_HIDDEN );
463  sibling->YItem()->setOpen( true );
464  }
465  }
466  else // No parent (i.e. this is a toplevel item)
467  {
468  // Make sure this item is visible
469 
470  ClearState( S_HIDDEN );
471  YItem()->setOpen( true );
472  }
473 
474  return true; // status change (the line was invisible before)
475 }
476 
477 
478 unsigned NCTreeLine::Hotspot( unsigned & at ) const
479 {
480  return 6;
481 }
482 
483 
484 bool NCTreeLine::handleInput( wint_t key )
485 {
486  bool handled = false;
487 
488  switch ( key )
489  {
490  // At this time, there are no more special keys to handle on this
491  // level. This method is a stub for future extension if any more keys
492  // need to be handled.
493  //
494  // Add 'case KEY_XXX' branches here if there should be any
495  // and don't forget to set 'handled' to 'true'.
496 #if 0
497  case KEY_SOMETHING: // Sample
498  doSomething();
499  handled = true;
500  break;
501 #endif
502 
503  default: // Call parent class input handler
504  handled = NCTableLine::handleInput( key );
505  break;
506  }
507 
508  return handled;
509 }
510 
wsze
Screen dimension (screen size) in the order height, width: (H, W)
Definition: position.h:154
NCstring
A string with an optional hot key.
Definition: NCstring.h:36
NCTree::getTreeLine
const NCTreeLine * getTreeLine(unsigned idx) const
Return a const pointer to the tree line at the specified index for read-only operations.
Definition: NCTree.cc:66
NCTreeLine::handleInput
virtual bool handleInput(wint_t key)
Handle keyboard input.
Definition: NCTree.cc:484
YNCursesUI::ui
static YNCursesUI * ui()
Access the global Y2NCursesUI.
Definition: YNCursesUI.h:93
YNCursesUI::sendEvent
void sendEvent(NCursesEvent event)
Send an event to the UI.
Definition: YNCursesUI.cc:456
NCTablePadBase::ClearTable
void ClearTable()
Clear all content.
Definition: NCTablePadBase.cc:51
NCTableCol
One cell in an NCTableLine with a label and a cell-specific style.
Definition: NCTableItem.h:422
NCTreePad
An NCPad for an NCTree.
Definition: NCTreePad.h:50
NCTreeLine::ChangeToVisible
virtual bool ChangeToVisible()
Change a line that may have been invisible until now to be visible.
Definition: NCTree.cc:443
NCTree::setLabel
virtual void setLabel(const std::string &nlabel)
Set the label (the caption) above the tree.
Definition: NCTree.cc:216
NCWidget::setEnabled
virtual void setEnabled(bool do_bv)=0
Pure virtual to make sure every widget implements it.
Definition: NCWidget.cc:392
NCTablePadBase::GetCurrentLine
NCTableLine * GetCurrentLine() const
Return the current line (the line at the cursor position) or 0 if there is none.
Definition: NCTablePadBase.cc:444
NCTree::deleteAllItems
virtual void deleteAllItems()
Delete all items and clear the TreePad.
Definition: NCTree.cc:405
NCTablePadBase::Append
void Append(NCTableLine *item)
Add one item to the end of _items.
Definition: NCTablePadBase.h:147
NCTreeLine::YItem
YTreeItem * YItem() const
Return the corresponding YTreeItem.
Definition: NCTree.h:276
NCTableLine::indentationStr
std::string indentationStr() const
Return a string of a number of blanks suitable for the indentation of this tree level.
Definition: NCTableItem.cc:173
NCTree::myPad
virtual NCTreePad * myPad() const
Return the TreePad that belongs to this widget.
Definition: NCTree.h:186
NCTablePadBase::ModifyLine
NCTableLine * ModifyLine(unsigned idx)
Return line at idx for read-write operations and mark it as modified.
Definition: NCTablePadBase.cc:93
NCTablePadBase::GetLine
const NCTableLine * GetLine(unsigned idx) const
Return the line at idx for read-only operations.
Definition: NCTablePadBase.cc:87
NCPad
A virtual window with a real viewport (which is NCursesWindow) and a scrolling mechanism.
Definition: NCPad.h:113
NCTree::selectItem
virtual void selectItem(YItem *item, bool selected)
Select or deselect an item.
Definition: NCTree.cc:146
NCTreeLine
One line in a tree widdget.
Definition: NCTree.h:262
NCTree::DrawPad
virtual void DrawPad()
Fill the TreePad with lines (using CreateTreeLines to create them)
Definition: NCTree.cc:297
wpos
Screen position pair in the order line, column: (L, C)
Definition: position.h:110
NCTree::rebuildTree
virtual void rebuildTree()
Recursively build the tree in this widget according to the items.
Definition: NCTree.cc:223
NCTree::preferredWidth
virtual int preferredWidth()
libyui geometry management: Return the preferred width for this widget.
Definition: NCTree.cc:85
NCTree::currentItem
virtual YTreeItem * currentItem()
Get the current item.
Definition: NCTree.cc:291
NCTree::setSize
virtual void setSize(int newWidth, int newHeight)
libyui geometry management: Apply the width and height assigned from the parent layout widget.
Definition: NCTree.cc:106
NCursesWindow::bkgd
int bkgd(const chtype ch)
Set the background property and apply it to the window.
Definition: ncursesw.h:1445
NCTree::activate
virtual void activate()
Activate the item selected in the tree.
Definition: NCTree.cc:395
NCTableLine::GetCol
NCTableCol * GetCol(unsigned idx)
Return a non-const pointer for read/write operations to the column (the cell) with the specified inde...
Definition: NCTableItem.cc:293
NCTree::getCurrentItem
virtual YTreeItem * getCurrentItem() const
Return a pointer to the current item (the item under the cursor).
Definition: NCTree.cc:112
NCTree::CreateTreeLines
void CreateTreeLines(NCTreeLine *parentLine, NCTreePad *pad, YItem *item)
Create TreeLines and append them to the TreePad.
Definition: NCTree.cc:240
NCTableLine
One line in a NCTable with multiple cells and an optional tree hierarchy.
Definition: NCTableItem.h:68
NCTree::setEnabled
virtual void setEnabled(bool do_bv)
Enable or disable this widget.
Definition: NCTree.cc:99
NCTree::wHandleInput
virtual NCursesEvent wHandleInput(wint_t key)
Keyboard input handler.
Definition: NCTree.cc:321
NCTree::CreatePad
virtual NCPad * CreatePad()
Create an empty pad.
Definition: NCTree.cc:230
NCursesEvent
Definition: NCurses.h:73
NCTableLine::handleInput
virtual bool handleInput(wint_t key)
Handle keyboard input.
Definition: NCTableItem.cc:472
NCTree::modifyTreeLine
NCTreeLine * modifyTreeLine(unsigned idx)
Return a non-const pointer to the tree line at the specified index for read-write operations.
Definition: NCTree.cc:76
NCPadWidget
Base class for widgets with scrollable contents.
Definition: NCPadWidget.h:40
NCTree::preferredHeight
virtual int preferredHeight()
libyui geometry management: Return the preferred height for this widget.
Definition: NCTree.cc:92