libyui-ncurses  2.44.1
/usr/src/RPM/BUILD/libyui-ncurses-2.44.1/src/NCTable.cc
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 }
 All Classes Functions Variables