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 }
YItemCollection::const_iterator YItemConstIterator
Const iterator over YItemCollection.
Definition: YItem.h:42
YItemCollection::iterator YItemIterator
Mutable iterator over YItemCollection.
Definition: YItem.h:40
std::vector< YItem * > YItemCollection
Collection of pointers to YItem.
Definition: YItem.h:38
Simple item class for SelectionBox, ComboBox, MultiSelectionBox etc.
Definition: YItem.h:50
std::string label() const
Return this item's label.
Definition: YItem.h:82
virtual YItemIterator childrenBegin()
Return an iterator that points to the first child item of this item.
Definition: YItem.h:186
virtual bool hasChildren() const
Return 'true' if this item has any child items.
Definition: YItem.h:167
int index() const
Return the index of this item (as set with setIndex() ).
Definition: YItem.h:138
void setIndex(int index)
Set this item's index.
Definition: YItem.h:133
virtual YItemIterator childrenEnd()
Return an iterator that points after the last child item of this item.
Definition: YItem.h:195
void resolveShortcutConflicts()
Resolve keyboard shortcut conflicts: Change shortcuts of menu items if there are duplicates in the re...
Definition: YMenuButton.cc:209
YMenuItem * findMenuItem(int index)
Recursively find the first menu item with the specified index.
Definition: YMenuButton.cc:108
virtual const YPropertySet & propertySet()
Return this class's property set.
Definition: YMenuButton.cc:216
virtual void addItem(YItem *item_disown)
Add one item.
Definition: YMenuButton.cc:74
virtual YPropertyValue getProperty(const std::string &propertyName)
Get a property.
Definition: YMenuButton.cc:255
virtual bool setProperty(const std::string &propertyName, const YPropertyValue &val)
Set a property.
Definition: YMenuButton.cc:238
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
virtual ~YMenuButton()
Destructor.
Definition: YMenuButton.cc:58
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
Definition: YMenuButton.cc:65
virtual void deleteAllItems()
Delete all items.
Definition: YMenuButton.cc:100
virtual void rebuildMenuTree()=0
Rebuild the displayed menu tree from the internally stored YMenuItems.
YMenuButton(YWidget *parent, const std::string &label)
Constructor.
Definition: YMenuButton.cc:49
Item class for menu items.
Definition: YMenuItem.h:36
A set of properties to check names and types against.
Definition: YProperty.h:198
void check(const std::string &propertyName) const
Check if a property 'propertyName' exists in this property set.
Definition: YProperty.cc:88
bool isEmpty() const
Returns 'true' if this property set does not contain anything.
Definition: YProperty.h:263
void add(const YProperty &prop)
Add a property to this property set.
Definition: YProperty.cc:146
Transport class for the value of simple properties.
Definition: YProperty.h:105
std::string stringVal() const
Methods to get the value of this property.
Definition: YProperty.h:180
YPropertyType type() const
Returns the type of this property value.
Definition: YProperty.h:169
Class for widget properties.
Definition: YProperty.h:52
Base class for various kinds of multi-value widgets.
virtual void deleteAllItems()
Delete all items.
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
YItemIterator itemsEnd()
Return an iterator that points behind the last item.
std::string iconBasePath() const
Return this widget's base path where to look up icons as set with setIconBasePath().
YItemIterator itemsBegin()
Return an iterator that points to the first item.
virtual void addItem(YItem *item_disown)
Add one item.
std::string label() const
Return this widget's label (the caption above the item list).
virtual void setLabel(const std::string &newLabel)
Change this widget's label (the caption above the item list).
void setIconBasePath(const std::string &basePath)
Set this widget's base path where to look up icons.
static char normalized(char c)
Return the normalized version of shortcut character 'c', i.e.
Definition: YShortcut.cc:301
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
static char shortcutMarker()
Static function: Returns the character used for marking keyboard shortcuts.
Definition: YShortcut.h:154
std::string cleanShortcutString()
Returns the shortcut string ( from the widget's shortcut property ) without any "&" markers.
Definition: YShortcut.cc:93
virtual bool hasChildren() const
Return 'true' if this item has any child items.
Definition: YTreeItem.h:76
virtual YItemIterator childrenBegin()
Return an iterator that points to the first child item of this item.
Definition: YTreeItem.h:83
virtual YItemIterator childrenEnd()
Return an iterator that points after the last child item of this item.
Definition: YTreeItem.h:91
Abstract base class of all UI widgets.
Definition: YWidget.h:55
YWidgetListIterator end()
A helper for the range-based "for" loop.
Definition: YWidget.h:245
YWidgetListIterator begin()
A helper for the range-based "for" loop.
Definition: YWidget.h:238
virtual const YPropertySet & propertySet()
Return this class's property set.
Definition: YWidget.cc:395
virtual bool setProperty(const std::string &propertyName, const YPropertyValue &val)
Set a property.
Definition: YWidget.cc:432
virtual YPropertyValue getProperty(const std::string &propertyName)
Get a property.
Definition: YWidget.cc:457