libyui  3.4.2
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 
36 {
38  : nextSerialNo( 0 )
39  {}
40 
41  int nextSerialNo;
42 };
43 
44 
45 
46 
47 YMenuButton::YMenuButton( YWidget * parent, const std::string & label )
48  : YSelectionWidget( parent, label,
49  false ) // enforceSingleSelection
50  , priv( new YMenuButtonPrivate() )
51 {
52  YUI_CHECK_NEW( priv );
53 }
54 
55 
57 {
58  // NOP
59 }
60 
61 
62 void
63 YMenuButton::addItems( const YItemCollection & itemCollection )
64 {
65  YSelectionWidget::addItems( itemCollection );
68 }
69 
70 
71 void
73 {
75  item->setIndex( ++(priv->nextSerialNo) );
76 
77  if ( item->hasChildren() )
78  assignUniqueIndex( item->childrenBegin(), item->childrenEnd() );
79 }
80 
81 
82 void
83 YMenuButton::assignUniqueIndex( YItemIterator begin, YItemIterator end )
84 {
85  for ( YItemIterator it = begin; it != end; ++it )
86  {
87  YItem * item = *it;
88 
89  item->setIndex( ++(priv->nextSerialNo) );
90 
91  if ( item->hasChildren() )
92  assignUniqueIndex( item->childrenBegin(), item->childrenEnd() );
93  }
94 }
95 
96 
97 void
99 {
101  priv->nextSerialNo = 0;
102 }
103 
104 
105 YMenuItem *
107 {
108  return findMenuItem( index, itemsBegin(), itemsEnd() );
109 }
110 
111 
112 YMenuItem *
114 {
115  for ( YItemConstIterator it = begin; it != end; ++it )
116  {
117  YMenuItem * item = dynamic_cast<YMenuItem *> (*it);
118 
119  if ( item )
120  {
121  if ( item->index() == wantedIndex )
122  return item;
123 
124  if ( item->hasChildren() )
125  {
126  YMenuItem * result = findMenuItem( wantedIndex, item->childrenBegin(), item->childrenEnd() );
127 
128  if ( result )
129  return result;
130  }
131  }
132  }
133 
134  return 0;
135 }
136 
137 static void resolveShortcutsConflictFlat(YItemConstIterator begin, YItemConstIterator end)
138 {
139  bool used[ sizeof( char ) << 8 ];
140  for ( unsigned i=0; i < sizeof( char ) << 8; i++ )
141  used[i] = false;
142  std::vector<YMenuItem*> conflicts;
143 
144  for ( YItemConstIterator it = begin; it != end; ++it )
145  {
146  YMenuItem * item = dynamic_cast<YMenuItem *> (*it);
147 
148  if ( item )
149  {
150  if ( item->hasChildren() )
151  {
152  resolveShortcutsConflictFlat(item->childrenBegin(), item->childrenEnd() );
153  }
154 
155  char shortcut = YShortcut::normalized(YShortcut::findShortcut(item->label()));
156 
157  if (shortcut == 0)
158  {
159  conflicts.push_back(item);
160  yuiMilestone() << "No or invalid shortcut found " << item->label() << std::endl;
161  }
162  else if (used[(unsigned)shortcut])
163  {
164  conflicts.push_back(item);
165  yuiWarning() << "Conflicting shortcut found " << item->label() << std::endl;
166  }
167  else
168  {
169  used[(unsigned)shortcut] = true;
170  }
171  }
172  else
173  {
174  yuiWarning() << "non menu item used in call " << (*it)->label() << std::endl;
175  }
176  }
177 
178  // cannot use YShortcut directly as YItem is not YWidget
179  for(YMenuItem *i: conflicts)
180  {
181  std::string clean = YShortcut::cleanShortcutString(i->label());
182  char new_c = 0;
183 
184  size_t index = 0;
185  for (; index < clean.size(); ++index)
186  {
187  char ch = YShortcut::normalized(clean[index]);
188  // ch is set to 0 by normalized if not valid
189  if (ch != 0 && !used[(unsigned)ch])
190  {
191  new_c = ch;
192  used[(unsigned)ch] = true;
193  break;
194  }
195  }
196 
197  if (new_c != 0)
198  {
199  clean.insert(index, 1, YShortcut::shortcutMarker());
200  yuiMilestone() << "New label used: " << clean << std::endl;
201  }
202  i->setLabel(clean);
203  }
204 }
205 
206 void
208 {
209  resolveShortcutsConflictFlat(itemsBegin(), itemsEnd());
210 }
211 
212 
213 const YPropertySet &
215 {
216  static YPropertySet propSet;
217 
218  if ( propSet.isEmpty() )
219  {
220  /*
221  * @property std::string Label Label on the menu button
222  * @property itemList Items All menu items and submenus
223  * @property std::string IconPath Base path for icons (on menu items)
224  */
225  propSet.add( YProperty( YUIProperty_Label, YStringProperty ) );
226  propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) );
227  propSet.add( YProperty( YUIProperty_IconPath, YStringProperty ) );
228  propSet.add( YWidget::propertySet() );
229  }
230 
231  return propSet;
232 }
233 
234 
235 bool
236 YMenuButton::setProperty( const std::string & propertyName, const YPropertyValue & val )
237 {
238  propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch
239 
240  if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() );
241  else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling
242  else if ( propertyName == YUIProperty_IconPath ) setIconBasePath( val.stringVal() );
243  else
244  {
245  return YWidget::setProperty( propertyName, val );
246  }
247 
248  return true; // success -- no special processing necessary
249 }
250 
251 
253 YMenuButton::getProperty( const std::string & propertyName )
254 {
255  propertySet().check( propertyName ); // throws exceptions if not found
256 
257  if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() );
258  else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty );
259  else if ( propertyName == YUIProperty_IconPath ) return YPropertyValue( iconBasePath() );
260  else
261  {
262  return YWidget::getProperty( propertyName );
263  }
264 }
YMenuItem * findMenuItem(int index)
Recursively find the first menu item with the specified index.
Definition: YMenuButton.cc:106
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 bool hasChildren() const
Return &#39;true&#39; if this item has any child items.
Definition: YTreeItem.h:78
virtual YItemIterator childrenEnd()
Return an iterator that points after the last child item of this item.
Definition: YTreeItem.h:93
std::string label() const
Return this item&#39;s label.
Definition: YItem.h:82
bool isEmpty() const
Returns &#39;true&#39; if this property set does not contain anything.
Definition: YProperty.h:263
virtual const YPropertySet & propertySet()
Return this class&#39;s property set.
Definition: YMenuButton.cc:214
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).
Transport class for the value of simple properties.
Definition: YProperty.h:104
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
Base class for various kinds of multi-value widgets.
virtual ~YMenuButton()
Destructor.
Definition: YMenuButton.cc:56
void add(const YProperty &prop)
Add a property to this property set.
Definition: YProperty.cc:145
virtual bool setProperty(const std::string &propertyName, const YPropertyValue &val)
Set a property.
Definition: YWidget.cc:430
virtual bool hasChildren() const
Return &#39;true&#39; if this item has any child items.
Definition: YItem.h:153
A set of properties to check names and types against.
Definition: YProperty.h:197
virtual void addItem(YItem *item_disown)
Add one item.
Definition: YMenuButton.cc:72
int index() const
Return the index of this item (as set with setIndex() ).
Definition: YItem.h:124
static char normalized(char c)
Return the normalized version of shortcut character &#39;c&#39;, i.e.
Definition: YShortcut.cc:299
virtual void rebuildMenuTree()=0
Rebuild the displayed menu tree from the internally stored YMenuItems.
YItemIterator itemsBegin()
Return an iterator that points to the first item.
virtual void deleteAllItems()
Delete all items.
Definition: YMenuButton.cc:98
virtual const YPropertySet & propertySet()
Return this class&#39;s property set.
Definition: YWidget.cc:393
std::string cleanShortcutString()
Returns the shortcut string ( from the widget&#39;s shortcut property ) without any "&" markers...
Definition: YShortcut.cc:91
virtual void deleteAllItems()
Delete all items.
virtual YPropertyValue getProperty(const std::string &propertyName)
Get a property.
Definition: YWidget.cc:455
static char shortcutMarker()
Static function: Returns the character used for marking keyboard shortcuts.
Definition: YShortcut.h:154
std::string stringVal() const
Methods to get the value of this property.
Definition: YProperty.h:180
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
Definition: YMenuButton.cc:63
YMenuButton(YWidget *parent, const std::string &label)
Constructor.
Definition: YMenuButton.cc:47
virtual YPropertyValue getProperty(const std::string &propertyName)
Get a property.
Definition: YMenuButton.cc:253
Class for widget properties.
Definition: YProperty.h:51
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
Item class for menu items.
Definition: YMenuItem.h:35
virtual YItemIterator childrenEnd()
Return an iterator that points after the last child item of this item.
Definition: YItem.h:181
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:280
virtual bool setProperty(const std::string &propertyName, const YPropertyValue &val)
Set a property.
Definition: YMenuButton.cc:236
void setIconBasePath(const std::string &basePath)
Set this widget&#39;s base path where to look up icons.
YWidgetListIterator begin()
A helper for the range-based "for" loop.
Definition: YWidget.h:238
virtual YItemIterator childrenBegin()
Return an iterator that points to the first child item of this item.
Definition: YTreeItem.h:85
void check(const std::string &propertyName) const
Check if a property &#39;propertyName&#39; exists in this property set.
Definition: YProperty.cc:87
void resolveShortcutConflicts()
Resolve keyboard shortcut conflicts: Change shortcuts of menu items if there are duplicates in the re...
Definition: YMenuButton.cc:207
Abstract base class of all UI widgets.
Definition: YWidget.h:54
YPropertyType type() const
Returns the type of this property value.
Definition: YProperty.h:169
std::string iconBasePath() const
Return this widget&#39;s base path where to look up icons as set with setIconBasePath().