libyui  3.3.3
YSelectionWidget.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: YSelectionWidget.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 
26 #define YUILogComponent "ui"
27 #include "YUILog.h"
28 
29 #include <algorithm>
30 #include "YSelectionWidget.h"
31 #include "YUIException.h"
32 #include "YApplication.h"
33 
34 
36 {
37  YSelectionWidgetPrivate( const std::string & label,
38  bool enforceSingleSelection,
39  bool recursiveSelection )
40  : label( label )
41  , enforceSingleSelection( enforceSingleSelection )
42  , recursiveSelection ( recursiveSelection )
43  {}
44 
45  std::string label;
46  bool enforceSingleSelection;
47  bool recursiveSelection;
48  std::string iconBasePath;
49  YItemCollection itemCollection;
50 };
51 
52 
53 
54 
56  const std::string & label,
57  bool enforceSingleSelection ,
58  bool recursiveSelection )
59  : YWidget( parent )
60  , priv( new YSelectionWidgetPrivate( label, enforceSingleSelection, recursiveSelection ) )
61 {
62  YUI_CHECK_NEW( priv );
63 
65  YUI_THROW( YUIException( "recursiveSelection is only available for multiSelection Widgets."));
66 
67 }
68 
69 
71 {
73 }
74 
75 
77 {
79 
80  while ( it != itemsEnd() )
81  {
82  YItem * item = *it;
83  ++it;
84  delete item;
85 
86  // No need to check for item->hasChildren() and iterate recursively
87  // over the children: The item will take care of its children in its
88  // destructor.
89  }
90 
91  priv->itemCollection.clear();
92 }
93 
94 
95 std::string YSelectionWidget::label() const
96 {
97  return priv->label;
98 }
99 
100 
101 void YSelectionWidget::setLabel( const std::string & newLabel )
102 {
103  priv->label = newLabel;
104 }
105 
106 
108 {
109  return priv->enforceSingleSelection;
110 }
111 
113 {
114  return priv->recursiveSelection;
115 }
116 
117 
118 
119 void YSelectionWidget::setEnforceSingleSelection( bool enforceSingleSelection )
120 {
121  priv->enforceSingleSelection = enforceSingleSelection;
122 }
123 
124 
125 void YSelectionWidget::setIconBasePath( const std::string & basePath )
126 {
127  priv->iconBasePath = basePath;
128 }
129 
130 
132 {
133  return priv->iconBasePath;
134 }
135 
136 
137 std::string YSelectionWidget::iconFullPath( const std::string & iconName ) const
138 {
139  std::string fullPath;
140 
141  if ( ! iconName.empty() )
142  {
143  if ( iconName[0] == '/' )
144  return iconName;
145 
146  if ( priv->iconBasePath.empty() ||
147  priv->iconBasePath[0] != '/' )
148  {
149  return YUI::yApp()->iconLoader()->findIcon( iconName );
150  }
151 
152  fullPath += priv->iconBasePath + "/" + iconName;
153  }
154 
155  return fullPath;
156 }
157 
158 
159 std::string YSelectionWidget::iconFullPath( YItem * item ) const
160 {
161  if ( item )
162  return iconFullPath( item->iconName() );
163  else
164  return "";
165 }
166 
167 
169 {
170  YUI_CHECK_PTR( item );
171 
172  if ( item->parent() )
173  {
174  YUI_THROW( YUIException( "Item already owned by parent item -"
175  " call addItem() only for toplevel items!" ) );
176  }
177 
178  // Add the new item to the item list
179 
180  priv->itemCollection.push_back( item );
181  item->setIndex( priv->itemCollection.size() - 1 );
182 
183  // yuiDebug() << "Adding item \"" << item->label() << "\"" << endl;
184 
185  //
186  // Enforce single selection (if applicable)
187  //
188 
189  if ( priv->enforceSingleSelection )
190  {
191  YItem* newItemSelected = NULL;
192  if ( item->selected() )
193  {
194  newItemSelected = item;
195  }
196  else
197  {
198  newItemSelected = findSelectedItem( item->childrenBegin(),
199  item->childrenEnd() );
200  }
201 
202  if ( newItemSelected )
203  {
204  // This looks expensive, but it is not: Even though deselectAllItems()
205  // searches the complete item list and de select all.
206  //
207  // This prevents the calling application does this systematically wrong
208  // and sets the "selected" flag for more items or children
210  newItemSelected->setSelected( true );
211  }
212 
213 
214  // Make sure there is one item selected initially.
215  //
216  // If any other subsequently added items are to be selected, they will
217  // override this initial selection.
218 
219  if ( priv->itemCollection.size() == 1 )
220  item->setSelected( true );
221  }
222 }
223 
224 
225 void YSelectionWidget::addItem( const std::string & itemLabel,
226  const std::string & iconName,
227  bool selected )
228 {
229  YItem * item = new YItem( itemLabel, iconName, selected );
230  YUI_CHECK_NEW( item );
231  addItem( item );
232 }
233 
234 
235 void YSelectionWidget::addItem( const std::string & itemLabel, bool selected )
236 {
237  addItem( itemLabel, "", selected );
238 }
239 
240 
241 void YSelectionWidget::addItems( const YItemCollection & itemCollection )
242 {
243  OptimizeChanges below( *this ); // Delay screen updates until this block is left
244  priv->itemCollection.reserve( priv->itemCollection.size() + itemCollection.size() );
245 
246  for ( YItemConstIterator it = itemCollection.begin();
247  it != itemCollection.end();
248  ++it )
249  {
250  addItem( *it );
251 
252  // No need to check for (*it)->hasChildren() and iterate recursively
253  // over the children: Any children of this item simply remain in this
254  // item's YItemCollection.
255  }
256 }
257 
258 
261 {
262  return priv->itemCollection.begin();
263 }
264 
267 {
268  return priv->itemCollection.begin();
269 }
270 
271 
274 {
275  return priv->itemCollection.end();
276 }
277 
278 
281 {
282  return priv->itemCollection.end();
283 }
284 
285 
287 {
288  return ! priv->itemCollection.empty();
289 }
290 
291 
293 {
294  return priv->itemCollection.size();
295 }
296 
297 
298 YItem *
300 {
301  if ( priv->itemCollection.empty() )
302  return 0;
303  else
304  return priv->itemCollection.front();
305 }
306 
307 
308 YItem *
309 YSelectionWidget::itemAt( int index ) const
310 {
311  if ( index < 0 || index >= (int) priv->itemCollection.size() )
312  return 0;
313 
314  return priv->itemCollection[ index ];
315 }
316 
317 
318 YItem *
320 {
321  return findSelectedItem( itemsBegin(), itemsEnd() );
322 }
323 
324 
325 YItem *
327  YItemConstIterator end )
328 {
329  for ( YItemConstIterator it = begin; it != end; ++it )
330  {
331  const YItem * item = *it;
332 
333  if ( item->selected() )
334  {
335  return *it;
336  }
337  if ( item->hasChildren() )
338  {
340  item->childrenEnd() );
341  if ( selectedItem )
342  {
343  // yuiDebug() << "Selected item: \"" << selectedItem->label() << "\"" << endl;
344  return selectedItem;
345  }
346  }
347  }
348 
349  return 0;
350 }
351 
352 
355 {
358 
359  return selectedItems;
360 }
361 
362 
363 void
365  YItemConstIterator begin,
366  YItemConstIterator end )
367 {
368  for ( YItemConstIterator it = begin; it != end; ++it )
369  {
370  YItem * item = *it;
371 
372  if ( item->selected() )
373  selectedItems.push_back( item );
374 
375  if ( item->hasChildren() )
376  {
378  item->childrenBegin(),
379  item->childrenEnd() );
380  }
381  }
382 }
383 
384 
386 {
387  return selectedItem() != 0;
388 }
389 
390 
391 void YSelectionWidget::selectItem( YItem * item, bool selected )
392 {
393  YUI_CHECK_PTR( item );
394 
395  if ( ! itemsContain( item ) )
396  YUI_THROW( YUIException( "Item does not belong to this widget" ) );
397 
398  if ( priv->enforceSingleSelection && selected )
399  {
400  YItem * oldSelectedItem = selectedItem();
401 
402  if ( oldSelectedItem )
403  oldSelectedItem->setSelected( false );
404  }
405 
406 
407  if ( recursiveSelection() && item->hasChildren() )
408  {
409  for ( YItemIterator it = item->childrenBegin(); it != item->childrenEnd(); ++it )
410  {
411  YItem * item = *it;
412  selectItem(item, selected );
413  item->setSelected( selected );
414  }
415  }
416 
417  item->setSelected( selected );
418 }
419 
420 
421 bool YSelectionWidget::itemsContain( YItem * wantedItem ) const
422 {
423  return itemsContain( wantedItem, itemsBegin(), itemsEnd() );
424 }
425 
426 
427 
428 bool
430  YItemConstIterator begin,
431  YItemConstIterator end ) const
432 {
433  for ( YItemConstIterator it = begin; it != end; ++it )
434  {
435  const YItem * item = *it;
436 
437  if ( item == wantedItem )
438  return true;
439 
440  if ( item->hasChildren() )
441  {
442  if ( itemsContain( wantedItem,
443  item->childrenBegin(),
444  item->childrenEnd() ) )
445  {
446  return true;
447  }
448  }
449  }
450 
451  return false;
452 }
453 
454 
456 {
458 }
459 
460 
462  YItemIterator end )
463 {
464  for ( YItemConstIterator it = begin; it != end; ++it )
465  {
466  YItem * item = *it;
467 
468  item->setSelected( false );
469 
470  if ( item->hasChildren() )
471  deselectAllItems( item->childrenBegin(), item->childrenEnd() );
472  }
473 }
474 
475 
476 YItem *
477 YSelectionWidget::findItem( const std::string & wantedItemLabel ) const
478 {
479  return findItem( wantedItemLabel, itemsBegin(), itemsEnd() );
480 }
481 
482 
483 YItem *
484 YSelectionWidget::findItem( const std::string & wantedItemLabel,
485  YItemConstIterator begin,
486  YItemConstIterator end ) const
487 {
488  for ( YItemConstIterator it = begin; it != end; ++it )
489  {
490  YItem * item = *it;
491 
492  if ( item->label() == wantedItemLabel )
493  return item;
494 
495  if ( item->hasChildren() )
496  {
497  YItem * wantedItem = findItem( wantedItemLabel,
498  item->childrenBegin(),
499  item->childrenEnd() );
500  if ( wantedItem )
501  return wantedItem;
502  }
503  }
504 
505  return 0;
506 }
YItemCollection::iterator YItemIterator
Mutable iterator over YItemCollection.
Definition: YItem.h:40
std::string label() const
Return this widget's label (the caption above the item list).
virtual void selectItem(YItem *item, bool selected=true)
Select or deselect an item.
std::string label() const
Return this item's label.
Definition: YItem.h:82
bool selected() const
Return 'true' if this item is currently selected.
Definition: YItem.h:107
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
YItemIterator itemsEnd()
Return an iterator that points behind the last item.
void setIndex(int index)
Set this item's index.
Definition: YItem.h:119
virtual void setLabel(const std::string &newLabel)
Change this widget's label (the caption above the item list).
YItem * firstItem() const
Return the first item or 0 if there is none.
YWidgetListIterator end()
A helper for the range-based "for" loop.
Definition: YWidget.h:245
virtual YItemIterator childrenBegin()
Return an iterator that points to the first child item of this item.
Definition: YItem.h:172
std::vector< YItem * > YItemCollection
Collection of pointers to YItem.
Definition: YItem.h:38
std::string iconName() const
Return this item's icon name.
Definition: YItem.h:92
YSelectionWidget(YWidget *parent, const std::string &label, bool enforceSingleSelection, bool recurisveSelection=false)
Constructor.
virtual bool hasChildren() const
Return 'true' if this item has any child items.
Definition: YItem.h:153
void setEnforceSingleSelection(bool on)
Set single selection mode on or off.
void setSelected(bool sel=true)
Select or unselect this item.
Definition: YItem.h:114
virtual YItemCollection selectedItems()
Return all selected items.
void findSelectedItems(YItemCollection &selectedItems, YItemConstIterator begin, YItemConstIterator end)
Recursively find all selected items between iterators 'begin' and 'end' and add each of them to the '...
YItemIterator itemsBegin()
Return an iterator that points to the first item.
virtual YItem * parent() const
Returns this item's parent item or 0 if it is a toplevel item.
Definition: YItem.h:189
virtual void deleteAllItems()
Delete all items.
int itemsCount() const
Return the number of items.
bool itemsContain(YItem *item) const
Return 'true' if this widget's items contain the specified item.
virtual YItem * selectedItem()
Return the (first) selected item or 0 if none is selected.
bool hasSelectedItem()
Return 'true' if any item is selected.
virtual void addItem(YItem *item_disown)
Add one item.
Simple item class for SelectionBox, ComboBox, MultiSelectionBox etc.
Definition: YItem.h:49
YItemCollection::const_iterator YItemConstIterator
Const iterator over YItemCollection.
Definition: YItem.h:42
virtual YItemIterator childrenEnd()
Return an iterator that points after the last child item of this item.
Definition: YItem.h:181
virtual void deselectAllItems()
Deselect all items.
void setIconBasePath(const std::string &basePath)
Set this widget's base path where to look up icons.
virtual ~YSelectionWidget()
Destructor.
Helper class that calls startMultipleChanges() in its constructor and cares about the necessary call ...
Definition: YWidget.h:45
YWidgetListIterator begin()
A helper for the range-based "for" loop.
Definition: YWidget.h:238
bool recursiveSelection() const
Return 'true' if this base class should select children recursively.
YItem * findSelectedItem(YItemConstIterator begin, YItemConstIterator end)
Recursively try to find the first selected item between iterators 'begin' and 'end'.
YItem * itemAt(int index) const
Return the item at index 'index' (from 0) or 0 if there is no such item.
Abstract base class of all UI widgets.
Definition: YWidget.h:54
bool hasItems() const
Return 'true' if this widget has any items.
Base class for UI Exceptions.
Definition: YUIException.h:297
bool enforceSingleSelection() const
Return 'true' if this base class should enforce single selection.
YItem * findItem(const std::string &itemLabel) const
Find the (first) item with the specified label.
std::string iconBasePath() const
Return this widget's base path where to look up icons as set with setIconBasePath().
std::string iconFullPath(const std::string &iconName) const
Return the full path + file name for the specified icon name.