mirror of https://github.com/KLayout/klayout.git
Fixed a potential crash
This bug was triggered during development and happened because the tool bar build code was invalidating QAction objects indirectly while they are used for building the main menu. Solution is to separate building of menu bar and tool bar / context menus.
This commit is contained in:
parent
cb918203c7
commit
4cc1d2ff9a
|
|
@ -1280,32 +1280,139 @@ AbstractMenu::extra_menu_name ()
|
|||
void
|
||||
AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
||||
{
|
||||
if (tbar) {
|
||||
tbar->clear ();
|
||||
}
|
||||
|
||||
std::set<std::pair<size_t, QAction *> > present_actions;
|
||||
// Build the menu bar
|
||||
if (mbar) {
|
||||
|
||||
std::set<std::pair<size_t, QAction *> > present_actions;
|
||||
|
||||
QList<QAction *> a = mbar->actions ();
|
||||
for (QList<QAction *>::const_iterator i = a.begin (); i != a.end (); ++i) {
|
||||
present_actions.insert (std::make_pair (id_from_action (*i), *i));
|
||||
}
|
||||
|
||||
// NOTE: on MacOS, once the top level menu is created, we should not
|
||||
// modify it and place menu items into the "Extras" menu instead.
|
||||
bool menu_frozen = ! s_can_move_menu && ! present_actions.empty ();
|
||||
|
||||
// NOTE: the "extras" menu is relevant on MacOS only
|
||||
QMenu *extras_menu = find_extras_menu (mbar);
|
||||
if (extras_menu) {
|
||||
extras_menu->clear ();
|
||||
}
|
||||
|
||||
QAction *prev_action = 0;
|
||||
|
||||
for (std::list<AbstractMenuItem>::iterator c = m_root.children.begin (); c != m_root.children.end (); ++c) {
|
||||
|
||||
if (c->has_submenu ()) {
|
||||
|
||||
if (c->name ().find ("@") == 0) {
|
||||
|
||||
// done later.
|
||||
|
||||
} else {
|
||||
|
||||
if (c->menu () == 0) {
|
||||
|
||||
// NOTE: we intentionally do not make the item owner of the menu action
|
||||
// as implicitly deleting it might cause trouble on MacOS. Instead we
|
||||
// explicitly delete below or keep the action.
|
||||
QMenu *menu = new QMenu (mp_dispatcher->menu_parent_widget ());
|
||||
menu->setTitle (tl::to_qstring (c->action ()->get_title ()));
|
||||
c->set_action (new Action (menu, false), true);
|
||||
|
||||
// This case happens when we dynamically create menus.
|
||||
// MacOS does not like generating top-level menus dynamically, so
|
||||
// we put them into the "_extra" top level one.
|
||||
if (menu_frozen) {
|
||||
if (extras_menu) {
|
||||
extras_menu->addMenu (menu);
|
||||
}
|
||||
} else {
|
||||
prev_action = insert_action_after (mbar, prev_action, menu->menuAction ());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Move the action to the end if present in the menu already
|
||||
std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ()));
|
||||
if (a != present_actions.end ()) {
|
||||
if (s_can_move_menu) {
|
||||
mbar->removeAction (a->second);
|
||||
insert_action_after (mbar, prev_action, a->second);
|
||||
}
|
||||
prev_action = a->second;
|
||||
present_actions.erase (*a);
|
||||
} else if (menu_frozen) {
|
||||
if (extras_menu) {
|
||||
extras_menu->addMenu (c->menu ());
|
||||
}
|
||||
} else {
|
||||
prev_action = insert_action_after (mbar, prev_action, c->menu ()->menuAction ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NOTE: the "extras" menu is built implicitly. You cannot put anything there.
|
||||
if (c->menu () != extras_menu) {
|
||||
build (c->menu (), c->children);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Move the action to the end if present in the menu already
|
||||
std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->action ()->qaction ()), c->action ()->qaction ()));
|
||||
if (a != present_actions.end ()) {
|
||||
if (s_can_move_menu) {
|
||||
mbar->removeAction (a->second);
|
||||
insert_action_after (mbar, prev_action, a->second);
|
||||
}
|
||||
prev_action = a->second;
|
||||
present_actions.erase (*a);
|
||||
} else if (menu_frozen) {
|
||||
QMenu *extras_menu = find_extras_menu (mbar);
|
||||
if (extras_menu) {
|
||||
extras_menu->addAction (c->action ()->qaction ());
|
||||
}
|
||||
} else {
|
||||
prev_action = insert_action_after (mbar, prev_action, c->action ()->qaction ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Disable the (maybe new) "extras" menu if empty
|
||||
extras_menu = find_extras_menu (mbar);
|
||||
if (extras_menu) {
|
||||
extras_menu->setEnabled (! extras_menu->isEmpty ());
|
||||
}
|
||||
|
||||
// Remove all actions that have vanished
|
||||
for (std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
|
||||
if (s_can_move_menu) {
|
||||
mbar->removeAction (a->second);
|
||||
delete a->second;
|
||||
} else {
|
||||
if (a->second->menu ()) {
|
||||
a->second->menu ()->clear ();
|
||||
}
|
||||
a->second->setEnabled (false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NOTE: on MacOS, once the top level menu is created, we should not
|
||||
// modify it and place menu items into the "Extras" menu instead.
|
||||
bool menu_frozen = ! s_can_move_menu && ! present_actions.empty ();
|
||||
// Finally build the context menus and toolbar.
|
||||
// NOTE: this is done afterwards, as generating the submenus, specifically for the toolbar menu buttons
|
||||
// messes with the QActions stored in "present_actions".
|
||||
|
||||
// NOTE: the "extras" menu is relevant on MacOS only
|
||||
QMenu *extras_menu = find_extras_menu (mbar);
|
||||
if (extras_menu) {
|
||||
extras_menu->clear ();
|
||||
if (tbar) {
|
||||
tbar->clear ();
|
||||
}
|
||||
|
||||
QAction *prev_action = 0;
|
||||
|
||||
for (std::list<AbstractMenuItem>::iterator c = m_root.children.begin (); c != m_root.children.end (); ++c) {
|
||||
|
||||
if (c->has_submenu ()) {
|
||||
|
|
@ -1338,100 +1445,11 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
|||
// prepare a detached menu which can be used as context menus
|
||||
build (c->menu (), c->children);
|
||||
|
||||
} else if (mbar) {
|
||||
|
||||
if (c->menu () == 0) {
|
||||
|
||||
// NOTE: we intentionally do not make the item owner of the menu action
|
||||
// as implicitly deleting it might cause trouble on MacOS. Instead we
|
||||
// explicitly delete below or keep the action.
|
||||
QMenu *menu = new QMenu (mp_dispatcher->menu_parent_widget ());
|
||||
menu->setTitle (tl::to_qstring (c->action ()->get_title ()));
|
||||
c->set_action (new Action (menu, false), true);
|
||||
|
||||
// This case happens when we dynamically create menus.
|
||||
// MacOS does not like generating top-level menus dynamically, so
|
||||
// we put them into the "_extra" top level one.
|
||||
if (menu_frozen) {
|
||||
if (extras_menu) {
|
||||
extras_menu->addMenu (menu);
|
||||
}
|
||||
} else {
|
||||
prev_action = insert_action_after (mbar, prev_action, menu->menuAction ());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Move the action to the end if present in the menu already
|
||||
std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ()));
|
||||
if (a != present_actions.end ()) {
|
||||
if (s_can_move_menu) {
|
||||
mbar->removeAction (a->second);
|
||||
insert_action_after (mbar, prev_action, a->second);
|
||||
}
|
||||
prev_action = a->second;
|
||||
present_actions.erase (*a);
|
||||
} else if (menu_frozen) {
|
||||
if (extras_menu) {
|
||||
extras_menu->addMenu (c->menu ());
|
||||
}
|
||||
} else {
|
||||
prev_action = insert_action_after (mbar, prev_action, c->menu ()->menuAction ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NOTE: the "extras" menu is built implicitly. You cannot put anything there.
|
||||
if (c->menu () != extras_menu) {
|
||||
build (c->menu (), c->children);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (mbar) {
|
||||
|
||||
// Move the action to the end if present in the menu already
|
||||
std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->action ()->qaction ()), c->action ()->qaction ()));
|
||||
if (a != present_actions.end ()) {
|
||||
if (s_can_move_menu) {
|
||||
mbar->removeAction (a->second);
|
||||
insert_action_after (mbar, prev_action, a->second);
|
||||
}
|
||||
prev_action = a->second;
|
||||
present_actions.erase (*a);
|
||||
} else if (menu_frozen) {
|
||||
QMenu *extras_menu = find_extras_menu (mbar);
|
||||
if (extras_menu) {
|
||||
extras_menu->addAction (c->action ()->qaction ());
|
||||
}
|
||||
} else {
|
||||
prev_action = insert_action_after (mbar, prev_action, c->action ()->qaction ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Disable the (maybe new) "extras" menu if empty
|
||||
extras_menu = find_extras_menu (mbar);
|
||||
if (extras_menu) {
|
||||
extras_menu->setEnabled (! extras_menu->isEmpty ());
|
||||
}
|
||||
|
||||
// Remove all actions that have vanished
|
||||
if (mbar) {
|
||||
for (std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
|
||||
if (s_can_move_menu) {
|
||||
mbar->removeAction (a->second);
|
||||
delete a->second;
|
||||
} else {
|
||||
if (a->second->menu ()) {
|
||||
a->second->menu ()->clear ();
|
||||
}
|
||||
a->second->setEnabled (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Reference in New Issue