libyui-ncurses  2.44.1
/usr/src/RPM/BUILD/libyui-ncurses-2.44.1/src/NCTree.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:       NCTree.cc
00020 
00021    Author:     Michael Andres <ma@suse.de>
00022 
00023 /-*/
00024 
00025 #define  YUILogComponent "ncurses"
00026 #include <yui/YUILog.h>
00027 #include "NCTree.h"
00028 
00029 #include <yui/TreeItem.h>
00030 #include <yui/YSelectionWidget.h>
00031 
00032 
00033 class NCTreeLine : public NCTableLine
00034 {
00035 
00036 private:
00037 
00038     YTreeItem *         yitem;
00039     const unsigned      level;
00040 
00041     NCTreeLine * parent;
00042     NCTreeLine * nsibling;
00043     NCTreeLine * fchild;
00044 
00045     mutable chtype * prefix;
00046     bool multiSel;
00047     unsigned prefixLen() const { return level + 3; }
00048 
00049 public:
00050 
00051     NCTreeLine( NCTreeLine * p, YTreeItem * item, bool multiSelection )
00052             : NCTableLine( 0 )
00053             , yitem( item )
00054             , level( p ? p->level + 1 : 0 )
00055             , parent( p )
00056             , nsibling( 0 )
00057             , fchild( 0 )
00058             , prefix( 0 )
00059             , multiSel( multiSelection )
00060     {
00061         if ( parent )
00062         {
00063             if ( parent->fchild )
00064             {
00065                 NCTreeLine * s = parent->fchild;
00066 
00067                 for ( ; s->nsibling; s = s->nsibling )
00068                     ;
00069 
00070                 s->nsibling = this;
00071             }
00072             else
00073             {
00074                 parent->fchild = this;
00075             }
00076 
00077             if ( !parent->yitem->isOpen() )
00078             {
00079                 SetState( S_HIDDEN );
00080             }
00081         }
00082 
00083         if ( !multiSel )
00084         {
00085             Append( new NCTableCol( NCstring( std::string( prefixLen(), ' ' )
00086                                           + yitem->label() ) ) );
00087         }
00088         else
00089         {
00090             Append( new NCTableCol( NCstring( std::string( prefixLen(), ' ' ) + "[ ] "
00091                                               + yitem->label() ) ) );
00092         }
00093     }
00094 
00095     virtual ~NCTreeLine() { delete [] prefix; }
00096 
00097 public:
00098 
00099     YTreeItem * YItem() const { return yitem; }
00100 
00101     unsigned    Level() const { return level; }
00102 
00103     virtual bool isVisible() const
00104     {
00105         return !parent || ( !isHidden() && parent->isVisible() );
00106     }
00107 
00108 
00109     virtual int ChangeToVisible()
00110     {
00111         if ( isVisible() )
00112             return 0;
00113 
00114         if ( parent )
00115         {
00116             parent->ChangeToVisible();
00117 
00118             for ( NCTreeLine * c = parent->fchild; c; c = c->nsibling )
00119             {
00120                 c->ClearState( S_HIDDEN );
00121                 c->YItem()->setOpen( true );
00122             }
00123         }
00124         else
00125         {
00126             ClearState( S_HIDDEN );
00127             yitem->setOpen( true );
00128         }
00129 
00130         return 1;
00131     }
00132 
00133 
00134     virtual unsigned Hotspot( unsigned & at ) const
00135     {
00136         at = Level();
00137         return 6;
00138     }
00139 
00140 
00141     virtual int  handleInput( wint_t key )
00142     {
00143         if ( !fchild )
00144             return 0;
00145 
00146         switch ( key )
00147         {
00148             case KEY_IC:
00149             case '+':
00150                 if ( fchild->isVisible() )
00151                     return 0;
00152 
00153                 break;
00154 
00155             case KEY_DC:
00156             case '-':
00157                 if ( !fchild->isVisible() )
00158                     return 0;
00159 
00160                 break;
00161 
00162             case KEY_SPACE:
00163             //  case KEY_RETURN: see bug 67350
00164 
00165                 break;
00166 
00167             default:
00168                 return 0;
00169 
00170                 break;
00171         }
00172 
00173         if ( fchild->isVisible() )
00174         {
00175             yitem->setOpen( false );
00176             yuiMilestone() << "Closing item " << yitem->label() << std::endl;
00177 
00178             for ( NCTreeLine * c = fchild; c; c = c->nsibling )
00179                 c->SetState( S_HIDDEN );
00180         }
00181         else
00182         {
00183             yitem->setOpen( true );
00184             yuiMilestone() << "Opening item " << yitem->label() << std::endl;
00185 
00186             for ( NCTreeLine * c = fchild; c; c = c->nsibling )
00187                 c->ClearState( S_HIDDEN );
00188         }
00189 
00190         return 1;
00191     }
00192 
00193 
00194     virtual void DrawAt( NCursesWindow & w, const wrect at,
00195                          NCTableStyle & tableStyle,
00196                          bool active ) const
00197     {
00198 
00199         NCTableLine::DrawAt( w, at, tableStyle, active );
00200 
00201         if ( !isSpecial() )
00202             w.bkgdset( tableStyle.getBG( vstate, NCTableCol::SEPARATOR ) );
00203 
00204         if ( ! prefix )
00205         {
00206             prefix = new chtype[prefixLen()];
00207             chtype * tagend = &prefix[prefixLen()-1];
00208             *tagend-- = ACS_HLINE;
00209             *tagend-- = fchild ? ACS_TTEE : ACS_HLINE;
00210 
00211             if ( parent )
00212             {
00213                 *tagend-- = nsibling ? ACS_LTEE : ACS_LLCORNER;
00214 
00215                 for ( NCTreeLine * p = parent; p; p = p->parent )
00216                 {
00217                     *tagend-- = p->nsibling ? ACS_VLINE : ( ' '&A_CHARTEXT );
00218                 }
00219             }
00220             else
00221             {
00222                 *tagend-- = ACS_HLINE;
00223             }
00224         }
00225 
00226         w.move( at.Pos.L, at.Pos.C );
00227 
00228         unsigned i = 0;
00229 
00230         for ( ; i < prefixLen(); ++i )
00231             w.addch( prefix[i] );
00232 
00233         w.move( at.Pos.L, at.Pos.C + prefixLen() - 2 );
00234 
00235         if ( fchild && !isSpecial() )
00236             w.bkgdset( tableStyle.highlightBG( vstate, NCTableCol::HINT,
00237                                                NCTableCol::SEPARATOR ) );
00238 
00239         if ( fchild && !fchild->isVisible() )
00240             w.addch( '+' );
00241         else
00242             w.addch( prefix[prefixLen() - 2] );
00243     }
00244 };
00245 
00246 
00247 
00248 
00249 
00250 
00251 NCTree::NCTree( YWidget * parent, const std::string & nlabel, bool multiselection, bool recursiveselection )
00252     : YTree( parent, nlabel, multiselection, recursiveselection )
00253         , NCPadWidget( parent )
00254         , multiSel ( multiselection )
00255 {
00256     yuiDebug() << std::endl;
00257 
00258     if ( multiselection && recursiveselection )
00259         yuiMilestone() << "NCTree recursive multi selection ON" << std::endl;
00260     else if ( multiselection )
00261         yuiMilestone() << "NCTree multi selection ON" << std::endl;
00262 
00263     setLabel( nlabel );
00264 }
00265 
00266 
00267 
00268 NCTree::~NCTree()
00269 {
00270     yuiDebug() << std::endl;
00271 }
00272 
00273 
00274 
00275 
00276 // Return pointer to tree line  at given index
00277 inline const NCTreeLine * NCTree::getTreeLine( unsigned idx ) const
00278 {
00279     if ( myPad() )
00280         return dynamic_cast<const NCTreeLine *>( myPad()->GetLine( idx ) );
00281     else
00282         return 0;
00283 }
00284 
00285 
00286 
00287 
00288 // Modify tree line at given index
00289 inline NCTreeLine * NCTree::modifyTreeLine( unsigned idx )
00290 {
00291     if ( myPad() )
00292     {
00293         return dynamic_cast<NCTreeLine *>( myPad()->ModifyLine( idx ) );
00294     }
00295 
00296     return 0;
00297 }
00298 
00299 
00300 
00301 
00302 // Set preferred width
00303 int NCTree::preferredWidth()
00304 {
00305     wsze sze = wsze::max( defsze, wsze( 0, labelWidth() + 2 ) );
00306     return sze.W;
00307 }
00308 
00309 
00310 
00311 
00312 // Set preferred height
00313 int NCTree::preferredHeight()
00314 {
00315     wsze sze = wsze::max( defsze, wsze( 0, labelWidth() + 2 ) );
00316     return sze.H;
00317 }
00318 
00319 
00320 
00321 
00322 // Enable/disable widget
00323 void NCTree::setEnabled( bool do_bv )
00324 {
00325     NCWidget::setEnabled( do_bv );
00326     YWidget::setEnabled( do_bv );
00327 }
00328 
00329 
00330 
00331 
00332 void NCTree::setSize( int newwidth, int newheight )
00333 {
00334     wRelocate( wpos( 0 ), wsze( newheight, newwidth ) );
00335 }
00336 
00337 
00338 
00339 
00340 // Return YTreeItem pointer for a current line
00341 //                    (under the cursor)
00342 YTreeItem * NCTree::getCurrentItem() const
00343 {
00344     YTreeItem * yitem = 0;
00345 
00346     if ( myPad() )
00347     {
00348         const NCTreeLine * cline = dynamic_cast<const NCTreeLine *>( myPad()->GetCurrentLine() );
00349 
00350         if ( cline )
00351             yitem = cline->YItem();
00352     }
00353 
00354     yuiDebug() << "-> " << ( yitem ? yitem->label().c_str() : "noitem" ) << std::endl;
00355 
00356     return yitem;
00357 }
00358 
00359 void NCTree::deselectAllItems()
00360 {
00361     if ( multiSel)
00362     {
00363         YItemCollection selectedItems = YTree::selectedItems();
00364 
00365         for ( YItemConstIterator it = selectedItems.begin(); it != selectedItems.end(); ++it )
00366         {
00367             selectItem( *it, false );
00368         }
00369     }
00370 
00371     YTree::deselectAllItems();
00372 }
00373 
00374 
00375 // Set current item (under the cursor) to selected
00376 void NCTree::selectItem( YItem *item, bool selected )
00377 {
00378     if ( !myPad() )
00379         return;
00380 
00381     YTreeItem * treeItem =  dynamic_cast<YTreeItem *>( item );
00382     YUI_CHECK_PTR( treeItem );
00383     YTreeItem *citem = getCurrentItem();
00384 
00385     //retrieve position of item
00386     int at = treeItem->index();
00387 
00388     NCTreeLine * cline = 0;     // current line
00389     NCTableCol * ccol = 0;      // current column
00390 
00391     if ( multiSel )
00392     {
00393         cline = modifyTreeLine( at );
00394         if ( cline )
00395         {
00396             ccol = cline->GetCol(0);
00397         }
00398     }
00399 
00400     if ( !selected )
00401     {
00402         if ( !multiSel && (treeItem == citem) )
00403         {
00404             YTree::deselectAllItems();
00405         }
00406         else
00407         {
00408             YTree::selectItem ( treeItem, false );
00409             if ( ccol )
00410             {
00411                 ccol->SetLabel( NCstring( std::string( cline->Level() + 3, ' ' ) + "[ ] "
00412                                           + item->label() ) );
00413             }
00414         }
00415     }
00416     else
00417     {
00418         YTree::selectItem( treeItem, selected );
00419 
00420         if ( multiSel && ccol )
00421         {
00422             ccol->SetLabel( NCstring( std::string( cline->Level() + 3, ' ' ) + "[x] "
00423                                       + item->label() ) );
00424         }
00425 
00426         //this highlights selected item, possibly unpacks the tree
00427         //should it be in currently hidden branch
00428         myPad()->ShowItem( getTreeLine( at ) );
00429     }
00430 }
00431 
00432 
00433 
00434 
00435 // Set current item (at given index) to selected
00436 //                    (overloaded for convenience)
00437 void NCTree::selectItem( int index )
00438 {
00439     YItem * item = YTree::itemAt( index );
00440 
00441     if ( item )
00442     {
00443         selectItem( item, true );
00444     }
00445     else
00446         YUI_THROW( YUIException( "Can't find selected item" ) );
00447 }
00448 
00449 
00450 
00451 void NCTree::setLabel( const std::string & nlabel )
00452 {
00453     YTree::setLabel( nlabel );
00454     NCPadWidget::setLabel( NCstring( nlabel ) );
00455 }
00456 
00457 
00458 
00459 void NCTree::rebuildTree()
00460 {
00461     DelPad();
00462     Redraw();
00463 }
00464 
00465 
00466 
00467 
00468 // Creates empty pad
00469 NCPad * NCTree::CreatePad()
00470 {
00471     wsze    psze( defPadSze() );
00472     NCPad * npad = new NCTreePad( psze.H, psze.W, *this );
00473     npad->bkgd( listStyle().item.plain );
00474     return npad;
00475 }
00476 
00477 
00478 // Creates tree lines and appends them to TreePad
00479 // (called recursively for each child of an item)
00480 void NCTree::CreateTreeLines( NCTreeLine * parentLine, NCTreePad * pad, YItem * item )
00481 {
00482     //set item index explicitely, it is set to -1 by default
00483     //which makes selecting items painful
00484     item->setIndex( idx++ );
00485 
00486     YTreeItem * treeItem = dynamic_cast<YTreeItem *>( item );
00487     YUI_CHECK_PTR( treeItem );
00488 
00489     NCTreeLine * line = new NCTreeLine( parentLine, treeItem, multiSel );
00490     pad->Append( line );
00491 
00492     // iterate over children
00493 
00494     for ( YItemIterator it = item->childrenBegin();  it < item->childrenEnd(); ++it )
00495     {
00496         CreateTreeLines( line, pad, *it );
00497     }
00498 }
00499 
00500 // Returns current item (pure virtual in YTree)
00501 YTreeItem * NCTree::currentItem()
00502 {
00503     return getCurrentItem();
00504 }
00505 
00506 // Fills TreePad with lines (uses CreateTreeLines to create them)
00507 void NCTree::DrawPad()
00508 {
00509     if ( !myPad() )
00510     {
00511         yuiWarning() << "PadWidget not yet created" << std::endl;
00512         return;
00513     }
00514 
00515     idx = 0;
00516     // YItemIterator iterates over the toplevel items
00517     for ( YItemIterator it = itemsBegin(); it < itemsEnd(); ++it )
00518     {
00519         CreateTreeLines( 0, myPad(), *it );
00520     }
00521 
00522     idx = 0;
00523     NCPadWidget::DrawPad();
00524 }
00525 
00526 
00527 
00528 NCursesEvent NCTree::wHandleInput( wint_t key )
00529 {
00530     NCursesEvent ret = NCursesEvent::none;
00531     YTreeItem * oldCurrentItem = getCurrentItem();
00532 
00533     bool handled = handleInput( key ); // NCTreePad::handleInput()
00534     const YItem * currentItem = getCurrentItem();
00535 
00536     if ( !currentItem )
00537         return ret;
00538 
00539     if ( multiSel )
00540     {
00541         if ( ! handled )
00542         {
00543             switch ( key )
00544             {
00545                 // KEY_SPACE is handled in NCTreeLine::handleInput
00546                 case KEY_RETURN:
00547 
00548                     if ( currentItem->selected() )
00549                         selectItem( const_cast<YItem *>(currentItem), false );
00550                     else
00551                         selectItem( const_cast<YItem *>(currentItem), true );
00552 
00553                     if ( notify() )
00554                     {
00555                         return NCursesEvent::ValueChanged;
00556                     }
00557                     break;
00558             }
00559         }
00560     }
00561     else
00562     {
00563         if ( ! handled )
00564         {
00565             switch ( key )
00566             {
00567                 // KEY_SPACE is handled in NCTreeLine::handleInput
00568                 case KEY_RETURN:
00569 
00570                     if ( notify() )
00571                     {
00572                         return NCursesEvent::Activated;
00573                     }
00574                     break;
00575             }
00576         }
00577 
00578         YTree::selectItem( const_cast<YItem *>( currentItem ), true );
00579     }
00580 
00581     if ( notify() && immediateMode() && ( oldCurrentItem != currentItem ) )
00582             ret = NCursesEvent::SelectionChanged;
00583 
00584     yuiDebug() << "Notify: " << ( notify() ? "true" : "false" ) <<
00585         " Return event: " << ret.reason << std::endl;
00586 
00587     return ret;
00588 }
00589 
00590 
00591 
00592 
00593 
00594 // clears the table and the lists holding
00595 //                    the values
00596 void NCTree::deleteAllItems()
00597 {
00598     YTree::deleteAllItems();
00599     myPad()->ClearTable();
00600 }
 All Classes Functions Variables