mirror of https://github.com/KLayout/klayout.git
Fixed issue-1131 (do not show non-existing files in MRU lists) (#1133)
* Fixed issue-1131 (do not show files in MRU lists which do no longer exist) The solution consists of an extension of the Action system allowing to dynamically hide or disable items. This currently works for menu items only. This feature is used to dynamically *disable* (as of now, not hiding) items from the four MRU lists corresponding to non-existing files. In addition, a "clear list" menu has been added to the MRU lists. * Small enhancement: file names can be URIs
This commit is contained in:
parent
e2f9015c26
commit
801ef78990
|
|
@ -51,6 +51,8 @@
|
|||
#include "tlStream.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "tlExpression.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlUri.h"
|
||||
#include "dbMemStatistics.h"
|
||||
#include "dbManager.h"
|
||||
#include "dbStream.h"
|
||||
|
|
@ -2902,29 +2904,28 @@ MainWindow::add_mru (const std::string &fn_rel)
|
|||
add_mru (fn_rel, m_initial_technology);
|
||||
}
|
||||
|
||||
const size_t max_mru = 16;
|
||||
const size_t max_mru = 16; // TODO: make configurable?
|
||||
|
||||
void
|
||||
MainWindow::add_mru (const std::string &fn_rel, const std::string &tech)
|
||||
{
|
||||
std::vector <std::pair<std::string, std::string> > new_mru (m_mru);
|
||||
std::vector <std::pair<std::string, std::string> > new_mru;
|
||||
std::string fn (tl::InputStream::absolute_path (fn_rel));
|
||||
|
||||
for (std::vector<std::pair<std::string, std::string> >::iterator mru = new_mru.begin (); mru != new_mru.end (); ++mru) {
|
||||
if (mru->first == fn) {
|
||||
new_mru.erase (mru);
|
||||
break;
|
||||
for (auto mru = m_mru.begin (); mru != m_mru.end (); ++mru) {
|
||||
if (mru->first != fn /* delete non-existing files: && tl::is_readable (mru->first) */) {
|
||||
new_mru.push_back (*mru);
|
||||
}
|
||||
}
|
||||
|
||||
new_mru.push_back (std::make_pair (fn, tech));
|
||||
|
||||
if (new_mru.size () > max_mru) {
|
||||
new_mru.erase (new_mru.begin ());
|
||||
new_mru.erase (new_mru.begin (), new_mru.end () - max_mru);
|
||||
}
|
||||
|
||||
std::string config_str;
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator mru = new_mru.begin (); mru != new_mru.end (); ++mru) {
|
||||
for (auto mru = new_mru.begin (); mru != new_mru.end (); ++mru) {
|
||||
if (! config_str.empty ()) {
|
||||
config_str += " ";
|
||||
}
|
||||
|
|
@ -2952,20 +2953,19 @@ MainWindow::add_to_other_mru (const std::string &fn_rel, const std::string &cfg)
|
|||
tl_assert (false);
|
||||
}
|
||||
|
||||
std::vector <std::string> new_mru = *mru_ptr;
|
||||
std::vector <std::string> new_mru;
|
||||
std::string fn (tl::InputStream::absolute_path (fn_rel));
|
||||
|
||||
for (std::vector<std::string>::iterator mru = new_mru.begin (); mru != new_mru.end (); ++mru) {
|
||||
if (*mru == fn) {
|
||||
new_mru.erase (mru);
|
||||
break;
|
||||
for (auto mru = mru_ptr->begin (); mru != mru_ptr->end (); ++mru) {
|
||||
if (*mru != fn /* delete non-existing files: && tl::is_readable (*mru) */) {
|
||||
new_mru.push_back (*mru);
|
||||
}
|
||||
}
|
||||
|
||||
new_mru.push_back (fn);
|
||||
|
||||
if (new_mru.size () > max_mru) {
|
||||
new_mru.erase (new_mru.begin ());
|
||||
new_mru.erase (new_mru.begin (), new_mru.end () - max_mru);
|
||||
}
|
||||
|
||||
std::string config_str;
|
||||
|
|
@ -2986,72 +2986,45 @@ class OpenRecentAction
|
|||
: public lay::Action
|
||||
{
|
||||
public:
|
||||
OpenRecentAction (lay::MainWindow *mw, size_t n)
|
||||
: lay::Action (), mp_mw (mw), m_n (n)
|
||||
OpenRecentAction (lay::MainWindow *mw, size_t n, void (lay::MainWindow::*open_meth) (size_t), bool (lay::MainWindow::*avail_meth) (size_t))
|
||||
: lay::Action (), mp_mw (mw), m_n (n), m_open_meth (open_meth), m_avail_meth (avail_meth)
|
||||
{ }
|
||||
|
||||
void triggered ()
|
||||
{
|
||||
mp_mw->open_recent (m_n);
|
||||
(mp_mw->*m_open_meth) (m_n);
|
||||
}
|
||||
|
||||
bool wants_enabled () const
|
||||
{
|
||||
return (mp_mw->*m_avail_meth) (m_n);
|
||||
}
|
||||
|
||||
private:
|
||||
lay::MainWindow *mp_mw;
|
||||
size_t m_n;
|
||||
void (lay::MainWindow::*m_open_meth) (size_t);
|
||||
bool (lay::MainWindow::*m_avail_meth) (size_t);
|
||||
};
|
||||
|
||||
class OpenRecentSessionAction
|
||||
class ClearRecentAction
|
||||
: public lay::Action
|
||||
{
|
||||
public:
|
||||
OpenRecentSessionAction (lay::MainWindow *mw, size_t n)
|
||||
: lay::Action (), mp_mw (mw), m_n (n)
|
||||
{ }
|
||||
ClearRecentAction (lay::MainWindow *mw, const std::string &cfg)
|
||||
: lay::Action (), mp_mw (mw), m_cfg (cfg)
|
||||
{
|
||||
set_title (tl::to_string (tr ("Clear List")));
|
||||
}
|
||||
|
||||
void triggered ()
|
||||
{
|
||||
mp_mw->open_recent_session (m_n);
|
||||
mp_mw->configure (m_cfg, std::string ());
|
||||
}
|
||||
|
||||
private:
|
||||
lay::MainWindow *mp_mw;
|
||||
size_t m_n;
|
||||
};
|
||||
|
||||
class OpenRecentLayerPropertiesAction
|
||||
: public lay::Action
|
||||
{
|
||||
public:
|
||||
OpenRecentLayerPropertiesAction (lay::MainWindow *mw, size_t n)
|
||||
: lay::Action (), mp_mw (mw), m_n (n)
|
||||
{ }
|
||||
|
||||
void triggered ()
|
||||
{
|
||||
mp_mw->open_recent_layer_properties (m_n);
|
||||
}
|
||||
|
||||
private:
|
||||
lay::MainWindow *mp_mw;
|
||||
size_t m_n;
|
||||
};
|
||||
|
||||
class OpenRecentBookmarksAction
|
||||
: public lay::Action
|
||||
{
|
||||
public:
|
||||
OpenRecentBookmarksAction (lay::MainWindow *mw, size_t n)
|
||||
: lay::Action (), mp_mw (mw), m_n (n)
|
||||
{ }
|
||||
|
||||
void triggered ()
|
||||
{
|
||||
mp_mw->open_recent_bookmarks (m_n);
|
||||
}
|
||||
|
||||
private:
|
||||
lay::MainWindow *mp_mw;
|
||||
size_t m_n;
|
||||
std::string m_cfg;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -3074,11 +3047,14 @@ MainWindow::do_update_mru_menus ()
|
|||
for (std::vector<std::pair<std::string, std::string> >::iterator mru = m_mru.end (); mru != m_mru.begin (); ) {
|
||||
--mru;
|
||||
size_t i = std::distance (m_mru.begin (), mru);
|
||||
Action *action = new OpenRecentAction (this, i);
|
||||
Action *action = new OpenRecentAction (this, i, &lay::MainWindow::open_recent, &lay::MainWindow::is_available_recent);
|
||||
action->set_title (mru->first);
|
||||
menu ()->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action);
|
||||
}
|
||||
|
||||
menu ()->insert_separator (mru_menu + ".end", "clear_sep");
|
||||
menu ()->insert_item (mru_menu + ".end", "clear_recent", new ClearRecentAction (this, cfg_mru));
|
||||
|
||||
} else {
|
||||
open_recent_action->set_enabled (false);
|
||||
}
|
||||
|
|
@ -3100,11 +3076,14 @@ MainWindow::do_update_mru_menus ()
|
|||
for (std::vector<std::string>::iterator mru = m_mru_sessions.end (); mru != m_mru_sessions.begin (); ) {
|
||||
--mru;
|
||||
size_t i = std::distance (m_mru_sessions.begin (), mru);
|
||||
Action *action = new OpenRecentSessionAction (this, i);
|
||||
Action *action = new OpenRecentAction (this, i, &lay::MainWindow::open_recent_session, &lay::MainWindow::is_available_recent_session);
|
||||
action->set_title (*mru);
|
||||
menu ()->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action);
|
||||
}
|
||||
|
||||
menu ()->insert_separator (mru_menu + ".end", "clear_sep");
|
||||
menu ()->insert_item (mru_menu + ".end", "clear_recent", new ClearRecentAction (this, cfg_mru_sessions));
|
||||
|
||||
} else {
|
||||
open_recent_action->set_enabled (false);
|
||||
}
|
||||
|
|
@ -3126,11 +3105,14 @@ MainWindow::do_update_mru_menus ()
|
|||
for (std::vector<std::string>::iterator mru = m_mru_layer_properties.end (); mru != m_mru_layer_properties.begin (); ) {
|
||||
--mru;
|
||||
size_t i = std::distance (m_mru_layer_properties.begin (), mru);
|
||||
Action *action = new OpenRecentLayerPropertiesAction (this, i);
|
||||
Action *action = new OpenRecentAction (this, i, &lay::MainWindow::open_recent_layer_properties, &lay::MainWindow::is_available_recent_layer_properties);
|
||||
action->set_title (*mru);
|
||||
menu ()->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action);
|
||||
}
|
||||
|
||||
menu ()->insert_separator (mru_menu + ".end", "clear_sep");
|
||||
menu ()->insert_item (mru_menu + ".end", "clear_recent", new ClearRecentAction (this, cfg_mru_layer_properties));
|
||||
|
||||
} else {
|
||||
open_recent_action->set_enabled (false);
|
||||
}
|
||||
|
|
@ -3152,11 +3134,14 @@ MainWindow::do_update_mru_menus ()
|
|||
for (std::vector<std::string>::iterator mru = m_mru_bookmarks.end (); mru != m_mru_bookmarks.begin (); ) {
|
||||
--mru;
|
||||
size_t i = std::distance (m_mru_bookmarks.begin (), mru);
|
||||
Action *action = new OpenRecentBookmarksAction (this, i);
|
||||
Action *action = new OpenRecentAction (this, i, &lay::MainWindow::open_recent_bookmarks, &lay::MainWindow::is_available_recent_bookmarks);
|
||||
action->set_title (*mru);
|
||||
menu ()->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action);
|
||||
}
|
||||
|
||||
menu ()->insert_separator (mru_menu + ".end", "clear_sep");
|
||||
menu ()->insert_item (mru_menu + ".end", "clear_recent", new ClearRecentAction (this, cfg_mru_bookmarks));
|
||||
|
||||
} else {
|
||||
open_recent_action->set_enabled (false);
|
||||
}
|
||||
|
|
@ -3218,6 +3203,25 @@ MainWindow::open_recent (size_t n)
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
static bool
|
||||
is_file_available (const std::string &fn)
|
||||
{
|
||||
tl::URI uri (fn);
|
||||
if (uri.scheme ().empty ()) {
|
||||
return tl::is_readable (fn);
|
||||
} else if (uri.scheme () == "file") {
|
||||
return tl::is_readable (uri.path ());
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::is_available_recent (size_t n)
|
||||
{
|
||||
return (n < m_mru.size () && is_file_available (m_mru [n].first));
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::open_recent_session (size_t n)
|
||||
{
|
||||
|
|
@ -3232,6 +3236,12 @@ MainWindow::open_recent_session (size_t n)
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::is_available_recent_session (size_t n)
|
||||
{
|
||||
return (n < m_mru_sessions.size () && is_file_available (m_mru_sessions [n]));
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::open_recent_layer_properties (size_t n)
|
||||
{
|
||||
|
|
@ -3246,6 +3256,12 @@ MainWindow::open_recent_layer_properties (size_t n)
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::is_available_recent_layer_properties (size_t n)
|
||||
{
|
||||
return (n < m_mru_layer_properties.size () && is_file_available (m_mru_layer_properties [n]));
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::open_recent_bookmarks (size_t n)
|
||||
{
|
||||
|
|
@ -3264,6 +3280,12 @@ MainWindow::open_recent_bookmarks (size_t n)
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::is_available_recent_bookmarks (size_t n)
|
||||
{
|
||||
return (n < m_mru_bookmarks.size () && is_file_available (m_mru_bookmarks [n]));
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::open (int mode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -637,6 +637,10 @@ public slots:
|
|||
void open_recent_session (size_t n);
|
||||
void open_recent_layer_properties (size_t n);
|
||||
void open_recent_bookmarks (size_t n);
|
||||
bool is_available_recent(size_t n);
|
||||
bool is_available_recent_session (size_t n);
|
||||
bool is_available_recent_layer_properties (size_t n);
|
||||
bool is_available_recent_bookmarks (size_t n);
|
||||
void view_selected (int index);
|
||||
void view_title_changed (lay::LayoutView *view);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,27 @@ public:
|
|||
on_triggered_event ();
|
||||
}
|
||||
|
||||
virtual bool wants_visible () const
|
||||
{
|
||||
if (wants_visible_cb.can_issue ()) {
|
||||
return wants_visible_cb.issue<lay::Action, bool> (&lay::Action::wants_visible);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool wants_enabled () const
|
||||
{
|
||||
if (wants_enabled_cb.can_issue ()) {
|
||||
return wants_enabled_cb.issue<lay::Action, bool> (&lay::Action::wants_enabled);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback triggered_cb;
|
||||
gsi::Callback wants_visible_cb;
|
||||
gsi::Callback wants_enabled_cb;
|
||||
tl::Event on_triggered_event;
|
||||
};
|
||||
|
||||
|
|
@ -291,10 +311,16 @@ Class<lay::Action> decl_ActionBase ("lay", "ActionBase",
|
|||
) +
|
||||
method ("is_effective_visible?", &lay::Action::is_effective_visible,
|
||||
"@brief Gets a value indicating whether the item is really visible\n"
|
||||
"This is the combined visibility from \\is_visible? and \\is_hidden?."
|
||||
"This is the combined visibility from \\is_visible? and \\is_hidden? and dynamic visibility (\\wants_visible)."
|
||||
"\n"
|
||||
"This attribute has been introduced in version 0.25.\n"
|
||||
) +
|
||||
method ("is_effective_enabled?", &lay::Action::is_effective_enabled,
|
||||
"@brief Gets a value indicating whether the item is really enabled\n"
|
||||
"This is the combined value from \\is_enabled? and dynamic value (\\wants_enabled)."
|
||||
"\n"
|
||||
"This attribute has been introduced in version 0.28.\n"
|
||||
) +
|
||||
method ("separator=", &lay::Action::set_separator, gsi::arg ("separator"),
|
||||
"@brief Makes an item a separator or not\n"
|
||||
"\n"
|
||||
|
|
@ -368,6 +394,24 @@ Class<ActionStub> decl_Action (decl_ActionBase, "lay", "Action",
|
|||
gsi::callback ("triggered", &ActionStub::triggered, &ActionStub::triggered_cb,
|
||||
"@brief This method is called if the menu item is selected"
|
||||
) +
|
||||
gsi::callback ("wants_visible", &ActionStub::wants_visible, &ActionStub::wants_visible_cb,
|
||||
"@brief Returns a value whether the action wants to become visible\n"
|
||||
"This is a dynamic query for visibility which the system uses to dynamically show or hide "
|
||||
"menu items, for example in the MRU lists. This visibility information is evaluated in addition "
|
||||
"to \\is_visible? and \\is_hidden? and contributes to the effective visibility status from "
|
||||
"\\is_effective_visible?.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::callback ("wants_enabled", &ActionStub::wants_enabled, &ActionStub::wants_enabled_cb,
|
||||
"@brief Returns a value whether the action wants to become enabled\n"
|
||||
"This is a dynamic query for enabled state which the system uses to dynamically show or hide "
|
||||
"menu items. This information is evaluated in addition "
|
||||
"to \\is_enabled? and contributes to the effective enabled status from "
|
||||
"\\is_effective_enabled?.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::event ("on_triggered", &ActionStub::on_triggered_event,
|
||||
"@brief This event is called if the menu item is selected\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ Action::Action () :
|
|||
#if defined(HAVE_QT)
|
||||
// catch the destroyed signal to tell if the QAction object is deleted.
|
||||
if (mp_action) {
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (triggered ()), this, SLOT (qaction_triggered ()));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -413,7 +413,7 @@ Action::Action (QAction *action, bool owned)
|
|||
sp_actionHandles->insert (this);
|
||||
|
||||
// catch the destroyed signal to tell if the QAction object is deleted.
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (triggered ()), this, SLOT (qaction_triggered ()));
|
||||
}
|
||||
|
||||
|
|
@ -436,7 +436,8 @@ Action::Action (QMenu *menu, bool owned)
|
|||
sp_actionHandles->insert (this);
|
||||
|
||||
// catch the destroyed signal to tell if the QAction object is deleted.
|
||||
connect (mp_menu, SIGNAL (destroyed (QObject *)), this, SLOT (destroyed (QObject *)));
|
||||
connect (mp_menu, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
connect (mp_menu, SIGNAL (aboutToShow ()), this, SLOT (menu_about_to_show ()));
|
||||
connect (mp_action, SIGNAL (triggered ()), this, SLOT (qaction_triggered ()));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -466,7 +467,7 @@ Action::Action (const std::string &title) :
|
|||
#if defined(HAVE_QT)
|
||||
// catch the destroyed signal to tell if the QAction object is deleted.
|
||||
if (mp_action) {
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (triggered ()), this, SLOT (qaction_triggered ()));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -536,6 +537,30 @@ Action::configure_from_title (const std::string &s)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Action::menu_about_to_show ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
if (! mp_dispatcher || ! mp_dispatcher->menu ()) {
|
||||
return;
|
||||
}
|
||||
AbstractMenuItem *item = mp_dispatcher->menu ()->find_item_for_action (this);
|
||||
if (! item ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto i = item->children.begin (); i != item->children.end (); ++i) {
|
||||
if (i->action ()) {
|
||||
i->action ()->sync_qaction ();
|
||||
}
|
||||
}
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Action::qaction_triggered ()
|
||||
|
|
@ -578,7 +603,7 @@ Action::menu () const
|
|||
}
|
||||
|
||||
void
|
||||
Action::destroyed (QObject *obj)
|
||||
Action::was_destroyed (QObject *obj)
|
||||
{
|
||||
if (obj == mp_action) {
|
||||
mp_action = 0;
|
||||
|
|
@ -591,17 +616,24 @@ Action::destroyed (QObject *obj)
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Action::sync_qaction ()
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
if (mp_action) {
|
||||
mp_action->setVisible (is_effective_visible ());
|
||||
mp_action->setShortcut (get_key_sequence ());
|
||||
mp_action->setEnabled (is_effective_enabled ());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
Action::set_visible (bool v)
|
||||
{
|
||||
if (m_visible != v) {
|
||||
m_visible = v;
|
||||
#if defined(HAVE_QT)
|
||||
if (mp_action) {
|
||||
mp_action->setVisible (is_effective_visible ());
|
||||
mp_action->setShortcut (get_key_sequence ());
|
||||
}
|
||||
#endif
|
||||
sync_qaction ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -610,12 +642,7 @@ Action::set_hidden (bool h)
|
|||
{
|
||||
if (m_hidden != h) {
|
||||
m_hidden = h;
|
||||
#if defined(HAVE_QT)
|
||||
if (mp_action) {
|
||||
mp_action->setVisible (is_effective_visible ());
|
||||
mp_action->setShortcut (get_key_sequence ());
|
||||
}
|
||||
#endif
|
||||
sync_qaction ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -634,7 +661,7 @@ Action::is_hidden () const
|
|||
bool
|
||||
Action::is_effective_visible () const
|
||||
{
|
||||
return m_visible && !m_hidden;
|
||||
return m_visible && !m_hidden && wants_visible ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -792,11 +819,7 @@ Action::is_checked () const
|
|||
bool
|
||||
Action::is_enabled () const
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
return qaction () ? qaction ()->isEnabled () : m_enabled;
|
||||
#else
|
||||
return m_enabled;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -808,12 +831,16 @@ Action::is_separator () const
|
|||
void
|
||||
Action::set_enabled (bool b)
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
if (qaction ()) {
|
||||
qaction ()->setEnabled (b);
|
||||
if (m_enabled != b) {
|
||||
m_enabled = b;
|
||||
sync_qaction ();
|
||||
}
|
||||
#endif
|
||||
m_enabled = b;
|
||||
}
|
||||
|
||||
bool
|
||||
Action::is_effective_enabled () const
|
||||
{
|
||||
return m_enabled && wants_enabled ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1508,6 +1535,33 @@ AbstractMenu::delete_items (Action *action)
|
|||
}
|
||||
}
|
||||
|
||||
const AbstractMenuItem *
|
||||
AbstractMenu::find_item_for_action (const Action *action, const AbstractMenuItem *from) const
|
||||
{
|
||||
return (const_cast<AbstractMenu *> (this))->find_item_for_action (action, const_cast<AbstractMenuItem *> (from));
|
||||
}
|
||||
|
||||
AbstractMenuItem *
|
||||
AbstractMenu::find_item_for_action (const Action *action, AbstractMenuItem *from)
|
||||
{
|
||||
if (! from) {
|
||||
from = const_cast<AbstractMenuItem *> (&root ());
|
||||
}
|
||||
|
||||
if (from->action () == action) {
|
||||
return from;
|
||||
}
|
||||
|
||||
for (auto i = from->children.begin (); i != from->children.end (); ++i) {
|
||||
AbstractMenuItem *item = find_item_for_action (action, i.operator-> ());
|
||||
if (item) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const AbstractMenuItem *
|
||||
AbstractMenu::find_item_exact (const std::string &path) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -318,6 +318,34 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating the action is visible (dynamic calls)
|
||||
* In addition to static visibility (visible/hidden), an Action object can request to
|
||||
* become invisible dynamically based on conditions. This will work for menu-items
|
||||
* for which the system will query the status before the menu is shown.
|
||||
*/
|
||||
virtual bool wants_visible () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating the action is enabled (dynamic calls)
|
||||
* In addition to static visibility (visible/hidden), an Action object can request to
|
||||
* become invisible dynamically based on conditions. This will work for menu-items
|
||||
* for which the system will query the status before the menu is shown.
|
||||
*/
|
||||
virtual bool wants_enabled () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the effective enabled state
|
||||
* This is the combined value from is_enabled and wants_enabled.
|
||||
*/
|
||||
bool is_effective_enabled () const;
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Get the underlying QAction object
|
||||
|
|
@ -342,8 +370,9 @@ public:
|
|||
|
||||
#if defined(HAVE_QT)
|
||||
protected slots:
|
||||
void destroyed (QObject *obj);
|
||||
void was_destroyed (QObject *obj);
|
||||
void qaction_triggered ();
|
||||
void menu_about_to_show ();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
@ -381,6 +410,7 @@ private:
|
|||
#endif
|
||||
|
||||
void configure_from_title (const std::string &s);
|
||||
void sync_qaction ();
|
||||
|
||||
// no copying
|
||||
Action (const Action &);
|
||||
|
|
@ -801,7 +831,7 @@ public:
|
|||
* @param group The group name
|
||||
* @param A vector of all members (as actions) of the group
|
||||
*/
|
||||
std::vector<Action *> group_actions(const std::string &name);
|
||||
std::vector<Action *> group_actions (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Get the configure actions for a given configuration name
|
||||
|
|
@ -844,6 +874,8 @@ private:
|
|||
std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator> > find_item (tl::Extractor &extr);
|
||||
const AbstractMenuItem *find_item_exact (const std::string &path) const;
|
||||
AbstractMenuItem *find_item_exact (const std::string &path);
|
||||
const AbstractMenuItem *find_item_for_action (const Action *action, const AbstractMenuItem *from = 0) const;
|
||||
AbstractMenuItem *find_item_for_action (const Action *action, AbstractMenuItem *from = 0);
|
||||
#if defined(HAVE_QT)
|
||||
void build (QMenu *menu, std::list<AbstractMenuItem> &items);
|
||||
void build (QToolBar *tbar, std::list<AbstractMenuItem> &items);
|
||||
|
|
|
|||
|
|
@ -227,20 +227,20 @@ RESULT
|
|||
$a1.visible = false
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_visible?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_checked?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_enabled?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_enabled?, true )
|
||||
|
||||
$a1.checked = true
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_visible?, false )
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_checked?, false )
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_checkable?, false )
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_enabled?, false )
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_enabled?, true )
|
||||
|
||||
$a1.checked = false
|
||||
$a1.checkable = true;
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_visible?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_checked?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_checkable?, true )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_enabled?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_enabled?, true )
|
||||
$a1.checked = true
|
||||
assert_equal( menu.action( "file_menu.#0" ).is_checked?, true )
|
||||
|
||||
|
|
@ -440,6 +440,50 @@ RESULT
|
|||
|
||||
end
|
||||
|
||||
class MyAction < RBA::Action
|
||||
attr_accessor :dyn_visible, :dyn_enabled
|
||||
def initialize
|
||||
self.dyn_visible = true
|
||||
self.dyn_enabled = true
|
||||
end
|
||||
def wants_visible
|
||||
self.dyn_visible
|
||||
end
|
||||
def wants_enabled
|
||||
self.dyn_enabled
|
||||
end
|
||||
end
|
||||
|
||||
def test_7
|
||||
|
||||
a = MyAction::new
|
||||
|
||||
assert_equal(a.is_effective_visible?, true)
|
||||
a.hidden = true
|
||||
assert_equal(a.is_effective_visible?, false)
|
||||
a.hidden = false
|
||||
assert_equal(a.is_effective_visible?, true)
|
||||
a.visible = false
|
||||
assert_equal(a.is_effective_visible?, false)
|
||||
a.visible = true
|
||||
assert_equal(a.is_effective_visible?, true)
|
||||
a.dyn_visible = false
|
||||
assert_equal(a.is_effective_visible?, false)
|
||||
a.dyn_visible = true
|
||||
assert_equal(a.is_effective_visible?, true)
|
||||
|
||||
assert_equal(a.is_effective_enabled?, true)
|
||||
a.enabled = false
|
||||
assert_equal(a.is_effective_enabled?, false)
|
||||
a.enabled = true
|
||||
assert_equal(a.is_effective_enabled?, true)
|
||||
a.dyn_enabled = false
|
||||
assert_equal(a.is_effective_enabled?, false)
|
||||
a.dyn_enabled = true
|
||||
assert_equal(a.is_effective_enabled?, true)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue