libyui
3.0.10
|
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 }