libyui-ncurses
2.44.1
|
00001 /* 00002 Copyright (C) 2000-2012 Novell, Inc 00003 This library is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU Lesser General Public License as 00005 published by the Free Software Foundation; either version 2.1 of the 00006 License, or (at your option) version 3.0 of the License. This library 00007 is distributed in the hope that it will be useful, but WITHOUT ANY 00008 WARRANTY; without even the implied warranty of MERCHANTABILITY or 00009 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 00010 License for more details. You should have received a copy of the GNU 00011 Lesser General Public License along with this library; if not, write 00012 to the Free Software Foundation, Inc., 51 Franklin Street, Fifth 00013 Floor, Boston, MA 02110-1301 USA 00014 */ 00015 00016 00017 /*-/ 00018 00019 File: NCTable.cc 00020 00021 Author: Michael Andres <ma@suse.de> 00022 00023 /-*/ 00024 00025 #define YUILogComponent "ncurses" 00026 #include <yui/YUILog.h> 00027 #include "NCTable.h" 00028 #include "NCPopupMenu.h" 00029 #include <yui/YMenuButton.h> 00030 #include <yui/YTypes.h> 00031 00032 using std::endl; 00033 00034 /* 00035 * Some remarks about single/multi selection: 00036 * A table in single selection mode has only one line/item selected which is equal to the 00037 * current item (means the highlighted line). Asking for `CurrentItem in YCP looks for 00038 * selectedItem() (see YCPPropertyHandler::tryGetSelectionWidgetValue). 00039 * In multi selection mode there can be several items selected (here is means checked/marked 00040 * with [x]) and the value is also got from selectedItem() when asking for `SelectedItems 00041 * (see YCPPropertyHandler::tryGetSelectionWidgetValue). 00042 * This means for multi selection mode: at the moment there isn't a possibility to get the 00043 * `CurrentItem. To get the current item (which line of the list is currently highlighted), 00044 * a virtual function currentItem() like available for the MultiSelectionBox has to be 00045 * provided to allow NCTable to specify the line number itself (getCurrentItem). 00046 * 00047 */ 00048 NCTable::NCTable( YWidget * parent, YTableHeader *tableHeader, bool multiSelection ) 00049 : YTable( parent, tableHeader, multiSelection ) 00050 , NCPadWidget( parent ) 00051 , biglist( false ) 00052 , multiselect( multiSelection ) 00053 { 00054 yuiDebug() << std::endl; 00055 00056 InitPad(); 00057 // !!! head is UTF8 encoded, thus should be std::vector<NCstring> 00058 if ( !multiselect ) 00059 { 00060 _header.assign( tableHeader->columns(), NCstring( "" ) ); 00061 for ( int col = 0; col < tableHeader->columns(); col++ ) 00062 { 00063 if ( hasColumn( col ) ) 00064 { 00065 // set alignment first 00066 setAlignment( col, alignment( col ) ); 00067 // and then append header 00068 _header[ col ] += NCstring( tableHeader->header( col ) ) ; 00069 } 00070 } 00071 } 00072 else 00073 { 00074 _header.assign( tableHeader->columns()+1, NCstring( "" ) ); 00075 00076 for ( int col = 1; col <= tableHeader->columns(); col++ ) 00077 { 00078 if ( hasColumn( col-1 ) ) 00079 { 00080 // set alignment first 00081 setAlignment( col, alignment( col-1 ) ); 00082 // and then append header 00083 _header[ col ] += NCstring( tableHeader->header( col-1 ) ) ; 00084 } 00085 } 00086 } 00087 00088 hasHeadline = myPad()->SetHeadline( _header ); 00089 00090 } 00091 00092 00093 00094 00095 NCTable::~NCTable() 00096 { 00097 yuiDebug() << std::endl; 00098 } 00099 00100 00101 00102 // Change individual cell of a table line (to newtext) 00103 // provided for backwards compatibility 00104 00105 void NCTable::cellChanged( int index, int colnum, const std::string & newtext ) 00106 { 00107 NCTableLine * cl = myPad()->ModifyLine( index ); 00108 00109 if ( !cl ) 00110 { 00111 yuiWarning() << "No such line: " << wpos( index, colnum ) << newtext << std::endl; 00112 } 00113 else 00114 { 00115 NCTableCol * cc = cl->GetCol( colnum ); 00116 00117 if ( !cc ) 00118 { 00119 yuiWarning() << "No such colnum: " << wpos( index, colnum ) << newtext << std::endl; 00120 } 00121 else 00122 { 00123 // use NCtring to enforce recoding from 'utf8' 00124 cc->SetLabel( NCstring( newtext ) ); 00125 DrawPad(); 00126 } 00127 } 00128 } 00129 00130 00131 00132 // Change individual cell of a table line (to newtext) 00133 00134 void NCTable::cellChanged( const YTableCell *cell ) 00135 { 00136 00137 cellChanged( cell->itemIndex(), cell->column(), cell->label() ); 00138 00139 } 00140 00141 00142 00143 // Set all table headers all at once 00144 00145 void NCTable::setHeader( std::vector<std::string> head ) 00146 { 00147 _header.assign( head.size(), NCstring( "" ) ); 00148 YTableHeader *th = new YTableHeader(); 00149 00150 for ( unsigned int i = 0; i < head.size(); i++ ) 00151 { 00152 th->addColumn( head[ i ] ); 00153 _header[ i ] += NCstring( head[ i ] ) ; 00154 } 00155 00156 hasHeadline = myPad()->SetHeadline( _header ); 00157 00158 YTable::setTableHeader( th ); 00159 } 00160 00161 // 00162 // Return table header as std::string std::vector (alignment removed) 00163 // 00164 void NCTable::getHeader( std::vector<std::string> & header ) 00165 { 00166 header.assign( _header.size(), "" ); 00167 00168 for ( unsigned int i = 0; i < _header.size(); i++ ) 00169 { 00170 header[ i ] = _header[i].Str().substr( 1 ); // remove alignment 00171 } 00172 } 00173 00174 00175 // Set alignment of i-th table column (left, right, center). 00176 // Create temp. header consisting of single letter; 00177 // setHeader will append the rest. 00178 00179 void NCTable::setAlignment( int col, YAlignmentType al ) 00180 { 00181 std::string s; 00182 00183 switch ( al ) 00184 { 00185 case YAlignUnchanged: 00186 s = 'L' ; 00187 break; 00188 00189 case YAlignBegin: 00190 s = 'L' ; 00191 break; 00192 00193 case YAlignCenter: 00194 s = 'C' ; 00195 break; 00196 00197 case YAlignEnd: 00198 s = 'R' ; 00199 break; 00200 } 00201 00202 _header[ col ] = NCstring( s ); 00203 } 00204 00205 // Append item (as pointed to by 'yitem') in one-by-one 00206 // fashion i.e. the whole table gets redrawn afterwards. 00207 void NCTable::addItem( YItem *yitem) 00208 { 00209 addItem(yitem, false); // add just this one 00210 } 00211 00212 // Append item (as pointed to by 'yitem') to a table. 00213 // This creates visual representation of new table line 00214 // consisting of individual cells. Depending on the 2nd 00215 // param, table is redrawn. If 'allAtOnce' is set to 00216 // true, it is up to the caller to redraw the table. 00217 void NCTable::addItem( YItem *yitem, bool allAtOnce ) 00218 { 00219 00220 YTableItem *item = dynamic_cast<YTableItem *>( yitem ); 00221 YUI_CHECK_PTR( item ); 00222 YTable::addItem( item ); 00223 unsigned int itemCount; 00224 00225 if ( !multiselect ) 00226 itemCount = item->cellCount(); 00227 else 00228 itemCount = item->cellCount()+1; 00229 00230 std::vector<NCTableCol*> Items( itemCount ); 00231 unsigned int i = 0; 00232 00233 if ( !multiselect ) 00234 { 00235 // Iterate over cells to create columns 00236 for ( YTableCellIterator it = item->cellsBegin(); 00237 it != item->cellsEnd(); 00238 ++it ) 00239 { 00240 Items[i] = new NCTableCol( NCstring(( *it )->label() ) ); 00241 i++; 00242 } 00243 } 00244 else 00245 { 00246 // Create the tag first 00247 Items[0] = new NCTableTag( yitem, yitem->selected() ); 00248 i++; 00249 // and then iterate over cells 00250 for ( YTableCellIterator it = item->cellsBegin(); 00251 it != item->cellsEnd(); 00252 ++it ) 00253 { 00254 Items[i] = new NCTableCol( NCstring(( *it )->label() ) ); 00255 i++; 00256 } 00257 } 00258 00259 //Insert @idx 00260 NCTableLine *newline = new NCTableLine( Items, item->index() ); 00261 00262 YUI_CHECK_PTR( newline ); 00263 00264 newline->setOrigItem( item ); 00265 00266 myPad()->Append( newline ); 00267 00268 if ( item->selected() ) 00269 { 00270 setCurrentItem( item->index() ) ; 00271 } 00272 00273 //in one-by-one mode, redraw the table (otherwise, leave it 00274 //up to the caller) 00275 if (!allAtOnce) 00276 { 00277 DrawPad(); 00278 } 00279 } 00280 00281 // reimplemented here to speed up item insertion 00282 // (and prevent inefficient redrawing after every single addItem 00283 // call) 00284 void NCTable::addItems( const YItemCollection & itemCollection ) 00285 { 00286 00287 for ( YItemConstIterator it = itemCollection.begin(); 00288 it != itemCollection.end(); 00289 ++it ) 00290 { 00291 addItem( *it, true); 00292 } 00293 DrawPad(); 00294 } 00295 00296 // Clear the table (in terms of YTable and visually) 00297 00298 void NCTable::deleteAllItems() 00299 { 00300 myPad()->ClearTable(); 00301 DrawPad(); 00302 YTable::deleteAllItems(); 00303 } 00304 00305 00306 00307 // Return index of currently selected table item 00308 00309 int NCTable::getCurrentItem() 00310 { 00311 if ( !myPad()->Lines() ) 00312 return -1; 00313 00314 return keepSorting() ? myPad()->GetLine( myPad()->CurPos().L )->getIndex() 00315 : myPad()->CurPos().L; 00316 00317 } 00318 00319 00320 00321 // Return origin pointer of currently selected table item 00322 00323 YItem * NCTable::getCurrentItemPointer() 00324 { 00325 const NCTableLine *cline = myPad()->GetLine( myPad()->CurPos().L ); 00326 00327 if ( cline ) 00328 return cline->origItem(); 00329 else 00330 return 0; 00331 } 00332 00333 00334 00335 // Highlight item at 'index' 00336 00337 void NCTable::setCurrentItem( int index ) 00338 { 00339 myPad()->ScrlLine( index ); 00340 } 00341 00342 00343 00344 // Mark table item (as pointed to by 'yitem') as selected 00345 00346 void NCTable::selectItem( YItem *yitem, bool selected ) 00347 { 00348 if ( ! yitem ) 00349 return; 00350 00351 YTableItem *item = dynamic_cast<YTableItem *>( yitem ); 00352 YUI_CHECK_PTR( item ); 00353 00354 NCTableLine *line = ( NCTableLine * )item->data(); 00355 YUI_CHECK_PTR( line ); 00356 00357 const NCTableLine *current_line = myPad()->GetLine( myPad()->CurPos().L ); 00358 YUI_CHECK_PTR( current_line ); 00359 00360 if ( !multiselect ) 00361 { 00362 if ( !selected && ( line == current_line ) ) 00363 { 00364 deselectAllItems(); 00365 } 00366 else 00367 { 00368 // first highlight only, then select 00369 setCurrentItem( line->getIndex() ); 00370 YTable::selectItem( item, selected ); 00371 } 00372 } 00373 else 00374 { 00375 setCurrentItem( line->getIndex() ); 00376 YTable::selectItem( item, selected ); 00377 00378 yuiMilestone() << item->label() << " is selected: " << (selected?"yes":"no") << endl; 00379 00380 NCTableTag *tag = static_cast<NCTableTag *>( line->GetCol( 0 ) ); 00381 tag->SetSelected( selected ); 00382 } 00383 00384 // and redraw 00385 DrawPad(); 00386 } 00387 00388 00389 00390 // Mark currently highlighted table item as selected 00391 // Yeah, it is really already highlighted, so no need to 00392 // selectItem() and setCurrentItem() here again - #493884 00393 00394 void NCTable::selectCurrentItem() 00395 { 00396 const NCTableLine *cline = myPad()->GetLine( myPad()->CurPos().L ); 00397 00398 if ( cline ) 00399 YTable::selectItem( cline->origItem(), true ); 00400 } 00401 00402 00403 00404 // Mark all items as deselected 00405 00406 void NCTable::deselectAllItems() 00407 { 00408 if ( !multiselect ) 00409 { 00410 setCurrentItem( -1 ); 00411 YTable::deselectAllItems(); 00412 } 00413 else 00414 { 00415 YItemCollection itemCollection = YTable::selectedItems(); 00416 for ( YItemConstIterator it = itemCollection.begin(); 00417 it != itemCollection.end(); ++it ) 00418 { 00419 selectItem( *it, false ); // YTable::selectItem(item,false) 00420 } 00421 } 00422 00423 DrawPad(); 00424 } 00425 00426 00427 00428 // return preferred size 00429 00430 int NCTable::preferredWidth() 00431 { 00432 wsze sze = ( biglist ) ? myPad()->tableSize() + 2 : wGetDefsze(); 00433 return sze.W; 00434 } 00435 00436 00437 00438 // return preferred size 00439 00440 int NCTable::preferredHeight() 00441 { 00442 wsze sze = ( biglist ) ? myPad()->tableSize() + 2 : wGetDefsze(); 00443 return sze.H; 00444 } 00445 00446 00447 00448 // Set new size of the widget 00449 00450 void NCTable::setSize( int newwidth, int newheight ) 00451 { 00452 wRelocate( wpos( 0 ), wsze( newheight, newwidth ) ); 00453 } 00454 00455 00456 00457 00458 void NCTable::setLabel( const std::string & nlabel ) 00459 { 00460 // not implemented: YTable::setLabel( nlabel ); 00461 NCPadWidget::setLabel( NCstring( nlabel ) ); 00462 } 00463 00464 00465 00466 // Set widget state (enabled vs. disabled) 00467 00468 void NCTable::setEnabled( bool do_bv ) 00469 { 00470 NCWidget::setEnabled( do_bv ); 00471 YTable::setEnabled( do_bv ); 00472 } 00473 00474 00475 00476 00477 bool NCTable::setItemByKey( int key ) 00478 { 00479 return myPad()->setItemByKey( key ); 00480 } 00481 00482 00483 00484 00485 00486 // Create new NCTablePad, set its background 00487 NCPad * NCTable::CreatePad() 00488 { 00489 wsze psze( defPadSze() ); 00490 NCPad * npad = new NCTablePad( psze.H, psze.W, *this ); 00491 npad->bkgd( listStyle().item.plain ); 00492 00493 return npad; 00494 } 00495 00496 00497 00498 // Handle 'special' keys i.e those not handled by parent NCPad class 00499 // (space, return). Set items to selected, if appropriate. 00500 00501 NCursesEvent NCTable::wHandleInput( wint_t key ) 00502 { 00503 NCursesEvent ret; 00504 int citem = getCurrentItem(); 00505 bool sendEvent = false; 00506 00507 if ( ! handleInput( key ) ) 00508 { 00509 switch ( key ) 00510 { 00511 case CTRL( 'o' ): 00512 { 00513 if ( ! keepSorting() ) 00514 { 00515 // get the column 00516 wpos at( ScreenPos() + wpos( win->height() / 2, 1 ) ); 00517 00518 YItemCollection ic; 00519 ic.reserve( _header.size() ); 00520 unsigned int i = 0; 00521 00522 for ( std::vector<NCstring>::const_iterator it = _header.begin(); 00523 it != _header.end() ; it++, i++ ) 00524 { 00525 // strip the align mark 00526 std::string col = ( *it ).Str(); 00527 col.erase( 0, 1 ); 00528 00529 YMenuItem *item = new YMenuItem( col ) ; 00530 //need to set index explicitly, MenuItem inherits from TreeItem 00531 //and these don't have indexes set 00532 item->setIndex( i ); 00533 ic.push_back( item ); 00534 } 00535 00536 NCPopupMenu *dialog = new NCPopupMenu( at, ic.begin(), ic.end() ); 00537 00538 int column = dialog->post(); 00539 00540 if ( column != -1 ) 00541 myPad()->setOrder( column, true ); //enable sorting in reverse order 00542 00543 //remove the popup 00544 YDialog::deleteTopmostDialog(); 00545 00546 return NCursesEvent::none; 00547 } 00548 } 00549 00550 case KEY_RETURN: 00551 sendEvent = true; 00552 case KEY_SPACE: 00553 if ( !multiselect ) 00554 { 00555 if ( notify() && citem != -1 ) 00556 return NCursesEvent::Activated; 00557 } 00558 else 00559 { 00560 toggleCurrentItem(); 00561 // send ValueChanged on Return (like done for NCTree multiSelection) 00562 if ( notify() && sendEvent ) 00563 { 00564 return NCursesEvent::ValueChanged; 00565 } 00566 } 00567 break; 00568 00569 } 00570 } 00571 00572 00573 if ( citem != getCurrentItem() ) 00574 { 00575 if ( notify() && immediateMode() ) 00576 ret = NCursesEvent::SelectionChanged; 00577 00578 if ( !multiselect ) 00579 selectCurrentItem(); 00580 } 00581 00582 return ret; 00583 } 00584 00585 /** 00586 * Toggle item from selected -> deselected and vice versa 00587 **/ 00588 void NCTable::toggleCurrentItem() 00589 { 00590 YTableItem *it = dynamic_cast<YTableItem *>( getCurrentItemPointer() ); 00591 if ( it ) 00592 { 00593 selectItem( it, !( it->selected() ) ); 00594 } 00595 }