libyui-ncurses  2.55.0
NCTable.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: NCTable.cc
20 
21  Author: Michael Andres <ma@suse.de>
22 
23 /-*/
24 
25 #define YUILogComponent "ncurses"
26 #include <yui/YUILog.h>
27 #include "NCTable.h"
28 #include "NCPopupMenu.h"
29 #include <yui/YMenuButton.h>
30 #include <yui/YTypes.h>
31 
32 using std::endl;
33 
34 /*
35  * Some remarks about single/multi selection:
36  * A table in single selection mode has only one line/item selected which is equal to the
37  * current item (means the highlighted line). Asking for `CurrentItem in YCP looks for
38  * selectedItem() (see YCPPropertyHandler::tryGetSelectionWidgetValue).
39  * In multi selection mode there can be several items selected (here is means checked/marked
40  * with [x]) and the value is also got from selectedItem() when asking for `SelectedItems
41  * (see YCPPropertyHandler::tryGetSelectionWidgetValue).
42  * This means for multi selection mode: at the moment there isn't a possibility to get the
43  * `CurrentItem. To get the current item (which line of the list is currently highlighted),
44  * a virtual function currentItem() like available for the MultiSelectionBox has to be
45  * provided to allow NCTable to specify the line number itself (getCurrentItem).
46  *
47  */
48 NCTable::NCTable( YWidget * parent, YTableHeader *tableHeader, bool multiSelection )
49  : YTable( parent, tableHeader, multiSelection )
50  , NCPadWidget( parent )
51  , biglist( false )
52  , multiselect( multiSelection )
53 {
54  yuiDebug() << std::endl;
55 
56  InitPad();
57  // !!! head is UTF8 encoded, thus should be std::vector<NCstring>
58  if ( !multiselect )
59  {
60  _header.assign( tableHeader->columns(), NCstring( "" ) );
61  for ( int col = 0; col < tableHeader->columns(); col++ )
62  {
63  if ( hasColumn( col ) )
64  {
65  // set alignment first
66  setAlignment( col, alignment( col ) );
67  // and then append header
68  _header[ col ] += NCstring( tableHeader->header( col ) ) ;
69  }
70  }
71  }
72  else
73  {
74  _header.assign( tableHeader->columns()+1, NCstring( "" ) );
75 
76  for ( int col = 1; col <= tableHeader->columns(); col++ )
77  {
78  if ( hasColumn( col-1 ) )
79  {
80  // set alignment first
81  setAlignment( col, alignment( col-1 ) );
82  // and then append header
83  _header[ col ] += NCstring( tableHeader->header( col-1 ) ) ;
84  }
85  }
86  }
87 
88  hasHeadline = myPad()->SetHeadline( _header );
89 
90 }
91 
92 
93 
94 
95 NCTable::~NCTable()
96 {
97  yuiDebug() << std::endl;
98 }
99 
100 
101 
102 // Change individual cell of a table line (to newtext)
103 // provided for backwards compatibility
104 
105 void NCTable::cellChanged( int index, int colnum, const std::string & newtext )
106 {
107  NCTableLine * cl = myPad()->ModifyLine( index );
108 
109  if ( !cl )
110  {
111  yuiWarning() << "No such line: " << wpos( index, colnum ) << newtext << std::endl;
112  }
113  else
114  {
115  NCTableCol * cc = cl->GetCol( colnum );
116 
117  if ( !cc )
118  {
119  yuiWarning() << "No such colnum: " << wpos( index, colnum ) << newtext << std::endl;
120  }
121  else
122  {
123  // use NCtring to enforce recoding from 'utf8'
124  cc->SetLabel( NCstring( newtext ) );
125  DrawPad();
126  }
127  }
128 }
129 
130 
131 
132 // Change individual cell of a table line (to newtext)
133 
134 void NCTable::cellChanged( const YTableCell *cell )
135 {
136 
137  cellChanged( cell->itemIndex(), cell->column(), cell->label() );
138 
139 }
140 
141 
142 
143 // Set all table headers all at once
144 
145 void NCTable::setHeader( const std::vector<std::string>& head )
146 {
147  _header.assign( head.size(), NCstring( "" ) );
148  YTableHeader *th = new YTableHeader();
149 
150  for ( unsigned int i = 0; i < head.size(); i++ )
151  {
152  th->addColumn( head[ i ] );
153  _header[ i ] += NCstring( head[ i ] ) ;
154  }
155 
156  hasHeadline = myPad()->SetHeadline( _header );
157 
158  YTable::setTableHeader( th );
159 }
160 
161 //
162 // Return table header as std::string std::vector (alignment removed)
163 //
164 std::vector<std::string> NCTable::getHeader( ) const
165 {
166  std::vector<std::string> header;
167 
168  header.assign( _header.size(), "" );
169 
170  for ( unsigned int i = 0; i < _header.size(); i++ )
171  {
172  header[ i ] = _header[i].Str().substr( 1 ); // remove alignment
173  }
174 
175  return header;
176 }
177 
178 
179 // Set alignment of i-th table column (left, right, center).
180 // Create temp. header consisting of single letter;
181 // setHeader will append the rest.
182 
183 void NCTable::setAlignment( int col, YAlignmentType al )
184 {
185  std::string s;
186 
187  switch ( al )
188  {
189  case YAlignUnchanged:
190  s = 'L' ;
191  break;
192 
193  case YAlignBegin:
194  s = 'L' ;
195  break;
196 
197  case YAlignCenter:
198  s = 'C' ;
199  break;
200 
201  case YAlignEnd:
202  s = 'R' ;
203  break;
204  }
205 
206  _header[ col ] = NCstring( s );
207 }
208 
209 // Append item (as pointed to by 'yitem') in one-by-one
210 // fashion i.e. the whole table gets redrawn afterwards.
211 void NCTable::addItem( YItem *yitem)
212 {
213  addItem(yitem, false); // add just this one
214 }
215 
216 // Append item (as pointed to by 'yitem') to a table.
217 // This creates visual representation of new table line
218 // consisting of individual cells. Depending on the 2nd
219 // param, table is redrawn. If 'allAtOnce' is set to
220 // true, it is up to the caller to redraw the table.
221 void NCTable::addItem( YItem *yitem, bool allAtOnce )
222 {
223 
224  YTableItem *item = dynamic_cast<YTableItem *>( yitem );
225  YUI_CHECK_PTR( item );
226  YTable::addItem( item );
227  unsigned int itemCount;
228 
229  if ( !multiselect )
230  itemCount = item->cellCount();
231  else
232  itemCount = item->cellCount()+1;
233 
234  std::vector<NCTableCol*> Items( itemCount );
235  unsigned int i = 0;
236 
237  if ( !multiselect )
238  {
239  // Iterate over cells to create columns
240  for ( YTableCellIterator it = item->cellsBegin();
241  it != item->cellsEnd();
242  ++it )
243  {
244  Items[i] = new NCTableCol( NCstring(( *it )->label() ) );
245  i++;
246  }
247  }
248  else
249  {
250  // Create the tag first
251  Items[0] = new NCTableTag( yitem, yitem->selected() );
252  i++;
253  // and then iterate over cells
254  for ( YTableCellIterator it = item->cellsBegin();
255  it != item->cellsEnd();
256  ++it )
257  {
258  Items[i] = new NCTableCol( NCstring(( *it )->label() ) );
259  i++;
260  }
261  }
262 
263  //Insert @idx
264  NCTableLine *newline = new NCTableLine( Items, item->index() );
265 
266  YUI_CHECK_PTR( newline );
267 
268  newline->setOrigItem( item );
269 
270  myPad()->Append( newline );
271 
272  if ( item->selected() )
273  {
274  setCurrentItem( item->index() ) ;
275  }
276 
277  //in one-by-one mode, redraw the table (otherwise, leave it
278  //up to the caller)
279  if (!allAtOnce)
280  {
281  DrawPad();
282  }
283 }
284 
285 // reimplemented here to speed up item insertion
286 // (and prevent inefficient redrawing after every single addItem
287 // call)
288 void NCTable::addItems( const YItemCollection & itemCollection )
289 {
290 
291  for ( YItemConstIterator it = itemCollection.begin();
292  it != itemCollection.end();
293  ++it )
294  {
295  addItem( *it, true);
296  }
297 
298  if ( !keepSorting() )
299  {
300  myPad()->sort();
301 
302  if (!multiselect)
303  selectCurrentItem();
304  }
305 
306  DrawPad();
307 }
308 
309 // Clear the table (in terms of YTable and visually)
310 
311 void NCTable::deleteAllItems()
312 {
313  myPad()->ClearTable();
314  DrawPad();
315  YTable::deleteAllItems();
316 }
317 
318 
319 
320 // Return index of currently selected table item
321 
322 int NCTable::getCurrentItem() const
323 {
324  if ( !myPad()->Lines() )
325  return -1;
326 
327  return keepSorting() ? myPad()->GetLine( myPad()->CurPos().L )->getIndex()
328  : myPad()->CurPos().L;
329 }
330 
331 
332 
333 // Return origin pointer of currently selected table item
334 
335 YItem * NCTable::getCurrentItemPointer()
336 {
337  const NCTableLine *cline = myPad()->GetLine( myPad()->CurPos().L );
338 
339  if ( cline )
340  return cline->origItem();
341  else
342  return 0;
343 }
344 
345 
346 
347 // Highlight item at 'index'
348 
349 void NCTable::setCurrentItem( int index )
350 {
351  myPad()->ScrlLine( index );
352 }
353 
354 
355 
356 // Mark table item (as pointed to by 'yitem') as selected
357 
358 void NCTable::selectItem( YItem *yitem, bool selected )
359 {
360  if ( ! yitem )
361  return;
362 
363  YTableItem *item = dynamic_cast<YTableItem *>( yitem );
364  YUI_CHECK_PTR( item );
365 
366  NCTableLine *line = ( NCTableLine * )item->data();
367  YUI_CHECK_PTR( line );
368 
369  const NCTableLine *current_line = myPad()->GetLine( myPad()->CurPos().L );
370  YUI_CHECK_PTR( current_line );
371 
372  if ( !multiselect )
373  {
374  if ( !selected && ( line == current_line ) )
375  {
376  deselectAllItems();
377  }
378  else
379  {
380  // first highlight only, then select
381  setCurrentItem( line->getIndex() );
382  YTable::selectItem( item, selected );
383  }
384  }
385  else
386  {
387  YTable::selectItem( item, selected );
388 
389  yuiDebug() << item->label() << " is selected: " << (selected?"yes":"no") << endl;
390 
391  NCTableTag *tag = static_cast<NCTableTag *>( line->GetCol( 0 ) );
392  tag->SetSelected( selected );
393  }
394 
395  // and redraw
396  DrawPad();
397 }
398 
399 
400 
401 // Mark currently highlighted table item as selected
402 // Yeah, it is really already highlighted, so no need to
403 // selectItem() and setCurrentItem() here again - #493884
404 
405 void NCTable::selectCurrentItem()
406 {
407  const NCTableLine *cline = myPad()->GetLine( myPad()->CurPos().L );
408 
409  if ( cline )
410  YTable::selectItem( cline->origItem(), true );
411 }
412 
413 
414 
415 // Mark all items as deselected
416 
417 void NCTable::deselectAllItems()
418 {
419  if ( !multiselect )
420  {
421  setCurrentItem( -1 );
422  YTable::deselectAllItems();
423  }
424  else
425  {
426  YItemCollection itemCollection = YTable::selectedItems();
427  for ( YItemConstIterator it = itemCollection.begin();
428  it != itemCollection.end(); ++it )
429  {
430  selectItem( *it, false ); // YTable::selectItem(item,false)
431  }
432  }
433 
434  DrawPad();
435 }
436 
437 
438 
439 // return preferred size
440 
441 int NCTable::preferredWidth()
442 {
443  wsze sze = ( biglist ) ? myPad()->tableSize() + 2 : wGetDefsze();
444  return sze.W;
445 }
446 
447 
448 
449 // return preferred size
450 
451 int NCTable::preferredHeight()
452 {
453  wsze sze = ( biglist ) ? myPad()->tableSize() + 2 : wGetDefsze();
454  return sze.H;
455 }
456 
457 
458 
459 // Set new size of the widget
460 
461 void NCTable::setSize( int newwidth, int newheight )
462 {
463  wRelocate( wpos( 0 ), wsze( newheight, newwidth ) );
464 }
465 
466 
467 
468 
469 void NCTable::setLabel( const std::string & nlabel )
470 {
471  // not implemented: YTable::setLabel( nlabel );
472  NCPadWidget::setLabel( NCstring( nlabel ) );
473 }
474 
475 
476 
477 // Set widget state (enabled vs. disabled)
478 
479 void NCTable::setEnabled( bool do_bv )
480 {
481  NCWidget::setEnabled( do_bv );
482  YTable::setEnabled( do_bv );
483 }
484 
485 
486 
487 
488 bool NCTable::setItemByKey( int key )
489 {
490  return myPad()->setItemByKey( key );
491 }
492 
493 
494 
495 
496 
497 // Create new NCTablePad, set its background
498 NCPad * NCTable::CreatePad()
499 {
500  wsze psze( defPadSze() );
501  NCPad * npad = new NCTablePad( psze.H, psze.W, *this );
502  npad->bkgd( listStyle().item.plain );
503 
504  return npad;
505 }
506 
507 
508 
509 // Handle 'special' keys i.e those not handled by parent NCPad class
510 // (space, return). Set items to selected, if appropriate.
511 
512 NCursesEvent NCTable::wHandleInput( wint_t key )
513 {
514  NCursesEvent ret;
515  int citem = getCurrentItem();
516  bool sendEvent = false;
517 
518  if ( ! handleInput( key ) )
519  {
520  switch ( key )
521  {
522  case CTRL( 'o' ):
523  {
524  if ( ! keepSorting() )
525  {
526  // get the column - show popup in upper left corner
527  wpos at( ScreenPos() + wpos( 2, 1 ) );
528 
529  YItemCollection ic;
530  ic.reserve( _header.size() );
531  unsigned int i = 0;
532 
533  for ( std::vector<NCstring>::const_iterator it = _header.begin();
534  it != _header.end() ; it++, i++ )
535  {
536  // strip the align mark
537  std::string col = ( *it ).Str();
538  col.erase( 0, 1 );
539 
540  YMenuItem *item = new YMenuItem( col ) ;
541  //need to set index explicitly, MenuItem inherits from TreeItem
542  //and these don't have indexes set
543  item->setIndex( i );
544  ic.push_back( item );
545  }
546 
547  NCPopupMenu *dialog = new NCPopupMenu( at, ic.begin(), ic.end() );
548 
549  int column = dialog->post();
550 
551  if ( column != -1 )
552  {
553  myPad()->setOrder( column, true ); //enable sorting in reverse order
554 
555  if (!multiselect)
556  selectCurrentItem();
557  }
558 
559  //remove the popup
560  YDialog::deleteTopmostDialog();
561 
562  return NCursesEvent::none;
563  }
564  }
565 
566  case KEY_RETURN:
567  sendEvent = true;
568  case KEY_SPACE:
569  if ( !multiselect )
570  {
571  if ( notify() && citem != -1 )
572  return NCursesEvent::Activated;
573  }
574  else
575  {
576  toggleCurrentItem();
577  // send ValueChanged on Return (like done for NCTree multiSelection)
578  if ( notify() && sendEvent )
579  {
580  return NCursesEvent::ValueChanged;
581  }
582  }
583  break;
584 
585  }
586  }
587 
588 
589  if ( citem != getCurrentItem() )
590  {
591  if ( notify() && immediateMode() )
592  ret = NCursesEvent::SelectionChanged;
593 
594  if ( !multiselect )
595  selectCurrentItem();
596  }
597 
598  return ret;
599 }
600 
601 /**
602  * Toggle item from selected -> deselected and vice versa
603  **/
605 {
606  YTableItem *it = dynamic_cast<YTableItem *>( getCurrentItemPointer() );
607  if ( it )
608  {
609  selectItem( it, !( it->selected() ) );
610  }
611 }
wsze
Definition: position.h:155
NCstring
Definition: NCstring.h:33
NCTableCol
Definition: NCTableItem.h:147
NCWidget::setEnabled
virtual void setEnabled(bool do_bv)=0
Pure virtual to make sure every widget implements it.
Definition: NCWidget.cc:391
NCTablePad
Definition: NCTablePad.h:151
NCPad
Definition: NCPad.h:94
NCTable::setEnabled
virtual void setEnabled(bool do_bv)
Pure virtual to make sure every widget implements it.
Definition: NCTable.cc:479
NCTable::toggleCurrentItem
void toggleCurrentItem()
Toggle item from selected -> deselected and vice versa.
Definition: NCTable.cc:604
wpos
Definition: position.h:110
NCursesWindow::bkgd
int bkgd(const chtype ch)
Set the background property and apply it to the window.
Definition: ncursesw.h:1442
NCTableLine
Definition: NCTableItem.h:40
NCursesEvent
Definition: NCurses.h:73
NCPadWidget
Definition: NCPadWidget.h:38
NCTableTag
Definition: NCTablePad.h:102
NCPopupMenu
Definition: NCPopupMenu.h:36