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