libyui  3.10.0
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 <shundhammer@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 using std::string;
35 
36 
38 {
39  YSelectionWidgetPrivate( const string & label,
40  bool enforceSingleSelection,
41  bool recursiveSelection )
42  : label( label )
43  , enforceSingleSelection( enforceSingleSelection )
44  , enforceInitialSelection( true )
45  , recursiveSelection ( recursiveSelection )
46  {}
47 
48  string label;
49  bool enforceSingleSelection;
50  bool enforceInitialSelection;
51  bool recursiveSelection;
52  string iconBasePath;
53  YItemCollection itemCollection;
54 };
55 
56 
57 
58 
60  const string & label,
61  bool enforceSingleSelection ,
62  bool recursiveSelection )
63  : YWidget( parent )
64  , priv( new YSelectionWidgetPrivate( label, enforceSingleSelection, recursiveSelection ) )
65 {
66  YUI_CHECK_NEW( priv );
67 
69  YUI_THROW( YUIException( "recursiveSelection is only available for multiSelection Widgets."));
70 
71 }
72 
73 
75 {
77 }
78 
79 
81 {
83 
84  while ( it != itemsEnd() )
85  {
86  YItem * item = *it;
87  ++it;
88  delete item;
89 
90  // No need to check for item->hasChildren() and iterate recursively
91  // over the children: The item will take care of its children in its
92  // destructor.
93  }
94 
95  priv->itemCollection.clear();
96 }
97 
98 
100 {
101  return priv->label;
102 }
103 
104 
105 void YSelectionWidget::setLabel( const string & newLabel )
106 {
107  priv->label = newLabel;
108 }
109 
110 
112 {
113  return priv->enforceSingleSelection;
114 }
115 
116 
118 {
119  if ( priv->enforceSingleSelection )
120  priv->enforceInitialSelection = newVal;
121 }
122 
123 
125 {
126  return priv->enforceInitialSelection && priv->enforceSingleSelection;
127 }
128 
129 
131 {
132  return priv->recursiveSelection;
133 }
134 
135 
136 
137 void YSelectionWidget::setEnforceSingleSelection( bool enforceSingleSelection )
138 {
139  priv->enforceSingleSelection = enforceSingleSelection;
140 }
141 
142 
143 void YSelectionWidget::setIconBasePath( const string & basePath )
144 {
145  priv->iconBasePath = basePath;
146 }
147 
148 
150 {
151  return priv->iconBasePath;
152 }
153 
154 
155 string YSelectionWidget::iconFullPath( const string & iconName ) const
156 {
157  string fullPath;
158 
159  if ( ! iconName.empty() )
160  {
161  if ( iconName[0] == '/' )
162  return iconName;
163 
164  if ( priv->iconBasePath.empty() ||
165  priv->iconBasePath[0] != '/' )
166  {
167  return YUI::yApp()->iconLoader()->findIcon( iconName );
168  }
169 
170  fullPath += priv->iconBasePath + "/" + iconName;
171  }
172 
173  return fullPath;
174 }
175 
176 
177 string YSelectionWidget::iconFullPath( YItem * item ) const
178 {
179  if ( item )
180  return iconFullPath( item->iconName() );
181  else
182  return "";
183 }
184 
185 
187 {
188  YUI_CHECK_PTR( item );
189 
190  if ( item->parent() )
191  {
192  YUI_THROW( YUIException( "Item already owned by parent item -"
193  " call addItem() only for toplevel items!" ) );
194  }
195 
196  // Add the new item to the item list
197 
198  priv->itemCollection.push_back( item );
199  item->setIndex( priv->itemCollection.size() - 1 );
200 
201  // yuiDebug() << "Adding item \"" << item->label() << "\"" << endl;
202 
203  //
204  // Enforce single selection (if applicable)
205  //
206 
207  if ( priv->enforceSingleSelection )
208  {
209  YItem * newItemSelected = 0;
210 
211  if ( item->selected() )
212  {
213  newItemSelected = item;
214  }
215  else
216  {
217  newItemSelected = findSelectedItem( item->childrenBegin(),
218  item->childrenEnd() );
219  }
220 
221  if ( newItemSelected )
222  {
223  // This looks expensive, but it is not: Even though deselectAllItems()
224  // searches the complete item list and deselects them all.
225  //
226  // This prevents that the calling application does this systematically wrong
227  // and sets the "selected" flag for more items or children.
228 
230  newItemSelected->setSelected( true );
231  }
232 
233 
234  if ( priv->enforceInitialSelection )
235  {
236  // Make sure there is one item selected initially.
237  //
238  // If any other subsequently added items are to be selected, they will
239  // override this initial selection.
240 
241  if ( priv->itemCollection.size() == 1 )
242  item->setSelected( true );
243  }
244  }
245 }
246 
247 
248 void YSelectionWidget::addItem( const string & itemLabel,
249  const string & iconName,
250  bool selected )
251 {
252  YItem * item = new YItem( itemLabel, iconName, selected );
253  YUI_CHECK_NEW( item );
254  addItem( item );
255 }
256 
257 
258 void YSelectionWidget::addItem( const string & itemLabel, bool selected )
259 {
260  addItem( itemLabel, "", selected );
261 }
262 
263 
264 void YSelectionWidget::addItems( const YItemCollection & itemCollection )
265 {
266  OptimizeChanges below( *this ); // Delay screen updates until this block is left
267  priv->itemCollection.reserve( priv->itemCollection.size() + itemCollection.size() );
268 
269  for ( YItemConstIterator it = itemCollection.begin();
270  it != itemCollection.end();
271  ++it )
272  {
273  addItem( *it );
274 
275  // No need to check for (*it)->hasChildren() and iterate recursively
276  // over the children: Any children of this item simply remain in this
277  // item's YItemCollection.
278  }
279 }
280 
281 
284 {
285  return priv->itemCollection.begin();
286 }
287 
290 {
291  return priv->itemCollection.begin();
292 }
293 
294 
297 {
298  return priv->itemCollection.end();
299 }
300 
301 
304 {
305  return priv->itemCollection.end();
306 }
307 
308 
310 {
311  return ! priv->itemCollection.empty();
312 }
313 
314 
316 {
317  return priv->itemCollection.size();
318 }
319 
320 
321 YItem *
323 {
324  if ( priv->itemCollection.empty() )
325  return 0;
326  else
327  return priv->itemCollection.front();
328 }
329 
330 
331 YItem *
332 YSelectionWidget::itemAt( int index ) const
333 {
334  if ( index < 0 || index >= (int) priv->itemCollection.size() )
335  return 0;
336 
337  return priv->itemCollection[ index ];
338 }
339 
340 
341 YItem *
343 {
344  return findSelectedItem( itemsBegin(), itemsEnd() );
345 }
346 
347 
348 YItem *
350  YItemConstIterator end )
351 {
352  for ( YItemConstIterator it = begin; it != end; ++it )
353  {
354  const YItem * item = *it;
355 
356  if ( item->selected() )
357  {
358  return *it;
359  }
360  if ( item->hasChildren() )
361  {
363  item->childrenEnd() );
364  if ( selectedItem )
365  {
366  // yuiDebug() << "Selected item: \"" << selectedItem->label() << "\"" << endl;
367  return selectedItem;
368  }
369  }
370  }
371 
372  return 0;
373 }
374 
375 
378 {
381 
382  return selectedItems;
383 }
384 
385 
386 void
388  YItemConstIterator begin,
389  YItemConstIterator end )
390 {
391  for ( YItemConstIterator it = begin; it != end; ++it )
392  {
393  YItem * item = *it;
394 
395  if ( item->selected() )
396  selectedItems.push_back( item );
397 
398  if ( item->hasChildren() )
399  {
401  item->childrenBegin(),
402  item->childrenEnd() );
403  }
404  }
405 }
406 
407 
409 {
410  return selectedItem() != 0;
411 }
412 
413 
414 void YSelectionWidget::selectItem( YItem * item, bool selected )
415 {
416  YUI_CHECK_PTR( item );
417 
418  if ( ! itemsContain( item ) )
419  YUI_THROW( YUIException( "Item does not belong to this widget" ) );
420 
421  if ( priv->enforceSingleSelection && selected )
422  {
423  YItem * oldSelectedItem = selectedItem();
424 
425  if ( oldSelectedItem )
426  oldSelectedItem->setSelected( false );
427  }
428 
429 
430  if ( recursiveSelection() && item->hasChildren() )
431  {
432  for ( YItemIterator it = item->childrenBegin(); it != item->childrenEnd(); ++it )
433  {
434  YItem * item = *it;
435  selectItem(item, selected );
436  item->setSelected( selected );
437  }
438  }
439 
440  item->setSelected( selected );
441 }
442 
443 
444 void YSelectionWidget::setItemStatus( YItem * item, int status )
445 {
446  selectItem( item, status != 0 );
447 }
448 
449 
450 bool YSelectionWidget::itemsContain( YItem * wantedItem ) const
451 {
452  return itemsContain( wantedItem, itemsBegin(), itemsEnd() );
453 }
454 
455 
456 
457 bool
459  YItemConstIterator begin,
460  YItemConstIterator end ) const
461 {
462  for ( YItemConstIterator it = begin; it != end; ++it )
463  {
464  const YItem * item = *it;
465 
466  if ( item == wantedItem )
467  return true;
468 
469  if ( item->hasChildren() )
470  {
471  if ( itemsContain( wantedItem,
472  item->childrenBegin(),
473  item->childrenEnd() ) )
474  {
475  return true;
476  }
477  }
478  }
479 
480  return false;
481 }
482 
483 
485 {
487 }
488 
489 
491  YItemIterator end )
492 {
493  for ( YItemConstIterator it = begin; it != end; ++it )
494  {
495  YItem * item = *it;
496 
497  item->setSelected( false );
498 
499  if ( item->hasChildren() )
500  deselectAllItems( item->childrenBegin(), item->childrenEnd() );
501  }
502 }
503 
504 
505 YItem *
506 YSelectionWidget::findItem( const string & wantedItemLabel ) const
507 {
508  return findItem( wantedItemLabel, itemsBegin(), itemsEnd() );
509 }
510 
511 
512 YItem *
513 YSelectionWidget::findItem( const string & wantedItemLabel,
514  YItemConstIterator begin,
515  YItemConstIterator end ) const
516 {
517  for ( YItemConstIterator it = begin; it != end; ++it )
518  {
519  YItem * item = *it;
520 
521  if ( item->label() == wantedItemLabel )
522  return item;
523 
524  if ( item->hasChildren() )
525  {
526  YItem * wantedItem = findItem( wantedItemLabel,
527  item->childrenBegin(),
528  item->childrenEnd() );
529  if ( wantedItem )
530  return wantedItem;
531  }
532  }
533 
534  return 0;
535 }
536 
537 
539 {
540  yuiMilestone() << "Items:" << endl;
541 
542  for ( YItemConstIterator it = itemsBegin(); it != itemsEnd(); ++it )
543  {
544  string status;
545 
546  switch ( (*it)->status() )
547  {
548  case 0: status = "[ ]"; break;
549  case 1: status = "[x]"; break;
550  default:
551  {
552  char buffer[80];
553  sprintf( buffer, "[%d]", (*it)->status() );
554  status = buffer;
555  }
556  }
557 
558  yuiMilestone() << " " << status << " "
559  << (*it)->label()
560  << endl;
561  }
562 
563  yuiMilestone() << "---" << endl;
564 }
YItem::label
std::string label() const
Return this item's label.
Definition: YItem.h:82
YWidget
Abstract base class of all UI widgets.
Definition: YWidget.h:55
YSelectionWidget::selectedItems
virtual YItemCollection selectedItems()
Return all selected items.
Definition: YSelectionWidget.cc:377
YWidget::end
YWidgetListIterator end()
A helper for the range-based "for" loop.
Definition: YWidget.h:245
YItem::setIndex
void setIndex(int index)
Set this item's index.
Definition: YItem.h:133
YItemIterator
YItemCollection::iterator YItemIterator
Mutable iterator over YItemCollection.
Definition: YItem.h:40
YItemCollection
std::vector< YItem * > YItemCollection
Collection of pointers to YItem.
Definition: YItem.h:38
YSelectionWidget::setItemStatus
virtual void setItemStatus(YItem *item, int status)
Set the status of an item.
Definition: YSelectionWidget.cc:444
YSelectionWidget::hasSelectedItem
bool hasSelectedItem()
Return 'true' if any item is selected.
Definition: YSelectionWidget.cc:408
YItem::childrenBegin
virtual YItemIterator childrenBegin()
Return an iterator that points to the first child item of this item.
Definition: YItem.h:186
YSelectionWidget::~YSelectionWidget
virtual ~YSelectionWidget()
Destructor.
Definition: YSelectionWidget.cc:74
YItem::selected
bool selected() const
Return 'true' if this item is currently selected.
Definition: YItem.h:107
YSelectionWidgetPrivate
Definition: YSelectionWidget.cc:38
YItem::iconName
std::string iconName() const
Return this item's icon name.
Definition: YItem.h:92
YSelectionWidget::itemsEnd
YItemIterator itemsEnd()
Return an iterator that points behind the last item.
Definition: YSelectionWidget.cc:296
YSelectionWidget::selectedItem
virtual YItem * selectedItem()
Return the (first) selected item or 0 if none is selected.
Definition: YSelectionWidget.cc:342
YSelectionWidget::findItem
YItem * findItem(const std::string &itemLabel) const
Find the (first) item with the specified label.
Definition: YSelectionWidget.cc:506
YWidget::begin
YWidgetListIterator begin()
A helper for the range-based "for" loop.
Definition: YWidget.h:238
YSelectionWidget::label
std::string label() const
Return this widget's label (the caption above the item list).
Definition: YSelectionWidget.cc:99
YItem::parent
virtual YItem * parent() const
Returns this item's parent item or 0 if it is a toplevel item.
Definition: YItem.h:203
YSelectionWidget::hasItems
bool hasItems() const
Return 'true' if this widget has any items.
Definition: YSelectionWidget.cc:309
YSelectionWidget::deselectAllItems
virtual void deselectAllItems()
Deselect all items.
Definition: YSelectionWidget.cc:484
YSelectionWidget::enforceSingleSelection
bool enforceSingleSelection() const
Return 'true' if this base class should enforce single selection.
Definition: YSelectionWidget.cc:111
YSelectionWidget::iconBasePath
std::string iconBasePath() const
Return this widget's base path where to look up icons as set with setIconBasePath().
Definition: YSelectionWidget.cc:149
YSelectionWidget::enforceInitialSelection
bool enforceInitialSelection() const
Return 'true' if this class enforces an initial selection.
Definition: YSelectionWidget.cc:124
YItem::hasChildren
virtual bool hasChildren() const
Return 'true' if this item has any child items.
Definition: YItem.h:167
YSelectionWidget::iconFullPath
std::string iconFullPath(const std::string &iconName) const
Return the full path + file name for the specified icon name.
Definition: YSelectionWidget.cc:155
YSelectionWidget::firstItem
YItem * firstItem() const
Return the first item or 0 if there is none.
Definition: YSelectionWidget.cc:322
YSelectionWidget::setEnforceSingleSelection
void setEnforceSingleSelection(bool on)
Set single selection mode on or off.
Definition: YSelectionWidget.cc:137
YSelectionWidget::recursiveSelection
bool recursiveSelection() const
Return 'true' if this base class should select children recursively.
Definition: YSelectionWidget.cc:130
YSelectionWidget::setLabel
virtual void setLabel(const std::string &newLabel)
Change this widget's label (the caption above the item list).
Definition: YSelectionWidget.cc:105
YItem::setSelected
void setSelected(bool sel=true)
Select or unselect this item.
Definition: YItem.h:114
YSelectionWidget::itemAt
YItem * itemAt(int index) const
Return the item at index 'index' (from 0) or 0 if there is no such item.
Definition: YSelectionWidget.cc:332
YSelectionWidget::findSelectedItem
YItem * findSelectedItem(YItemConstIterator begin, YItemConstIterator end)
Recursively try to find the first selected item between iterators 'begin' and 'end'.
Definition: YSelectionWidget.cc:349
YSelectionWidget::itemsBegin
YItemIterator itemsBegin()
Return an iterator that points to the first item.
Definition: YSelectionWidget.cc:283
YSelectionWidget::selectItem
virtual void selectItem(YItem *item, bool selected=true)
Select or deselect an item.
Definition: YSelectionWidget.cc:414
YSelectionWidget::setIconBasePath
void setIconBasePath(const std::string &basePath)
Set this widget's base path where to look up icons.
Definition: YSelectionWidget.cc:143
YSelectionWidget::dumpItems
void dumpItems() const
Dump all items and their selection state to the log.
Definition: YSelectionWidget.cc:538
OptimizeChanges
Helper class that calls startMultipleChanges() in its constructor and cares about the necessary call ...
Definition: YWidget_OptimizeChanges.h:45
YSelectionWidget::setEnforceInitialSelection
void setEnforceInitialSelection(bool on)
In single selection mode, enforce selecting an initial item ('true' by default).
Definition: YSelectionWidget.cc:117
YSelectionWidget::YSelectionWidget
YSelectionWidget(YWidget *parent, const std::string &label, bool enforceSingleSelection, bool recursiveSelection=false)
Constructor.
Definition: YSelectionWidget.cc:59
YSelectionWidget::deleteAllItems
virtual void deleteAllItems()
Delete all items.
Definition: YSelectionWidget.cc:80
YItem::childrenEnd
virtual YItemIterator childrenEnd()
Return an iterator that points after the last child item of this item.
Definition: YItem.h:195
YSelectionWidget::addItems
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
Definition: YSelectionWidget.cc:264
YSelectionWidget::itemsCount
int itemsCount() const
Return the number of items.
Definition: YSelectionWidget.cc:315
YSelectionWidget::addItem
virtual void addItem(YItem *item_disown)
Add one item.
Definition: YSelectionWidget.cc:186
YSelectionWidget::itemsContain
bool itemsContain(YItem *item) const
Return 'true' if this widget's items contain the specified item.
Definition: YSelectionWidget.cc:450
YUIException
Base class for UI Exceptions.
Definition: YUIException.h:298
YSelectionWidget::findSelectedItems
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 '...
Definition: YSelectionWidget.cc:387
YItemConstIterator
YItemCollection::const_iterator YItemConstIterator
Const iterator over YItemCollection.
Definition: YItem.h:42
YItem
Simple item class for SelectionBox, ComboBox, MultiSelectionBox etc.
Definition: YItem.h:50