libyui-qt  2.56.2
YQMenuBar.cc
1 /*
2  Copyright (C) 2020 SUSE LLC
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: YQMenuBar.cc
20 
21  Author: Stefan Hundhammer <shundhammer@suse.de>
22 
23 /-*/
24 
25 
26 #include <QMenu>
27 #include <QTimer>
28 #define YUILogComponent "qt-ui"
29 #include <yui/YUILog.h>
30 
31 #include "utf8.h"
32 #include "YQUI.h"
33 #include "YQMenuBar.h"
34 #include "YQSignalBlocker.h"
35 #include <yui/YEvent.h>
36 
37 using std::string;
38 
39 
40 
41 YQMenuBar::YQMenuBar( YWidget * parent )
42  : QMenuBar( (QWidget *) parent->widgetRep() )
43  , YMenuBar( parent )
44  , _selectedItem( 0 )
45 {
46  setWidgetRep( this );
47 }
48 
49 
51 {
52  // NOP
53 }
54 
55 
56 void
58 {
59  //
60  // Delete any previous menus
61  // (in case the menu items got replaced)
62  //
63 
64  QMenuBar::clear();
65  _actionMap.clear();
66  _selectedItem = 0;
67 
68 
69  //
70  // Create toplevel menus
71  //
72 
73  for ( YItemIterator it = itemsBegin(); it != itemsEnd(); ++it )
74  {
75  YMenuItem * item = dynamic_cast<YMenuItem *>( *it );
76  YUI_CHECK_PTR( item );
77 
78  if ( ! item->isMenu() )
79  YUI_THROW( YUIException( "YQMenuBar: Only menus allowed on toplevel." ) );
80 
81  QMenu * menu = QMenuBar::addMenu( fromUTF8( item->label() ));
82  item->setUiItem( menu );
83 
84  connect( menu, &pclass(menu)::triggered,
85  this, &pclass(this)::menuEntryActivated );
86 
87  // Recursively add menu content
88  rebuildMenuTree( menu, item->childrenBegin(), item->childrenEnd() );
89  }
90 }
91 
92 
93 void
94 YQMenuBar::rebuildMenuTree( QMenu * parentMenu, YItemIterator begin, YItemIterator end )
95 {
96  for ( YItemIterator it = begin; it != end; ++it )
97  {
98  YMenuItem * item = dynamic_cast<YMenuItem *>( *it );
99  YUI_CHECK_PTR( item );
100  QIcon icon;
101 
102  if ( item->hasIconName() )
103  icon = YQUI::ui()->loadIcon( item->iconName() );
104 
105  if ( item->isSeparator() )
106  {
107  parentMenu->addSeparator();
108  }
109  else if ( item->isMenu() )
110  {
111  QMenu * subMenu = parentMenu->addMenu( fromUTF8( item->label() ));
112  item->setUiItem( subMenu );
113  subMenu->setEnabled( item->isEnabled() );
114  // Do NOT call
115  // subMenu->setVisible( item->isVisible() );
116  // here since this would make this pop-up menu visible immediately!
117  // It has to wait until the user explicitly opens it.
118 
119 
120  if ( ! icon.isNull() )
121  subMenu->setIcon( icon );
122 
123  connect( subMenu, &pclass(subMenu)::triggered,
124  this, &pclass(this)::menuEntryActivated );
125 
126  rebuildMenuTree( subMenu, item->childrenBegin(), item->childrenEnd() );
127  }
128  else // Plain menu item (leaf item)
129  {
130  QAction * action = parentMenu->addAction( fromUTF8( item->label() ) );
131  item->setUiItem( action );
132  _actionMap[ action ] = item;
133  action->setEnabled( item->isEnabled() );
134  action->setVisible( item->isVisible() );
135 
136  if ( ! icon.isNull() )
137  action->setIcon( icon );
138  }
139  }
140 }
141 
142 
143 void
144 YQMenuBar::menuEntryActivated( QAction * action )
145 {
146  if ( _actionMap.contains( action ) )
147  _selectedItem = _actionMap[ action ];
148 
149  if ( _selectedItem )
150  {
151  // yuiDebug() << "Selected menu entry \"" << fromUTF8( _selectedItem->label() ) << "\"" << endl;
152 
153  /*
154  * Defer the real returnNow() until all popup related events have been
155  * processed. This took me some hours to figure out; obviously
156  * exit_loop() doesn't have any effect as long as there are still
157  * popups open. So be it - use a timer to perform the real returnNow()
158  * later.
159  */
160 
161  /*
162  * The 100 delay is an ugly dirty workaround.
163  */
164  QTimer::singleShot( 100, this, SLOT( returnNow() ) );
165  }
166  else
167  {
168  yuiError() << "Unknown action \"" << action->text() << "\"" << endl;
169  }
170 }
171 
172 
173 void
175 {
176  if ( _selectedItem )
177  {
178  YQUI::ui()->sendEvent( new YMenuEvent( _selectedItem ) );
179  _selectedItem = 0;
180  }
181 }
182 
183 
184 void
185 YQMenuBar::setItemEnabled( YMenuItem * item, bool enabled )
186 {
187  QObject * qObj = static_cast<QObject *>( item->uiItem() );
188 
189  if ( qObj )
190  {
191  QMenu * menu = qobject_cast<QMenu *>( qObj );
192 
193  if ( menu )
194  menu->setEnabled( enabled );
195  else
196  {
197  QAction * action = qobject_cast<QAction *>( qObj );
198 
199  if ( action )
200  action->setEnabled( enabled );
201  }
202  }
203 
204  YMenuWidget::setItemEnabled( item, enabled );
205 }
206 
207 
208 void
209 YQMenuBar::setItemVisible( YMenuItem * item, bool visible )
210 {
211  QObject * qObj = static_cast<QObject *>( item->uiItem() );
212 
213  if ( qObj )
214  {
215  QMenu * menu = qobject_cast<QMenu *>( qObj );
216 
217  if ( menu )
218  menu->menuAction()->setVisible( visible );
219  else
220  {
221  QAction * action = qobject_cast<QAction *>( qObj );
222 
223  if ( action )
224  action->setVisible( visible );
225  }
226  }
227 
228  YMenuWidget::setItemVisible( item, visible );
229 }
230 
231 
232 void
233 YQMenuBar::setEnabled( bool enabled )
234 {
235  YWidget::setEnabled( enabled );
236 }
237 
238 
240 {
241  return sizeHint().width();
242 }
243 
244 
246 {
247  return sizeHint().height();
248 }
249 
250 
251 void
252 YQMenuBar::setSize( int newWidth, int newHeight )
253 {
254  QWidget::resize( newWidth, newHeight );
255 }
256 
257 
258 bool
260 {
261  QWidget::setFocus();
262 
263  return true;
264 }
265 
266 
267 void
268 YQMenuBar::activateItem( YMenuItem * item )
269 {
270  if ( item )
271  YQUI::ui()->sendEvent( new YMenuEvent( item ) );
272 }
273 
274 
275 void
277 {
278  // Any of the items might have its keyboard shortcut changed, but we don't
279  // know which one. So let's simply rebuild the menu bar again.
280 
281  // FIXME: This is called every time a menu shortcut is changed. Rebuilding
282  // the menu tree is an expensive operation. Try to avoid multiple rebuilds
283  // by calling this only after fixing all the shortcuts.
284 
285  rebuildMenuTree();
286 }
YQMenuBar::menuEntryActivated
void menuEntryActivated(QAction *menuItem)
Triggered when any menu item is activated.
Definition: YQMenuBar.cc:144
YQMenuBar::setEnabled
virtual void setEnabled(bool enabled)
Set enabled / disabled state.
Definition: YQMenuBar.cc:233
YQMenuBar::setSize
virtual void setSize(int newWidth, int newHeight)
Set the new size of the widget.
Definition: YQMenuBar.cc:252
YQMenuBar::preferredHeight
virtual int preferredHeight()
Preferred height of the widget.
Definition: YQMenuBar.cc:245
YQMenuBar::preferredWidth
virtual int preferredWidth()
Preferred width of the widget.
Definition: YQMenuBar.cc:239
YQUI::sendEvent
void sendEvent(YEvent *event)
Widget event handlers (slots) call this when an event occured that should be the answer to a UserInpu...
Definition: YQUI.cc:480
YQMenuBar::setKeyboardFocus
virtual bool setKeyboardFocus()
Accept the keyboard focus.
Definition: YQMenuBar.cc:259
YQMenuBar::setItemEnabled
virtual void setItemEnabled(YMenuItem *item, bool enabled)
Enable or disable an item.
Definition: YQMenuBar.cc:185
YQMenuBar::setItemVisible
virtual void setItemVisible(YMenuItem *item, bool visible)
Show or hide an item.
Definition: YQMenuBar.cc:209
YQMenuBar::shortcutChanged
virtual void shortcutChanged()
Notification that some shortcut was changed.
Definition: YQMenuBar.cc:276
YQUI::ui
static YQUI * ui()
Access the global Qt-UI.
Definition: YQUI.h:83
YQMenuBar::activateItem
virtual void activateItem(YMenuItem *item)
Activate the item selected in the tree.
Definition: YQMenuBar.cc:268
YQMenuBar::rebuildMenuTree
virtual void rebuildMenuTree()
Rebuild the displayed menu tree from the internally stored YMenuItems.
Definition: YQMenuBar.cc:57
YQMenuBar::~YQMenuBar
virtual ~YQMenuBar()
Destructor.
Definition: YQMenuBar.cc:50
YQMenuBar::returnNow
void returnNow()
Triggered via menuEntryActivated() by zero timer to get back in sync with the Qt event loop.
Definition: YQMenuBar.cc:174
YQMenuBar::YQMenuBar
YQMenuBar(YWidget *parent)
Constructor.
Definition: YQMenuBar.cc:41
YQUI::loadIcon
QIcon loadIcon(const string &iconName) const
Load an icon.
Definition: YQUI.cc:708