libyui  3.10.0
YMenuButton.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: YMenuButton.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 
26 #define YUILogComponent "ui"
27 #include "YUILog.h"
28 
29 #include "YUISymbols.h"
30 #include "YMenuButton.h"
31 #include "YMenuItem.h"
32 #include "YShortcut.h"
33 
34 using std::string;
35 
36 
38 {
40  : nextSerialNo( 0 )
41  {}
42 
43  int nextSerialNo;
44 };
45 
46 
47 
48 
49 YMenuButton::YMenuButton( YWidget * parent, const string & label )
50  : YSelectionWidget( parent, label,
51  false ) // enforceSingleSelection
52  , priv( new YMenuButtonPrivate() )
53 {
54  YUI_CHECK_NEW( priv );
55 }
56 
57 
59 {
60  // NOP
61 }
62 
63 
64 void
65 YMenuButton::addItems( const YItemCollection & itemCollection )
66 {
67  YSelectionWidget::addItems( itemCollection );
70 }
71 
72 
73 void
75 {
77  item->setIndex( ++(priv->nextSerialNo) );
78 
79  if ( item->hasChildren() )
80  assignUniqueIndex( item->childrenBegin(), item->childrenEnd() );
81 }
82 
83 
84 void
85 YMenuButton::assignUniqueIndex( YItemIterator begin, YItemIterator end )
86 {
87  for ( YItemIterator it = begin; it != end; ++it )
88  {
89  YItem * item = *it;
90 
91  item->setIndex( ++(priv->nextSerialNo) );
92 
93  if ( item->hasChildren() )
94  assignUniqueIndex( item->childrenBegin(), item->childrenEnd() );
95  }
96 }
97 
98 
99 void
101 {
103  priv->nextSerialNo = 0;
104 }
105 
106 
107 YMenuItem *
109 {
110  return findMenuItem( index, itemsBegin(), itemsEnd() );
111 }
112 
113 
114 YMenuItem *
116 {
117  for ( YItemConstIterator it = begin; it != end; ++it )
118  {
119  YMenuItem * item = dynamic_cast<YMenuItem *> (*it);
120 
121  if ( item )
122  {
123  if ( item->index() == wantedIndex )
124  return item;
125 
126  if ( item->hasChildren() )
127  {
128  YMenuItem * result = findMenuItem( wantedIndex, item->childrenBegin(), item->childrenEnd() );
129 
130  if ( result )
131  return result;
132  }
133  }
134  }
135 
136  return 0;
137 }
138 
139 static void resolveShortcutsConflictFlat(YItemConstIterator begin, YItemConstIterator end)
140 {
141  bool used[ sizeof( char ) << 8 ];
142  for ( unsigned i=0; i < sizeof( char ) << 8; i++ )
143  used[i] = false;
144  std::vector<YMenuItem*> conflicts;
145 
146  for ( YItemConstIterator it = begin; it != end; ++it )
147  {
148  YMenuItem * item = dynamic_cast<YMenuItem *> (*it);
149 
150  if ( item )
151  {
152  if ( item->hasChildren() )
153  {
154  resolveShortcutsConflictFlat(item->childrenBegin(), item->childrenEnd() );
155  }
156 
157  char shortcut = YShortcut::normalized(YShortcut::findShortcut(item->label()));
158 
159  if (shortcut == 0)
160  {
161  conflicts.push_back(item);
162  yuiMilestone() << "No or invalid shortcut found " << item->label() << endl;
163  }
164  else if (used[(unsigned)shortcut])
165  {
166  conflicts.push_back(item);
167  yuiWarning() << "Conflicting shortcut found " << item->label() << endl;
168  }
169  else
170  {
171  used[(unsigned)shortcut] = true;
172  }
173  }
174  else
175  {
176  yuiWarning() << "non menu item used in call " << (*it)->label() << endl;
177  }
178  }
179 
180  // cannot use YShortcut directly as YItem is not YWidget
181  for(YMenuItem *i: conflicts)
182  {
183  string clean = YShortcut::cleanShortcutString(i->label());
184  char new_c = 0;
185 
186  size_t index = 0;
187  for (; index < clean.size(); ++index)
188  {
189  char ch = YShortcut::normalized(clean[index]);
190  // ch is set to 0 by normalized if not valid
191  if (ch != 0 && !used[(unsigned)ch])
192  {
193  new_c = ch;
194  used[(unsigned)ch] = true;
195  break;
196  }
197  }
198 
199  if (new_c != 0)
200  {
201  clean.insert(index, 1, YShortcut::shortcutMarker());
202  yuiMilestone() << "New label used: " << clean << endl;
203  }
204  i->setLabel(clean);
205  }
206 }
207 
208 void
210 {
211  resolveShortcutsConflictFlat(itemsBegin(), itemsEnd());
212 }
213 
214 
215 const YPropertySet &
217 {
218  static YPropertySet propSet;
219 
220  if ( propSet.isEmpty() )
221  {
222  /*
223  * @property string Label Label on the menu button
224  * @property itemList Items All menu items and submenus
225  * @property string IconPath Base path for icons (on menu items)
226  */
227  propSet.add( YProperty( YUIProperty_Label, YStringProperty ) );
228  propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) );
229  propSet.add( YProperty( YUIProperty_IconPath, YStringProperty ) );
230  propSet.add( YWidget::propertySet() );
231  }
232 
233  return propSet;
234 }
235 
236 
237 bool
238 YMenuButton::setProperty( const string & propertyName, const YPropertyValue & val )
239 {
240  propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch
241 
242  if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() );
243  else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling
244  else if ( propertyName == YUIProperty_IconPath ) setIconBasePath( val.stringVal() );
245  else
246  {
247  return YWidget::setProperty( propertyName, val );
248  }
249 
250  return true; // success -- no special processing necessary
251 }
252 
253 
255 YMenuButton::getProperty( const string & propertyName )
256 {
257  propertySet().check( propertyName ); // throws exceptions if not found
258 
259  if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() );
260  else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty );
261  else if ( propertyName == YUIProperty_IconPath ) return YPropertyValue( iconBasePath() );
262  else
263  {
264  return YWidget::getProperty( propertyName );
265  }
266 }
267 
268 
269 YMenuItem *
270 YMenuButton::findItem( std::vector<std::string> & path ) const
271 {
272  return findItem( path.begin(), path.end(), itemsBegin(), itemsEnd());
273 }
274 
275 YMenuItem *
276 YMenuButton::findItem( std::vector<std::string>::iterator path_begin,
277  std::vector<std::string>::iterator path_end,
278  YItemConstIterator begin,
279  YItemConstIterator end ) const
280 {
281  for ( YItemConstIterator it = begin; it != end; ++it )
282  {
283  YMenuItem * item = dynamic_cast<YMenuItem *>(*it);
284  // Test that dynamic_cast didn't fail
285  if ( !item )
286  return nullptr;
287 
288  if( item->label() == *path_begin )
289  {
290  if ( std::next(path_begin) == path_end ) {
291  // Only return items which can trigger action, intermediate items only open nested popup, so continue looking
292  if( item->hasChildren() )
293  continue;
294 
295  return item;
296  }
297  // Look in child nodes and return if found one
298  YMenuItem * result = findItem( ++path_begin, path_end, item->childrenBegin(), item->childrenEnd() );
299  if ( result )
300  return result;
301  }
302  }
303  return nullptr;
304 }
YItem::label
std::string label() const
Return this item's label.
Definition: YItem.h:82
YPropertySet::add
void add(const YProperty &prop)
Add a property to this property set.
Definition: YProperty.cc:146
YWidget
Abstract base class of all UI widgets.
Definition: YWidget.h:54
YMenuButton::resolveShortcutConflicts
void resolveShortcutConflicts()
Resolve keyboard shortcut conflicts: Change shortcuts of menu items if there are duplicates in the re...
Definition: YMenuButton.cc:209
YShortcut::shortcutMarker
static char shortcutMarker()
Static function: Returns the character used for marking keyboard shortcuts.
Definition: YShortcut.h:154
YSelectionWidget
Base class for various kinds of multi-value widgets.
Definition: YSelectionWidget.h:42
YWidget::end
YWidgetListIterator end()
A helper for the range-based "for" loop.
Definition: YWidget.h:245
YSelectionWidget::itemsEnd
YItemIterator itemsEnd()
Return an iterator that points behind the last item.
Definition: YSelectionWidget.cc:296
YMenuButton::propertySet
virtual const YPropertySet & propertySet()
Return this class's property set.
Definition: YMenuButton.cc:216
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
YMenuButton::findItem
YMenuItem * findItem(std::vector< std::string > &path) const
Return item in the tree which matches path of labels or nullptr in case no item with such label was f...
Definition: YMenuButton.cc:270
YMenuButton::~YMenuButton
virtual ~YMenuButton()
Destructor.
Definition: YMenuButton.cc:58
YItem::index
int index() const
Return the index of this item (as set with setIndex() ).
Definition: YItem.h:138
YItem::childrenBegin
virtual YItemIterator childrenBegin()
Return an iterator that points to the first child item of this item.
Definition: YItem.h:186
YPropertySet
A set of properties to check names and types against.
Definition: YProperty.h:197
YShortcut::findShortcut
static char findShortcut(const std::string &str, std::string::size_type start_pos=0)
Static function: Find the next shortcut marker in a string, beginning at starting position start_pos.
Definition: YShortcut.cc:282
YPropertySet::isEmpty
bool isEmpty() const
Returns 'true' if this property set does not contain anything.
Definition: YProperty.h:263
YWidget::begin
YWidgetListIterator begin()
A helper for the range-based "for" loop.
Definition: YWidget.h:238
YPropertyValue::stringVal
std::string stringVal() const
Methods to get the value of this property.
Definition: YProperty.h:180
YSelectionWidget::label
std::string label() const
Return this widget's label (the caption above the item list).
Definition: YSelectionWidget.cc:99
YTreeItem::hasChildren
virtual bool hasChildren() const
Return 'true' if this item has any child items.
Definition: YTreeItem.h:76
YTreeItem::childrenBegin
virtual YItemIterator childrenBegin()
Return an iterator that points to the first child item of this item.
Definition: YTreeItem.h:83
YMenuButton::rebuildMenuTree
virtual void rebuildMenuTree()=0
Rebuild the displayed menu tree from the internally stored YMenuItems.
YPropertyValue::type
YPropertyType type() const
Returns the type of this property value.
Definition: YProperty.h:169
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
YTreeItem::childrenEnd
virtual YItemIterator childrenEnd()
Return an iterator that points after the last child item of this item.
Definition: YTreeItem.h:91
YItem::hasChildren
virtual bool hasChildren() const
Return 'true' if this item has any child items.
Definition: YItem.h:167
YMenuButton::addItem
virtual void addItem(YItem *item_disown)
Add one item.
Definition: YMenuButton.cc:74
YWidget::getProperty
virtual YPropertyValue getProperty(const std::string &propertyName)
Get a property.
Definition: YWidget.cc:457
YShortcut::normalized
static char normalized(char c)
Return the normalized version of shortcut character 'c', i.e.
Definition: YShortcut.cc:301
YProperty
Class for widget properties.
Definition: YProperty.h:51
YSelectionWidget::setLabel
virtual void setLabel(const std::string &newLabel)
Change this widget's label (the caption above the item list).
Definition: YSelectionWidget.cc:105
YMenuButton::setProperty
virtual bool setProperty(const std::string &propertyName, const YPropertyValue &val)
Set a property.
Definition: YMenuButton.cc:238
YMenuButton::deleteAllItems
virtual void deleteAllItems()
Delete all items.
Definition: YMenuButton.cc:100
YSelectionWidget::setIconBasePath
void setIconBasePath(const std::string &basePath)
Set this widget's base path where to look up icons.
Definition: YSelectionWidget.cc:143
YMenuButton::addItems
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
Definition: YMenuButton.cc:65
YMenuButton::YMenuButton
YMenuButton(YWidget *parent, const std::string &label)
Constructor.
Definition: YMenuButton.cc:49
YPropertySet::check
void check(const std::string &propertyName) const
Check if a property 'propertyName' exists in this property set.
Definition: YProperty.cc:88
YSelectionWidget::deleteAllItems
virtual void deleteAllItems()
Delete all items.
Definition: YSelectionWidget.cc:80
YPropertyValue
Transport class for the value of simple properties.
Definition: YProperty.h:104
YMenuItem
Item class for menu items.
Definition: YMenuItem.h:35
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
YMenuButton::getProperty
virtual YPropertyValue getProperty(const std::string &propertyName)
Get a property.
Definition: YMenuButton.cc:255
YSelectionWidget::addItem
virtual void addItem(YItem *item_disown)
Add one item.
Definition: YSelectionWidget.cc:186
YMenuButton::findMenuItem
YMenuItem * findMenuItem(int index)
Recursively find the first menu item with the specified index.
Definition: YMenuButton.cc:108
YShortcut::cleanShortcutString
std::string cleanShortcutString()
Returns the shortcut string ( from the widget's shortcut property ) without any "&" markers.
Definition: YShortcut.cc:93
YMenuButtonPrivate
Definition: YMenuButton.cc:37
YWidget::setProperty
virtual bool setProperty(const std::string &propertyName, const YPropertyValue &val)
Set a property.
Definition: YWidget.cc:432
YSelectionWidget::itemsBegin
YItemIterator itemsBegin()
Return an iterator that points to the first item.
Definition: YSelectionWidget.cc:283
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:49
YWidget::propertySet
virtual const YPropertySet & propertySet()
Return this class's property set.
Definition: YWidget.cc:395