Primary fix issue #318 (unable to remove key binding)

For a backward compatible solution, a key binding
target of '' still means "take default". For
"nothing", a new pseudo-key "none" was defined.

For scripting, this value is available as
constant "Action#NoShortCut".
This commit is contained in:
Matthias Koefferlein 2019-08-17 19:17:40 +02:00
parent e33c2f7b66
commit 4659569333
7 changed files with 134 additions and 69 deletions

View File

@ -407,6 +407,7 @@ CustomizeMenuConfigPage::CustomizeMenuConfigPage (QWidget *parent)
mp_ui->binding_le->setEnabled (false);
mp_ui->binding_le->set_clear_button_enabled (true);
connect (mp_ui->binding_le, SIGNAL (clear_pressed ()), this, SLOT (text_cleared ()));
connect (mp_ui->binding_le, SIGNAL (textChanged (QString)), this, SLOT (text_changed ()));
mp_ui->filter->set_clear_button_enabled (true);
@ -433,7 +434,7 @@ static void get_shortcuts (const lay::AbstractMenu &menu, const std::string &roo
}
get_shortcuts (menu, *i, bindings, with_defaults);
} else if (! menu.is_separator (*i)) {
bindings.insert (std::make_pair (*i, with_defaults ? menu.action (*i).get_default_shortcut () : menu.action (*i).get_shortcut ()));
bindings.insert (std::make_pair (*i, with_defaults ? menu.action (*i).get_default_shortcut () : menu.action (*i).get_effective_shortcut ()));
}
}
}
@ -483,7 +484,8 @@ CustomizeMenuConfigPage::apply (const std::vector<std::pair<std::string, std::st
for (std::map<std::string, std::string>::iterator kb = m_current_bindings.begin (); kb != m_current_bindings.end (); ++kb) {
std::map<std::string, std::string>::iterator bb = b.find (kb->first);
if (bb != b.end ()) {
kb->second = bb->second;
lay::Action a = lay::MainWindow::instance ()->menu ()->action (kb->first);
kb->second = a.get_effective_shortcut_for (bb->second);
} else {
kb->second.clear ();
}
@ -517,13 +519,9 @@ CustomizeMenuConfigPage::apply (const std::vector<std::pair<std::string, std::st
bool hidden = m_hidden_flags[cb->first];
std::map<std::string, std::string>::const_iterator db = default_bindings.find (cb->first);
bool is_default = false;
std::string sc = cb->second;
if (sc.empty () && db != default_bindings.end ()) {
sc = db->second;
is_default = true;
}
bool is_default = (db != default_bindings.end () && db->second == sc);
const std::string &path = cb->first;
@ -599,7 +597,16 @@ CustomizeMenuConfigPage::commit (lay::PluginRoot *root)
for (std::vector<std::pair<std::string, std::string> >::iterator kb = key_bindings.begin (); kb != key_bindings.end (); ++kb) {
std::map<std::string, std::string>::iterator cb = m_current_bindings.find (kb->first);
if (cb != m_current_bindings.end ()) {
kb->second = cb->second;
lay::Action a = lay::MainWindow::instance ()->menu ()->action (kb->first);
if (cb->second != a.get_default_shortcut ()) {
if (cb->second.empty ()) {
kb->second = lay::Action::no_shortcut ();
} else {
kb->second = cb->second;
}
} else {
kb->second.clear ();
}
m_current_bindings.erase (cb);
}
}
@ -631,6 +638,21 @@ CustomizeMenuConfigPage::commit (lay::PluginRoot *root)
root->config_set (cfg_menu_items_hidden, packed_hidden_flags);
}
void
CustomizeMenuConfigPage::text_cleared ()
{
QTreeWidgetItem *item = mp_ui->bindings_list->currentItem ();
if (! item) {
return;
}
std::string path = tl::to_string (item->data (0, Qt::UserRole).toString ());
lay::Action a = lay::MainWindow::instance ()->menu ()->action (path);
// "clear" reverts to default
mp_ui->binding_le->setText (tl::to_qstring (a.get_default_shortcut ()));
}
void
CustomizeMenuConfigPage::text_changed ()
{
@ -673,17 +695,18 @@ CustomizeMenuConfigPage::update_list_item (QTreeWidgetItem *item)
std::string path = tl::to_string (item->data (0, Qt::UserRole).toString ());
std::string shortcut = tl::to_string (mp_ui->binding_le->text ().simplified ());
// normalize string
shortcut = tl::to_string (QKeySequence (tl::to_qstring (shortcut)).toString ());
m_current_bindings[path] = shortcut;
bool is_default = false;
std::string eff_shortcut = shortcut;
if (shortcut.empty ()) {
lay::Action a = lay::MainWindow::instance ()->menu ()->action (path);
eff_shortcut = a.get_default_shortcut ();
is_default = true;
}
item->setData (2, Qt::DisplayRole, tl::to_qstring (eff_shortcut));
lay::Action a = lay::MainWindow::instance ()->menu ()->action (path);
std::string def_shortcut = a.get_default_shortcut ();
is_default = (def_shortcut == shortcut);
item->setData (2, Qt::DisplayRole, tl::to_qstring (shortcut));
item->setData (2, Qt::ForegroundRole, palette ().color (is_default ? QPalette::Disabled : QPalette::Normal, QPalette::Text));
// Set the aliases too
@ -696,7 +719,7 @@ CustomizeMenuConfigPage::update_list_item (QTreeWidgetItem *item)
m_current_bindings[*p] = shortcut;
std::map<std::string, QTreeWidgetItem *>::const_iterator i = m_item_for_path.find (*p);
if (i != m_item_for_path.end ()) {
i->second->setData (2, Qt::DisplayRole, tl::to_qstring (eff_shortcut));
i->second->setData (2, Qt::DisplayRole, tl::to_qstring (shortcut));
i->second->setData (2, Qt::ForegroundRole, palette ().color (is_default ? QPalette::Disabled : QPalette::Normal, QPalette::Text));
}
}

View File

@ -199,6 +199,7 @@ private slots:
void current_changed (QTreeWidgetItem *current, QTreeWidgetItem *previous);
void item_changed (QTreeWidgetItem *, int);
void text_changed ();
void text_cleared ();
void filter_changed ();
void reset_clicked ();

View File

@ -157,8 +157,16 @@ Class<lay::Action> decl_ActionBase ("lay", "ActionBase",
method ("shortcut=", (void (lay::Action::*)(const std::string &)) &lay::Action::set_shortcut,
"@brief Sets the keyboard shortcut\n"
"@args shortcut\n"
"If the shortcut string is empty, the default shortcut will be used. If the string "
"is equal to \\Action#NoShortCut, no keyboard shortcut will be assigned.\n"
"\n"
"@param shortcut The keyboard shortcut (i.e. \"Ctrl+C\")\n"
"@param shortcut The keyboard shortcut in Qt notation (i.e. \"Ctrl+C\")\n"
"\n"
"The NoShortCut option has been added in version 0.26."
) +
constant ("NoShortCut", &lay::Action::no_shortcut,
"@brief Gets a shortcut value indicating that no shortcut shall be assigned\n"
"This method has been introduced in version 0.26."
) +
method ("shortcut", &lay::Action::get_shortcut,
"@brief Gets the keyboard shortcut\n"

View File

@ -279,7 +279,8 @@ ActionHandle::ActionHandle (QWidget *parent)
m_ref_count (0),
m_owned (true),
m_visible (true),
m_hidden (false)
m_hidden (false),
m_no_key_sequence (false)
{
if (! sp_actionHandles) {
sp_actionHandles = new std::set<ActionHandle *> ();
@ -296,7 +297,8 @@ ActionHandle::ActionHandle (QAction *action, bool owned)
m_ref_count (0),
m_owned (owned),
m_visible (true),
m_hidden (false)
m_hidden (false),
m_no_key_sequence (false)
{
if (! sp_actionHandles) {
sp_actionHandles = new std::set<ActionHandle *> ();
@ -313,7 +315,8 @@ ActionHandle::ActionHandle (QMenu *menu, bool owned)
m_ref_count (0),
m_owned (owned),
m_visible (true),
m_hidden (false)
m_hidden (false),
m_no_key_sequence (false)
{
if (! sp_actionHandles) {
sp_actionHandles = new std::set<ActionHandle *> ();
@ -390,7 +393,7 @@ ActionHandle::set_visible (bool v)
m_visible = v;
if (mp_action) {
mp_action->setVisible (is_effective_visible ());
mp_action->setShortcut (get_effective_shortcut ());
mp_action->setShortcut (get_key_sequence ());
}
}
}
@ -402,7 +405,7 @@ ActionHandle::set_hidden (bool h)
m_hidden = h;
if (mp_action) {
mp_action->setVisible (is_effective_visible ());
mp_action->setShortcut (get_effective_shortcut ());
mp_action->setShortcut (get_key_sequence ());
}
}
}
@ -426,49 +429,69 @@ ActionHandle::is_effective_visible () const
}
void
ActionHandle::set_default_shortcut (const QKeySequence &sc)
ActionHandle::set_default_shortcut (const std::string &sc)
{
if (m_default_shortcut != sc) {
m_default_shortcut = sc;
m_default_key_sequence = QKeySequence (tl::to_qstring (sc));
if (mp_action) {
mp_action->setShortcut (get_effective_shortcut ());
mp_action->setShortcut (get_key_sequence ());
}
}
}
void
ActionHandle::set_shortcut (const QKeySequence &sc)
ActionHandle::set_shortcut (const std::string &sc)
{
if (m_shortcut != sc) {
m_shortcut = sc;
m_no_key_sequence = (sc == Action::no_shortcut ());
m_key_sequence = m_no_key_sequence ? QKeySequence () : QKeySequence (tl::to_qstring (m_shortcut));
if (mp_action) {
mp_action->setShortcut (get_effective_shortcut ());
mp_action->setShortcut (get_key_sequence ());
}
}
}
const QKeySequence &
std::string
ActionHandle::get_default_shortcut () const
{
return m_default_shortcut;
return tl::to_string (m_default_key_sequence.toString ());
}
const QKeySequence &
std::string
ActionHandle::get_shortcut () const
{
return m_shortcut;
return m_no_key_sequence ? Action::no_shortcut () : tl::to_string (m_key_sequence.toString ());
}
QKeySequence
ActionHandle::get_effective_shortcut () const
ActionHandle::get_key_sequence () const
{
if (m_hidden) {
// A hidden menu item does not have a key sequence too.
return QKeySequence ();
} else if (m_shortcut.isEmpty ()) {
return m_default_shortcut;
} else if (m_no_key_sequence) {
return QKeySequence ();
} else if (m_key_sequence.isEmpty ()) {
return m_default_key_sequence;
} else {
return m_shortcut;
return m_key_sequence;
}
}
QKeySequence
ActionHandle::get_key_sequence_for (const std::string &sc) const
{
if (m_hidden) {
// A hidden menu item does not have a key sequence too.
return QKeySequence ();
} else if (sc.empty ()) {
return m_default_key_sequence;
} else if (sc == Action::no_shortcut ()) {
return QKeySequence ();
} else {
return QKeySequence::fromString (tl::to_qstring (sc));
}
}
@ -485,6 +508,13 @@ Action::Action ()
}
}
const std::string &
Action::no_shortcut ()
{
static const std::string no_shortcut ("none");
return no_shortcut;
}
Action::Action (const std::string &title)
{
mp_handle = AbstractMenu::create_action (title);
@ -587,7 +617,7 @@ Action::get_title () const
}
void
Action::set_shortcut (const QKeySequence &s)
Action::set_shortcut (const std::string &s)
{
if (mp_handle) {
mp_handle->set_shortcut (s);
@ -595,30 +625,28 @@ Action::set_shortcut (const QKeySequence &s)
}
void
Action::set_default_shortcut (const QKeySequence &s)
Action::set_default_shortcut (const std::string &s)
{
if (mp_handle) {
mp_handle->set_default_shortcut (s);
}
}
void
Action::set_shortcut (const std::string &s)
{
set_shortcut (QKeySequence (tl::to_qstring (s)));
}
void
Action::set_default_shortcut (const std::string &s)
{
set_default_shortcut (QKeySequence (tl::to_qstring (s)));
}
std::string
Action::get_effective_shortcut () const
{
if (mp_handle) {
return tl::to_string (mp_handle->get_effective_shortcut ().toString ());
return tl::to_string (mp_handle->get_key_sequence ().toString ());
} else {
return std::string ();
}
}
std::string
Action::get_effective_shortcut_for (const std::string &sc) const
{
if (mp_handle) {
return tl::to_string (mp_handle->get_key_sequence_for (sc).toString ());
} else {
return std::string ();
}
@ -628,7 +656,7 @@ std::string
Action::get_shortcut () const
{
if (mp_handle) {
return tl::to_string (mp_handle->get_shortcut ().toString ());
return mp_handle->get_shortcut ();
} else {
return std::string ();
}
@ -638,7 +666,7 @@ std::string
Action::get_default_shortcut () const
{
if (mp_handle) {
return tl::to_string (mp_handle->get_default_shortcut ().toString ());
return mp_handle->get_default_shortcut ();
} else {
return std::string ();
}
@ -930,7 +958,7 @@ AbstractMenu::create_action (const std::string &s)
}
if (! shortcut.empty ()) {
ah->set_default_shortcut (QKeySequence (tl::to_qstring (shortcut)));
ah->set_default_shortcut (shortcut);
}
return ah;

View File

@ -79,11 +79,12 @@ public:
bool is_hidden () const;
bool is_effective_visible () const;
void set_default_shortcut (const QKeySequence &sc);
void set_shortcut (const QKeySequence &sc);
const QKeySequence &get_default_shortcut () const;
const QKeySequence &get_shortcut () const;
QKeySequence get_effective_shortcut () const;
void set_default_shortcut (const std::string &sc);
void set_shortcut (const std::string &sc);
std::string get_default_shortcut () const;
std::string get_shortcut() const;
QKeySequence get_key_sequence () const;
QKeySequence get_key_sequence_for (const std::string &sc) const;
protected slots:
void destroyed (QObject *obj);
@ -95,8 +96,11 @@ private:
bool m_owned;
bool m_visible;
bool m_hidden;
QKeySequence m_default_shortcut;
QKeySequence m_shortcut;
std::string m_default_shortcut;
QKeySequence m_default_key_sequence;
std::string m_shortcut;
QKeySequence m_key_sequence;
bool m_no_key_sequence;
// no copying
ActionHandle (const ActionHandle &);
@ -173,14 +177,14 @@ public:
std::string get_title () const;
/**
* @brief Sets the keyboard shortcut (as a QKeySequence object)
* If no shortcut is set, the default shortcut will be taken.
* @brief Gets the shortcut string for "no shortcut present"
*/
void set_shortcut (const QKeySequence &s);
static const std::string &no_shortcut ();
/**
* @brief Sets the keyboard shortcut
* If no shortcut is set, the default shortcut will be taken.
* If no shortcut is set (empty string), the default shortcut will be taken.
* If the shortcut string is "no_shortcut()", no shortcut will be assigned to the item.
*/
void set_shortcut (const std::string &s);
@ -191,12 +195,6 @@ public:
*/
std::string get_shortcut () const;
/**
* @brief Sets the default keyboard shortcut (as a QKeySequence object)
* This shortcut is used when no specific shortcut is set.
*/
void set_default_shortcut (const QKeySequence &s);
/**
* @brief Sets the default keyboard shortcut
* This shortcut is used when no specific shortcut is set.
@ -215,6 +213,11 @@ public:
*/
std::string get_effective_shortcut () const;
/**
* @brief Gets the effective shortcut for a given key sequence string
*/
std::string get_effective_shortcut_for (const std::string &sc) const;
/**
* @brief "is_checkable" attribute
*/

View File

@ -1100,6 +1100,7 @@ void DecoratedLineEdit::mouseReleaseEvent (QMouseEvent *event)
if (c == mp_clear_label) {
clear ();
emit clear_pressed (); // might modify the text
emit textEdited (text ());
}

View File

@ -439,6 +439,7 @@ signals:
void esc_pressed ();
void tab_pressed ();
void backtab_pressed ();
void clear_pressed ();
protected:
void mousePressEvent (QMouseEvent *event);