libyui  3.0.10
/usr/src/RPM/BUILD/libyui-3.0.10/src/YSelectionWidget.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:         YSelectionWidget.cc
00020 
00021   Author:       Stefan Hundhammer <sh@suse.de>
00022 
00023 /-*/
00024 
00025 
00026 #define YUILogComponent "ui"
00027 #include "YUILog.h"
00028 
00029 #include <algorithm>
00030 #include "YSelectionWidget.h"
00031 #include "YUIException.h"
00032 #include "YApplication.h"
00033 
00034 
00035 struct YSelectionWidgetPrivate
00036 {
00037     YSelectionWidgetPrivate( const std::string &        label,
00038                              bool               enforceSingleSelection,
00039                              bool               recursiveSelection )
00040         : label( label )
00041         , enforceSingleSelection( enforceSingleSelection )
00042         , recursiveSelection ( recursiveSelection )
00043         {}
00044 
00045     std::string         label;
00046     bool                enforceSingleSelection;
00047     bool                recursiveSelection;
00048     std::string         iconBasePath;
00049     YItemCollection     itemCollection;
00050 };
00051 
00052 
00053 
00054 
00055 YSelectionWidget::YSelectionWidget( YWidget *           parent,
00056                                     const std::string &         label,
00057                                     bool                enforceSingleSelection ,
00058                                     bool                recursiveSelection )
00059     : YWidget( parent )
00060     , priv( new YSelectionWidgetPrivate( label, enforceSingleSelection, recursiveSelection ) )
00061 {
00062     YUI_CHECK_NEW( priv );
00063 
00064     if ( enforceSingleSelection && recursiveSelection )
00065         YUI_THROW( YUIException( "recursiveSelection is only available for multiSelection Widgets."));
00066 
00067 }
00068 
00069 
00070 YSelectionWidget::~YSelectionWidget()
00071 {
00072     deleteAllItems();
00073 }
00074 
00075 
00076 void YSelectionWidget::deleteAllItems()
00077 {
00078     YItemIterator it = itemsBegin();
00079 
00080     while ( it != itemsEnd() )
00081     {
00082         YItem * item = *it;
00083         ++it;
00084         delete item;
00085 
00086         // No need to check for item->hasChildren() and iterate recursively
00087         // over the children: The item will take care of its children in its
00088         // destructor.
00089     }
00090 
00091     priv->itemCollection.clear();
00092 }
00093 
00094 
00095 std::string YSelectionWidget::label() const
00096 {
00097     return priv->label;
00098 }
00099 
00100 
00101 void YSelectionWidget::setLabel( const std::string & newLabel )
00102 {
00103     priv->label = newLabel;
00104 }
00105 
00106 
00107 bool YSelectionWidget::enforceSingleSelection() const
00108 {
00109     return priv->enforceSingleSelection;
00110 }
00111 
00112 bool YSelectionWidget::recursiveSelection() const
00113 {
00114     return priv->recursiveSelection;
00115 }
00116 
00117 
00118 
00119 void YSelectionWidget::setEnforceSingleSelection( bool enforceSingleSelection )
00120 {
00121     priv->enforceSingleSelection = enforceSingleSelection;
00122 }
00123 
00124 
00125 void YSelectionWidget::setIconBasePath( const std::string & basePath )
00126 {
00127     priv->iconBasePath = basePath;
00128 }
00129 
00130 
00131 std::string YSelectionWidget::iconBasePath() const
00132 {
00133     return priv->iconBasePath;
00134 }
00135 
00136 
00137 std::string YSelectionWidget::iconFullPath( const std::string & iconName ) const
00138 {
00139     std::string fullPath;
00140 
00141     if ( ! iconName.empty() )
00142     {
00143         if ( iconName[0] == '/' )
00144             return iconName;
00145 
00146         if ( priv->iconBasePath.empty() ||
00147              priv->iconBasePath[0] != '/' )
00148         {
00149             return YUI::yApp()->iconLoader()->findIcon( iconName );
00150         }
00151 
00152         fullPath += priv->iconBasePath + "/" + iconName;
00153     }
00154 
00155     return fullPath;
00156 }
00157 
00158 
00159 std::string YSelectionWidget::iconFullPath( YItem * item ) const
00160 {
00161     if ( item )
00162         return iconFullPath( item->iconName() );
00163     else
00164         return "";
00165 }
00166 
00167 
00168 void YSelectionWidget::addItem( YItem * item )
00169 {
00170     YUI_CHECK_PTR( item );
00171 
00172     if ( item->parent() )
00173     {
00174         YUI_THROW( YUIException( "Item already owned by parent item -"
00175                                  " call addItem() only for toplevel items!" ) );
00176     }
00177 
00178     // Add the new item to the item list
00179 
00180     priv->itemCollection.push_back( item );
00181     item->setIndex( priv->itemCollection.size() - 1 );
00182 
00183     // yuiDebug() << "Adding item \"" << item->label() << "\"" << endl;
00184 
00185     //
00186     // Enforce single selection (if applicable)
00187     //
00188 
00189     if ( priv->enforceSingleSelection )
00190     {
00191         if ( item->selected() )
00192         {
00193             YItem * oldSelectedItem = selectedItem();
00194 
00195             // This looks expensive, but it is not: Even though selectedItem()
00196             // searches the complete item list until it finds a selected item,
00197             // this happens only if a new item is to be inserted that has the
00198             // "selected" flag on. In the normal case, this will only be one
00199             // item.
00200             //
00201             // Only if the calling application does this systematically wrong
00202             // and sets the "selected" flag for ALL items it inserts this will
00203             // be more expensive. But then, this is a bug in that application
00204             // that needs to be fixed.
00205 
00206             if ( oldSelectedItem && oldSelectedItem != item )
00207             {
00208                 oldSelectedItem->setSelected( false );
00209                 item->setSelected( true );
00210             }
00211         }
00212 
00213 
00214         // Make sure there is one item selected initially.
00215         //
00216         // If any other subsequently added items are to be selected, they will
00217         // override this initial selection.
00218 
00219         if ( priv->itemCollection.size() == 1 )
00220             item->setSelected( true );
00221     }
00222 }
00223 
00224 
00225 void YSelectionWidget::addItem( const std::string &     itemLabel,
00226                                 const std::string &     iconName,
00227                                 bool            selected )
00228 {
00229     YItem * item = new YItem( itemLabel, iconName, selected );
00230     YUI_CHECK_NEW( item );
00231     addItem( item );
00232 }
00233 
00234 
00235 void YSelectionWidget::addItem( const std::string & itemLabel, bool selected )
00236 {
00237     addItem( itemLabel, "", selected );
00238 }
00239 
00240 
00241 void YSelectionWidget::addItems( const YItemCollection & itemCollection )
00242 {
00243     OptimizeChanges below( *this ); // Delay screen updates until this block is left
00244     priv->itemCollection.reserve( priv->itemCollection.size() + itemCollection.size() );
00245 
00246     for ( YItemConstIterator it = itemCollection.begin();
00247           it != itemCollection.end();
00248           ++it )
00249     {
00250         addItem( *it );
00251 
00252         // No need to check for (*it)->hasChildren() and iterate recursively
00253         // over the children: Any children of this item simply remain in this
00254         // item's YItemCollection.
00255     }
00256 }
00257 
00258 
00259 YItemIterator
00260 YSelectionWidget::itemsBegin()
00261 {
00262     return priv->itemCollection.begin();
00263 }
00264 
00265 YItemConstIterator
00266 YSelectionWidget::itemsBegin() const
00267 {
00268     return priv->itemCollection.begin();
00269 }
00270 
00271 
00272 YItemIterator
00273 YSelectionWidget::itemsEnd()
00274 {
00275     return priv->itemCollection.end();
00276 }
00277 
00278 
00279 YItemConstIterator
00280 YSelectionWidget::itemsEnd() const
00281 {
00282     return priv->itemCollection.end();
00283 }
00284 
00285 
00286 bool YSelectionWidget::hasItems() const
00287 {
00288     return ! priv->itemCollection.empty();
00289 }
00290 
00291 
00292 int YSelectionWidget::itemsCount() const
00293 {
00294     return priv->itemCollection.size();
00295 }
00296 
00297 
00298 YItem *
00299 YSelectionWidget::firstItem() const
00300 {
00301     if ( priv->itemCollection.empty() )
00302         return 0;
00303     else
00304         return priv->itemCollection.front();
00305 }
00306 
00307 
00308 YItem *
00309 YSelectionWidget::itemAt( int index ) const
00310 {
00311     if ( index < 0 || index >= (int) priv->itemCollection.size() )
00312         return 0;
00313 
00314     return priv->itemCollection[ index ];
00315 }
00316 
00317 
00318 YItem *
00319 YSelectionWidget::selectedItem()
00320 {
00321     return findSelectedItem( itemsBegin(), itemsEnd() );
00322 }
00323 
00324 
00325 YItem *
00326 YSelectionWidget::findSelectedItem( YItemConstIterator begin,
00327                                     YItemConstIterator end )
00328 {
00329     for ( YItemConstIterator it = begin; it != end; ++it )
00330     {
00331         const YItem * item = *it;
00332 
00333         if ( item->selected() )
00334             return *it;
00335 
00336         if ( item->hasChildren() )
00337         {
00338             YItem * selectedItem = findSelectedItem( item->childrenBegin(),
00339                                                      item->childrenEnd() );
00340             if ( selectedItem )
00341             {
00342                 // yuiDebug() << "Selected item: \"" << selectedItem->label() << "\"" << endl;
00343                 return selectedItem;
00344             }
00345         }
00346     }
00347 
00348     return 0;
00349 }
00350 
00351 
00352 YItemCollection
00353 YSelectionWidget::selectedItems()
00354 {
00355     YItemCollection selectedItems;
00356     findSelectedItems( selectedItems, itemsBegin(), itemsEnd() );
00357 
00358     return selectedItems;
00359 }
00360 
00361 
00362 void
00363 YSelectionWidget::findSelectedItems( YItemCollection &  selectedItems,
00364                                      YItemConstIterator begin,
00365                                      YItemConstIterator end )
00366 {
00367     for ( YItemConstIterator it = begin; it != end; ++it )
00368     {
00369         YItem * item = *it;
00370 
00371         if ( item->selected() )
00372             selectedItems.push_back( item );
00373 
00374         if ( item->hasChildren() )
00375         {
00376             findSelectedItems( selectedItems,
00377                                item->childrenBegin(),
00378                                item->childrenEnd() );
00379         }
00380     }
00381 }
00382 
00383 
00384 bool YSelectionWidget::hasSelectedItem()
00385 {
00386     return selectedItem() != 0;
00387 }
00388 
00389 
00390 void YSelectionWidget::selectItem( YItem * item, bool selected )
00391 {
00392     YUI_CHECK_PTR( item );
00393 
00394     if ( ! itemsContain( item ) )
00395         YUI_THROW( YUIException( "Item does not belong to this widget" ) );
00396 
00397     if ( priv->enforceSingleSelection && selected )
00398     {
00399         YItem * oldSelectedItem = selectedItem();
00400 
00401         if ( oldSelectedItem )
00402             oldSelectedItem->setSelected( false );
00403     }
00404 
00405 
00406     if ( recursiveSelection() && item->hasChildren() )
00407     {
00408         for ( YItemIterator it = item->childrenBegin(); it != item->childrenEnd(); ++it )
00409         {
00410             YItem * item = *it;
00411             selectItem(item, selected );
00412             item->setSelected( selected );
00413         }
00414     }
00415 
00416     item->setSelected( selected );
00417 }
00418 
00419 
00420 bool YSelectionWidget::itemsContain( YItem * wantedItem ) const
00421 {
00422     return itemsContain( wantedItem, itemsBegin(), itemsEnd() );
00423 }
00424 
00425 
00426 
00427 bool
00428 YSelectionWidget::itemsContain( YItem *                 wantedItem,
00429                                 YItemConstIterator      begin,
00430                                 YItemConstIterator      end ) const
00431 {
00432     for ( YItemConstIterator it = begin; it != end; ++it )
00433     {
00434         const YItem * item = *it;
00435 
00436         if ( item == wantedItem )
00437             return true;
00438 
00439         if ( item->hasChildren() )
00440         {
00441             if ( itemsContain( wantedItem,
00442                                item->childrenBegin(),
00443                                item->childrenEnd() ) )
00444             {
00445                 return true;
00446             }
00447         }
00448     }
00449 
00450     return false;
00451 }
00452 
00453 
00454 void YSelectionWidget::deselectAllItems()
00455 {
00456     deselectAllItems( itemsBegin(), itemsEnd() );
00457 }
00458 
00459 
00460 void YSelectionWidget::deselectAllItems( YItemIterator  begin,
00461                                          YItemIterator  end )
00462 {
00463     for ( YItemConstIterator it = begin; it != end; ++it )
00464     {
00465         YItem * item = *it;
00466 
00467         item->setSelected( false );
00468 
00469         if ( item->hasChildren() )
00470             deselectAllItems( item->childrenBegin(), item->childrenEnd() );
00471     }
00472 }
00473 
00474 
00475 YItem *
00476 YSelectionWidget::findItem( const std::string & wantedItemLabel ) const
00477 {
00478     return findItem( wantedItemLabel, itemsBegin(), itemsEnd() );
00479 }
00480 
00481 
00482 YItem *
00483 YSelectionWidget::findItem( const std::string & wantedItemLabel,
00484                             YItemConstIterator  begin,
00485                             YItemConstIterator  end ) const
00486 {
00487     for ( YItemConstIterator it = begin; it != end; ++it )
00488     {
00489         YItem * item = *it;
00490 
00491         if ( item->label() == wantedItemLabel )
00492             return item;
00493 
00494         if ( item->hasChildren() )
00495         {
00496             YItem * wantedItem = findItem( wantedItemLabel,
00497                                            item->childrenBegin(),
00498                                            item->childrenEnd() );
00499             if ( wantedItem )
00500                 return wantedItem;
00501         }
00502     }
00503 
00504     return 0;
00505 }
 All Classes Functions Variables Enumerations Friends