libyui  3.4.2
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 
64  if ( enforceSingleSelection && recursiveSelection )
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 
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 *
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 {
357  findSelectedItems( selectedItems, itemsBegin(), itemsEnd() );
358 
359  return selectedItems;
360 }
361 
362 
363 void
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  {
377  findSelectedItems( selectedItems,
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
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 
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,
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&#39;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&#39;s label.
Definition: YItem.h:82
bool selected() const
Return &#39;true&#39; 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&#39;s index.
Definition: YItem.h:119
virtual void setLabel(const std::string &newLabel)
Change this widget&#39;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&#39;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 &#39;true&#39; 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 &#39;begin&#39; and &#39;end&#39; and add each of them to the &#39;...
YItemIterator itemsBegin()
Return an iterator that points to the first item.
virtual YItem * parent() const
Returns this item&#39;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 &#39;true&#39; if this widget&#39;s items contain the specified item.
virtual YItem * selectedItem()
Return the (first) selected item or 0 if none is selected.
bool hasSelectedItem()
Return &#39;true&#39; 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&#39;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 &#39;true&#39; if this base class should select children recursively.
YItem * findSelectedItem(YItemConstIterator begin, YItemConstIterator end)
Recursively try to find the first selected item between iterators &#39;begin&#39; and &#39;end&#39;.
YItem * itemAt(int index) const
Return the item at index &#39;index&#39; (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 &#39;true&#39; if this widget has any items.
Base class for UI Exceptions.
Definition: YUIException.h:297
bool enforceSingleSelection() const
Return &#39;true&#39; 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&#39;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.