libyui  3.1.4
 All Classes Files Functions Variables Typedefs Enumerations Friends Pages
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 
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  if ( item->selected() )
192  {
193  YItem * oldSelectedItem = selectedItem();
194 
195  // This looks expensive, but it is not: Even though selectedItem()
196  // searches the complete item list until it finds a selected item,
197  // this happens only if a new item is to be inserted that has the
198  // "selected" flag on. In the normal case, this will only be one
199  // item.
200  //
201  // Only if the calling application does this systematically wrong
202  // and sets the "selected" flag for ALL items it inserts this will
203  // be more expensive. But then, this is a bug in that application
204  // that needs to be fixed.
205 
206  if ( oldSelectedItem && oldSelectedItem != item )
207  {
208  oldSelectedItem->setSelected( false );
209  item->setSelected( true );
210  }
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  return *it;
335 
336  if ( item->hasChildren() )
337  {
339  item->childrenEnd() );
340  if ( selectedItem )
341  {
342  // yuiDebug() << "Selected item: \"" << selectedItem->label() << "\"" << endl;
343  return selectedItem;
344  }
345  }
346  }
347 
348  return 0;
349 }
350 
351 
354 {
356  findSelectedItems( selectedItems, itemsBegin(), itemsEnd() );
357 
358  return selectedItems;
359 }
360 
361 
362 void
364  YItemConstIterator begin,
365  YItemConstIterator end )
366 {
367  for ( YItemConstIterator it = begin; it != end; ++it )
368  {
369  YItem * item = *it;
370 
371  if ( item->selected() )
372  selectedItems.push_back( item );
373 
374  if ( item->hasChildren() )
375  {
376  findSelectedItems( selectedItems,
377  item->childrenBegin(),
378  item->childrenEnd() );
379  }
380  }
381 }
382 
383 
385 {
386  return selectedItem() != 0;
387 }
388 
389 
390 void YSelectionWidget::selectItem( YItem * item, bool selected )
391 {
392  YUI_CHECK_PTR( item );
393 
394  if ( ! itemsContain( item ) )
395  YUI_THROW( YUIException( "Item does not belong to this widget" ) );
396 
397  if ( priv->enforceSingleSelection && selected )
398  {
399  YItem * oldSelectedItem = selectedItem();
400 
401  if ( oldSelectedItem )
402  oldSelectedItem->setSelected( false );
403  }
404 
405 
406  if ( recursiveSelection() && item->hasChildren() )
407  {
408  for ( YItemIterator it = item->childrenBegin(); it != item->childrenEnd(); ++it )
409  {
410  YItem * item = *it;
411  selectItem(item, selected );
412  item->setSelected( selected );
413  }
414  }
415 
416  item->setSelected( selected );
417 }
418 
419 
420 bool YSelectionWidget::itemsContain( YItem * wantedItem ) const
421 {
422  return itemsContain( wantedItem, itemsBegin(), itemsEnd() );
423 }
424 
425 
426 
427 bool
429  YItemConstIterator begin,
430  YItemConstIterator end ) const
431 {
432  for ( YItemConstIterator it = begin; it != end; ++it )
433  {
434  const YItem * item = *it;
435 
436  if ( item == wantedItem )
437  return true;
438 
439  if ( item->hasChildren() )
440  {
441  if ( itemsContain( wantedItem,
442  item->childrenBegin(),
443  item->childrenEnd() ) )
444  {
445  return true;
446  }
447  }
448  }
449 
450  return false;
451 }
452 
453 
455 {
457 }
458 
459 
461  YItemIterator end )
462 {
463  for ( YItemConstIterator it = begin; it != end; ++it )
464  {
465  YItem * item = *it;
466 
467  item->setSelected( false );
468 
469  if ( item->hasChildren() )
470  deselectAllItems( item->childrenBegin(), item->childrenEnd() );
471  }
472 }
473 
474 
475 YItem *
476 YSelectionWidget::findItem( const std::string & wantedItemLabel ) const
477 {
478  return findItem( wantedItemLabel, itemsBegin(), itemsEnd() );
479 }
480 
481 
482 YItem *
483 YSelectionWidget::findItem( const std::string & wantedItemLabel,
484  YItemConstIterator begin,
485  YItemConstIterator end ) const
486 {
487  for ( YItemConstIterator it = begin; it != end; ++it )
488  {
489  YItem * item = *it;
490 
491  if ( item->label() == wantedItemLabel )
492  return item;
493 
494  if ( item->hasChildren() )
495  {
496  YItem * wantedItem = findItem( wantedItemLabel,
497  item->childrenBegin(),
498  item->childrenEnd() );
499  if ( wantedItem )
500  return wantedItem;
501  }
502  }
503 
504  return 0;
505 }
YItemCollection::iterator YItemIterator
Mutable iterator over YItemCollection.
Definition: YItem.h:40
virtual void selectItem(YItem *item, bool selected=true)
Select or deselect an item.
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
bool recursiveSelection() const
Return 'true' if this base class should select children recursively.
YItemIterator itemsEnd()
Return an iterator that points behind the last item.
virtual YItem * parent() const
Returns this item's parent item or 0 if it is a toplevel item.
Definition: YItem.h:189
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).
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
YSelectionWidget(YWidget *parent, const std::string &label, bool enforceSingleSelection, bool recurisveSelection=false)
Constructor.
std::string iconFullPath(const std::string &iconName) const
Return the full path + file name for the specified icon name.
std::string iconBasePath() const
Return this widget's base path where to look up icons as set with setIconBasePath().
void setEnforceSingleSelection(bool on)
Set single selection mode on or off.
YItem * firstItem() const
Return the first item or 0 if there is none.
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.
YItem * itemAt(int index) const
Return the item at index 'index' (from 0) or 0 if there is no such item.
virtual void deleteAllItems()
Delete all items.
int itemsCount() const
Return the number of items.
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
bool itemsContain(YItem *item) const
Return 'true' if this widget's items contain the specified item.
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
std::string label() const
Return this widget's label (the caption above the item list).
bool enforceSingleSelection() const
Return 'true' if this base class should enforce single selection.
virtual bool hasChildren() const
Return 'true' if this item has any child items.
Definition: YItem.h:153
bool selected() const
Return 'true' if this item is currently selected.
Definition: YItem.h:107
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.
std::string iconName() const
Return this item's icon name.
Definition: YItem.h:92
Helper class that calls startMultipleChanges() in its constructor and cares about the necessary call ...
Definition: YWidget.h:45
bool hasItems() const
Return 'true' if this widget has any items.
YItem * findItem(const std::string &itemLabel) const
Find the (first) item with the specified label.
YItem * findSelectedItem(YItemConstIterator begin, YItemConstIterator end)
Recursively try to find the first selected item between iterators 'begin' and 'end'.
Abstract base class of all UI widgets.
Definition: YWidget.h:54
Base class for UI Exceptions.
Definition: YUIException.h:281
std::string label() const
Return this item's label.
Definition: YItem.h:82