1 /* 2 * Stellarium 3 * Copyright (C) 2013 Guillaume Chereau 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; either version 2 8 * of the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 */ 19 20 #ifndef STELACTIONMGR_HPP 21 #define STELACTIONMGR_HPP 22 23 #include "StelPropertyMgr.hpp" 24 #include <QKeySequence> 25 #include <QList> 26 27 //! Wrapper around an argumentless QObject slot or a bool Q_PROPERTY with WRITE method, 28 //! allowing the slot to be called/property to be toggled using this action object. 29 //! The action object can be identified by a unique string, and found through StelActionMgr::findAction. 30 //! Use StelActionMgr::addAction to define a new action. 31 //! In StelModule subclasses, one can also use StelModule::addAction for convenience. 32 //! 33 //! StelAction objects are intended for user interaction. They automatically show up in the hotkey configuration dialog 34 //! (ShortcutsDialog), and can be bound to interface buttons (StelButton). 35 //! 36 //! StelAction internally uses a StelProperty, if connected to a property. 37 //! A new StelProperty with the name of the action is registered automatically in this case. 38 //! A NOTIFY signal should be provided, though not strictly necessary, it is really recommended. 39 //! @note If you want to have a globally accessible reference to arbitrary Q_PROPERTY instances (not just bool), 40 //! or don't want to expose the property to the user you could use a StelProperty directly registered through the StelPropertyMgr instead. 41 //! @see StelActionMgr, StelProperty 42 class StelAction : public QObject 43 { 44 Q_OBJECT 45 public: 46 //! When the StelAction is @ref checkable, this may be used to get/set the current value. 47 //! Note that the @ref toggled signal may not be emitted on all changes of the connected property 48 //! @warning If used on a non-checkable action, the program may crash. 49 Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY toggled) 50 //! If this is true, this StelAction can be toggled. 51 //! This is the case when connected to a boolean Q_PROPERTY. 52 //! This means the @ref checked property as well as the toggle() function may be used 53 //! If false, the StelAction represents a simple argumentless slot call. Using @ref checked or toggle() may 54 //! result in an error. 55 Q_PROPERTY(bool checkable READ isCheckable) 56 57 //! @see checkable 58 bool isCheckable() const {return boolProperty;} 59 //! @see checked isChecked() const60 bool isChecked() const {return boolProperty ? boolProperty->getValue().toBool() : false; } isGlobal() const61 bool isGlobal() const {return global;} 62 //! Defines the key-combination used to call this action 63 void setShortcut(const QString& key); 64 //! Defines an alternative key-combination 65 void setAltShortcut(const QString& key); 66 QKeySequence::SequenceMatch matches(const QKeySequence& seq) const; 67 68 //! The ID of this action. Must be unique. getId() const69 QString getId() const {return objectName();} getGroup() const70 QString getGroup() const {return group;} getShortcut() const71 const QKeySequence getShortcut() const {return keySequence;} getAltShortcut() const72 const QKeySequence getAltShortcut() const {return altKeySequence;} 73 QString getText() const; setText(const QString & value)74 void setText(const QString& value) {text = value; emit changed();} 75 signals: 76 //! Emitted when the boolean state of this StelAction changes. 77 //! When the action is connected to a StelProperty, 78 //! this is equivalent to the StelProperty::valueChanged signal. 79 //! In the other cases, this state may not always be emitted correctly 80 //! (i.e. when the state changes through other mechanisms than StelAction) 81 void toggled(bool); 82 //! Emitted after an argumentless slot has been called 83 void triggered(); 84 //! Emitted when additional data associated with this action changed (i.e. shortcuts, text,...) 85 void changed(); 86 public slots: 87 //! @see checked 88 //! @warning If used on a non-checkable action, the program may crash. 89 void setChecked(bool); 90 //! If the action is @ref checkable, toggle() is called. 91 //! Otherwise, the connected slot is invoked. 92 void trigger(); 93 //! If the action is @ref checkable, this toggles the value of 94 //! the connected boolean property. 95 //! @warning If used on a non-checkable action, the program may crash. 96 void toggle(); 97 private slots: 98 void propertyChanged(bool); 99 private: 100 friend class StelActionMgr; 101 102 //! Constructor is used by StelActionMgr 103 StelAction(const QString& actionId, 104 const QString& groupId, 105 const QString& text, 106 const QString& primaryKey="", 107 const QString& altKey="", 108 bool global=false); 109 //! Connect the action to an object property or slot. 110 //! @param slot A property or a slot name. The slot can either have the signature `func()`, and in that 111 //! case the action is made not checkable, or have the signature `func(bool)` and in that case the action 112 //! is made checkable. When linked to a property the action is always made checkable. 113 void connectToObject(QObject* target, const char* slot); 114 115 QString group; 116 QString text; 117 bool global; 118 QKeySequence keySequence; 119 QKeySequence altKeySequence; 120 const QKeySequence defaultKeySequence; 121 const QKeySequence defaultAltKeySequence; 122 QObject* target; 123 //If the StelAction is connected to a boolean property with a NOTIFY signal, a StelProperty is used for the connection 124 StelProperty* boolProperty; 125 QMetaMethod slot; 126 127 // Currently, there is no proper way to handle shortcuts with non latin 128 // keyboards layouts. So for the moment, if we don't use QuickView, we 129 // create a QAction added to the main view that will trigger the 130 // StelAction when the shortcut is typed. 131 #ifndef USE_QUICKVIEW 132 private slots: 133 void onChanged(); 134 private: 135 class QAction* qAction; 136 #endif 137 }; 138 139 //! Manager for StelAction instances. Allows registration of new actions, and finding an existing one by name. 140 class StelActionMgr : public QObject 141 { 142 Q_OBJECT 143 public: 144 StelActionMgr(); 145 ~StelActionMgr(); 146 //! Create and add a new StelAction, connected to an object property or slot. 147 //! @param id Global identifier. 148 //! @param groupId Group identifier. 149 //! @param text Short human-readable description in English. 150 //! @param target The QObject the action is linked to. 151 //! @param slot The target slot or property that the action will trigger. 152 //! Either a slot name of the form 'func()' and in that case the 153 //! action is made non checkable, a slot name of the form 154 //! 'func(bool)' and in that case the action is made checkable, 155 //! or a property name and in that case the action is made 156 //! checkable. 157 //! @param shortcut Default shortcut/key combination for this action 158 //! @param altShortcut Alternative shortcut 159 //! @param global determines QAction shortcut context (not necessary anymore?) 160 StelAction* addAction(const QString& id, const QString& groupId, const QString& text, 161 QObject* target, const char* slot, 162 const QString& shortcut="", const QString& altShortcut="", 163 bool global=false); 164 165 //! Create and add a new StelAction, connected to an object slot. 166 //! @param id Global identifier. 167 //! @param groupId Group identifier. 168 //! @param text Short human-readable description in English. 169 //! @param context a reference object. When this is deleted, the Lambda function will not be called. 170 //! @param lambda a void function (Lambda). This can call slots and other functions. 171 //! @param shortcut Default shortcut/key combination for this action 172 //! @param altShortcut Alternative shortcut 173 //! @param global determines QAction shortcut context (not necessary anymore?) 174 StelAction* addAction(const QString& id, const QString& groupId, const QString& text, 175 QObject* context, std::function<void()> lambda, 176 const QString& shortcut="", const QString& altShortcut="", 177 bool global=false); 178 179 StelAction* findAction(const QString& id); 180 StelAction* findActionFromShortcut(const QString& shortcut); 181 bool pushKey(int key, bool global=false); 182 183 //! Returns a list of all current StelAction groups 184 QStringList getGroupList() const; 185 //! Returns all StelActions in the specified group 186 QList<StelAction*> getActionList(const QString& group) const; 187 //! Returns all registered StelActions 188 QList<StelAction*> getActionList() const; 189 QStringList getShortcutsList() const; 190 191 //! Save current shortcuts to file. 192 void saveShortcuts(); 193 //! Restore the default shortcuts combinations 194 void restoreDefaultShortcuts(); 195 void restoreDefaultShortcut(StelAction* action); 196 197 signals: 198 //! Emitted when any action registered with this StelActionMgr is toggled 199 //! @param id The id of the action that was toggled 200 //! @param value The new value of the action 201 void actionToggled(const QString& id, bool value); 202 203 void shortcutsChanged(); 204 205 public slots: 206 //! Enable/disable all actions of application. 207 //! need for editing shortcuts without trigging any actions 208 //! @todo find out if this is really necessary and why. setAllActionsEnabled(bool value)209 void setAllActionsEnabled(bool value) {actionsEnabled = value;} 210 211 private slots: 212 void onStelActionToggled(bool val); 213 214 private: 215 bool actionsEnabled; 216 QList<int> keySequence; 217 }; 218 219 #endif // STELACTIONMGR_HPP 220