libyui-mga-ncurses  1.0.1
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  NCTableCol * cc = cl->GetCol ( colnum );
110 
111  if ( !cc )
112  {
113  yuiWarning() << "No such colnum: " << wpos ( index, colnum ) << newtext << std::endl;
114  }
115  else
116  {
117  // use NCtring to enforce recoding from 'utf8'
118  cc->SetLabel ( NCstring ( newtext ) );
119  DrawPad();
120  }
121  }
122 }
123 
124 
125 
126 // Change individual cell of a table line (to newtext)
127 
128 void YMGA_NCCBTable::cellChanged ( const YTableCell *cell )
129 {
130 
131  cellChanged ( cell->itemIndex(), cell->column(), cell->label() );
132 
133 }
134 
135 
136 
137 // Set all table headers all at once
138 
139 void YMGA_NCCBTable::setHeader ( std::vector<std::string> head )
140 {
141  _header.assign ( head.size(), NCstring ( "" ) );
142  YTableHeader *th = new YTableHeader();
143 
144  for ( unsigned int i = 0; i < head.size(); i++ )
145  {
146  th->addColumn ( head[ i ] );
147  _header[ i ] += NCstring ( head[ i ] ) ;
148  }
149 
150  hasHeadline = myPad()->SetHeadline ( _header );
151 
152  YMGA_CBTable::setTableHeader ( th );
153 }
154 
155 //
156 // Return table header as std::string std::vector (alignment removed)
157 //
158 void YMGA_NCCBTable::getHeader ( std::vector<std::string> & header )
159 {
160  header.assign ( _header.size(), "" );
161 
162  for ( unsigned int i = 0; i < _header.size(); i++ )
163  {
164  header[ i ] = _header[i].Str().substr ( 1 ); // remove alignment
165  }
166 }
167 
168 
169 // Set alignment of i-th table column (left, right, center).
170 // Create temp. header consisting of single letter;
171 // setHeader will append the rest.
172 
173 void YMGA_NCCBTable::setAlignment ( int col, YAlignmentType al )
174 {
175  std::string s;
176 
177  switch ( al )
178  {
179  case YAlignUnchanged:
180  s = 'L' ;
181  break;
182 
183  case YAlignBegin:
184  s = 'L' ;
185  break;
186 
187  case YAlignCenter:
188  s = 'C' ;
189  break;
190 
191  case YAlignEnd:
192  s = 'R' ;
193  break;
194  }
195 
196  _header[ col ] = NCstring ( s );
197 }
198 
199 // Append item (as pointed to by 'yitem') in one-by-one
200 // fashion i.e. the whole table gets redrawn afterwards.
201 void YMGA_NCCBTable::addItem ( YItem *yitem )
202 {
203  addItem ( yitem, false ); // add just this one
204 }
205 
206 // Append item (as pointed to by 'yitem') to a table.
207 // This creates visual representation of new table line
208 // consisting of individual cells. Depending on the 2nd
209 // param, table is redrawn. If 'allAtOnce' is set to
210 // true, it is up to the caller to redraw the table.
211 void YMGA_NCCBTable::addItem ( YItem *yitem, bool allAtOnce )
212 {
213  YCBTableItem *item = dynamic_cast<YCBTableItem *> ( yitem );
214  YUI_CHECK_PTR ( item );
215  YMGA_CBTable::addItem ( item );
216  unsigned int itemCount;
217  YCBTableMode mode = tableMode();
218 
219 // if ( mode == YTableSingleLineSelection )
220  itemCount = columns();
221 // else
222 // itemCount = columns() +1;
223 
224  std::vector<NCTableCol*> Items ( itemCount );
225  int i = 0;
226 
227  if ( mode == YCBTableCheckBoxOnFirstColumn )
228  {
229  // Create the tag first
230  Items[0] = new NCTableTag ( yitem, item->checked() );
231  i++;
232  }
233  // and then iterate over cells
234  for ( YTableCellIterator it = item->cellsBegin();
235  it != item->cellsEnd();
236  ++it )
237  {
238  if ( i >= columns() )
239  {
240  yuiWarning() << "Item contains too many columns, current is " << i
241  << " but only " << columns() << " columns are configured" << std::endl;
242  i++;
243  }
244  else
245  {
246  yuiDebug() << "current column is " << i << "/" << columns() << " (" << ( *it )->label() << ")" << std::endl;
247  Items[i] = new NCTableCol ( NCstring ( ( *it )->label() ) );
248  i++;
249  }
250  }
251  if ( mode == YCBTableCheckBoxOnLastColumn )
252  {
253  // Create the tag at last column
254  Items[columns()-1] = new NCTableTag ( yitem, item->checked() );
255  }
256 
257  //Insert @idx
258  NCTableLine *newline = new NCTableLine ( Items, item->index() );
259 
260  YUI_CHECK_PTR ( newline );
261 
262  newline->setOrigItem ( item );
263 
264  myPad()->Append ( newline );
265 
266  if ( item->selected() )
267  {
268  setCurrentItem ( item->index() ) ;
269  }
270 
271  //in one-by-one mode, redraw the table (otherwise, leave it
272  //up to the caller)
273  if ( !allAtOnce )
274  {
275  DrawPad();
276  }
277 }
278 
279 // reimplemented here to speed up item insertion
280 // (and prevent inefficient redrawing after every single addItem
281 // call)
282 void YMGA_NCCBTable::addItems ( const YItemCollection & itemCollection )
283 {
284 
285  for ( YItemConstIterator it = itemCollection.begin();
286  it != itemCollection.end();
287  ++it )
288  {
289  addItem ( *it, true );
290  }
291  DrawPad();
292 }
293 
294 // Clear the table (in terms of YTable and visually)
295 
296 void YMGA_NCCBTable::deleteAllItems()
297 {
298  myPad()->ClearTable();
299  DrawPad();
300  YMGA_CBTable::deleteAllItems();
301 }
302 
303 
304 
305 // Return index of currently selected table item
306 
307 int YMGA_NCCBTable::getCurrentItem()
308 {
309  if ( !myPad()->Lines() )
310  return -1;
311 
312  return keepSorting() ? myPad()->GetLine ( myPad()->CurPos().L )->getIndex()
313  : myPad()->CurPos().L;
314 
315 }
316 
317 
318 
319 // Return origin pointer of currently selected table item
320 
321 YItem * YMGA_NCCBTable::getCurrentItemPointer()
322 {
323  const NCTableLine *cline = myPad()->GetLine ( myPad()->CurPos().L );
324 
325  if ( cline )
326  return cline->origItem();
327  else
328  return 0;
329 }
330 
331 
332 
333 // Highlight item at 'index'
334 
335 void YMGA_NCCBTable::setCurrentItem ( int index )
336 {
337  myPad()->ScrlLine ( index );
338 }
339 
340 
341 
342 // Mark table item (as pointed to by 'yitem') as selected
343 
344 void YMGA_NCCBTable::selectItem ( YItem *yitem, bool selected )
345 {
346  if ( ! yitem )
347  return;
348 
349  YCBTableItem *item = dynamic_cast<YCBTableItem *> ( yitem );
350  YUI_CHECK_PTR ( item );
351 
352  NCTableLine *line = ( NCTableLine * ) item->data();
353  YUI_CHECK_PTR ( line );
354 
355  const NCTableLine *current_line = myPad()->GetLine ( myPad()->CurPos().L );
356  YUI_CHECK_PTR ( current_line );
357 
358  if ( !selected && ( line == current_line ) )
359  {
360  deselectAllItems();
361  }
362  else
363  {
364  // first highlight only, then select
365  setCurrentItem ( line->getIndex() );
366  YMGA_CBTable::selectItem ( item, selected );
367  }
368 
369  // and redraw
370  DrawPad();
371 }
372 
373 
374 
375 // Mark currently highlighted table item as selected
376 // Yeah, it is really already highlighted, so no need to
377 // selectItem() and setCurrentItem() here again - #493884
378 
379 void YMGA_NCCBTable::selectCurrentItem()
380 {
381  const NCTableLine *cline = myPad()->GetLine ( myPad()->CurPos().L );
382 
383  if ( cline )
384  YMGA_CBTable::selectItem ( cline->origItem(), true );
385 }
386 
387 
388 
389 // Mark all items as deselected
390 
391 void YMGA_NCCBTable::deselectAllItems()
392 {
393  setCurrentItem ( -1 );
394  YMGA_CBTable::deselectAllItems();
395 
396  DrawPad();
397 }
398 
399 
400 
401 // return preferred size
402 
403 int YMGA_NCCBTable::preferredWidth()
404 {
405  wsze sze = ( biglist ) ? myPad()->tableSize() + 2 : wGetDefsze();
406  return sze.W;
407 }
408 
409 
410 
411 // return preferred size
412 
413 int YMGA_NCCBTable::preferredHeight()
414 {
415  wsze sze = ( biglist ) ? myPad()->tableSize() + 2 : wGetDefsze();
416  return sze.H;
417 }
418 
419 
420 
421 // Set new size of the widget
422 
423 void YMGA_NCCBTable::setSize ( int newwidth, int newheight )
424 {
425  wRelocate ( wpos ( 0 ), wsze ( newheight, newwidth ) );
426 }
427 
428 
429 
430 
431 void YMGA_NCCBTable::setLabel ( const std::string & nlabel )
432 {
433  // not implemented: YTable::setLabel( nlabel );
434  NCPadWidget::setLabel ( NCstring ( nlabel ) );
435 }
436 
437 
438 
439 // Set widget state (enabled vs. disabled)
440 
441 void YMGA_NCCBTable::setEnabled ( bool do_bv )
442 {
443  NCWidget::setEnabled ( do_bv );
444  YMGA_CBTable::setEnabled ( do_bv );
445 }
446 
447 
448 
449 
450 bool YMGA_NCCBTable::setItemByKey ( int key )
451 {
452  return myPad()->setItemByKey ( key );
453 }
454 
455 
456 
457 
458 
459 // Create new NCTablePad, set its background
460 NCPad * YMGA_NCCBTable::CreatePad()
461 {
462  wsze psze ( defPadSze() );
463  NCPad * npad = new NCTablePad ( psze.H, psze.W, *this );
464  npad->bkgd ( listStyle().item.plain );
465 
466  return npad;
467 }
468 
469 
470 
471 // Handle 'special' keys i.e those not handled by parent NCPad class
472 // (space, return). Set items to selected, if appropriate.
473 
474 NCursesEvent YMGA_NCCBTable::wHandleInput ( wint_t key )
475 {
476  NCursesEvent ret;
477  int citem = getCurrentItem();
478 
479  if ( ! handleInput ( key ) )
480  {
481  switch ( key )
482  {
483  case CTRL ( 'o' ) :
484  {
485  if ( ! keepSorting() )
486  {
487  // get the column
488  wpos at ( ScreenPos() + wpos ( win->height() / 2, 1 ) );
489 
490  YItemCollection ic;
491  ic.reserve ( _header.size() );
492  unsigned int i = 0;
493 
494  for ( std::vector<NCstring>::const_iterator it = _header.begin();
495  it != _header.end() ; it++, i++ )
496  {
497  // strip the align mark
498  std::string col = ( *it ).Str();
499  col.erase ( 0, 1 );
500 
501  YMenuItem *item = new YMenuItem ( col ) ;
502  //need to set index explicitly, MenuItem inherits from TreeItem
503  //and these don't have indexes set
504  item->setIndex ( i );
505  ic.push_back ( item );
506  }
507 
508  NCPopupMenu *dialog = new NCPopupMenu ( at, ic.begin(), ic.end() );
509 
510  int column = dialog->post();
511 
512  if ( column != -1 )
513  myPad()->setOrder ( column, true ); //enable sorting in reverse order
514 
515  //remove the popup
516  YDialog::deleteTopmostDialog();
517 
518  return NCursesEvent::none;
519  }
520  }
521 
522  case KEY_RETURN:
523  if ( notify() && citem != -1 )
524  return NCursesEvent::Activated;
525  case KEY_SPACE:
527  // send ValueChanged on Return (like done for NCTree multiSelection)
528  if ( notify())
529  {
530  YCBTableItem *pItem = dynamic_cast<YCBTableItem*>(getCurrentItemPointer());
531  YMGA_CBTable::setChangedItem(pItem);
532  return NCursesEvent::ValueChanged;
533  }
534  break;
535 
536  }
537  }
538 
539 
540  if ( citem != getCurrentItem() )
541  {
542  if ( notify() && immediateMode() )
543  ret = NCursesEvent::SelectionChanged;
544 
545  selectCurrentItem();
546  }
547 
548  return ret;
549 }
550 
551 
552 void YMGA_NCCBTable::checkItem ( YItem* yitem, bool checked )
553 {
554  YCBTableItem * item = dynamic_cast<YCBTableItem *> ( yitem );
555  YUI_CHECK_PTR ( item );
556  NCTableLine *line = ( NCTableLine * ) item->data();
557  YUI_CHECK_PTR ( line );
558 
559  item->check(checked);
560 
561  int checkable_column = 0;
562  YCBTableMode mode = tableMode();
563 
564  if ( mode == YCBTableCheckBoxOnLastColumn )
565  checkable_column = columns() -1;
566 
567  yuiDebug() << item->label() << " is now " << ( checked?"checked":"unchecked" ) << endl;
568 
569  NCTableTag *tag = static_cast<NCTableTag *> ( line->GetCol ( checkable_column ) );
570  tag->SetSelected ( checked );
571 }
572 
573 /**
574  * Toggle item from selected -> deselected and vice versa
575  **/
577 {
578  YCBTableItem *item = dynamic_cast<YCBTableItem *> ( getCurrentItemPointer() );
579  YUI_CHECK_PTR ( item );
580  checkItem(item, !item->checked());
581 }
virtual NCTablePad * myPad() const
Overload myPad to narrow the type.
void toggleCurrentItem()
Toggle item from selected -> deselected and vice versa.