1 /*
2  * %kadu copyright begin%
3  * Copyright 2010, 2011 Piotr Galiszewski (piotr.galiszewski@kadu.im)
4  * Copyright 2014 Piotr Dąbrowski (ultr@ultr.pl)
5  * Copyright 2010, 2011, 2014 Bartosz Brachaczek (b.brachaczek@gmail.com)
6  * Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
7  * %kadu copyright end%
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #ifndef ACTION_DESCRIPTION_H
24 #define ACTION_DESCRIPTION_H
25 
26 #include <QtCore/QMap>
27 #include <QtCore/QObject>
28 #include <QtCore/QPointer>
29 #include <QtWidgets/QToolButton>
30 #include <functional>
31 #include <injeqt/injeqt.h>
32 
33 #include "configuration/configuration-aware-object.h"
34 #include "icons/kadu-icon.h"
35 
36 class QAction;
37 class QMenu;
38 
39 class ActionContext;
40 class Actions;
41 class Action;
42 class Configuration;
43 class InjectedFactory;
44 
45 using ActionBoolCallback = std::function<void(Action *)>;
46 
47 /**
48  * @addtogroup Actions
49  * @{
50  */
51 
52 /**
53  * @class ActionDescription
54  * @author Rafał 'Vogel' Malinowski
55  * @short Class responsible for describing and creating actions for windows.
56  *
57  * This class is used to describe actions that can be created and inserted into menus and
58  * toolbars on different types of windows. Some actions can be only used in connection with
59  * chats, users, search window or history window. Some actions are only useable in main
60  * menu of Kadu.
61  *
62  * For each action each window gets its own instance of Action class created by given ActionDescription
63  * object. This is required because each window contains different objects (like chats, contacts and
64  * buddies) and may have different conditions for enabling/disabling actions. Windows are mapped
65  * as ActionContext interfaces - each type of window or widget can have its own implementation
66  * of this interface.
67  *
68  * Actions can be simple actions or actions with menu. If action has menu, it has to implement
69  * menuForAction method. Each menuForAction must return different instance of menu, as this method is called
70  * only once for each Action and menu will be destroyed when Action is destroyed.
71  *
72  * ActionDescription has two constructors. One of them is public and has a lot ofparameters. This
73  * is depreceated and will be removed in 0.11.0 or 0.12.0 release. This constructor registers action
74  * automatically.
75  *
76  * Second constructor is protected and had only one parameter - parent. This one should be called
77  * by subclasses. Then all setXXX methods should be called to set up proper values of ActionDescription
78  * properties. After setting all values registerAction method must be called so action can be used
79  * on toolbars in menus. Do not call registerAction before setting all properties.
80  *
81  * Unregistering of action is automatically performed by destructor.
82  */
83 class KADUAPI ActionDescription : public QObject, protected ConfigurationAwareObject
84 {
85 	Q_OBJECT
86 
87 public:
88 
89 	enum ActionType {
90 		TypeGlobal   = 0x0001, //!< actions with TypeGlobal type does not require access to user list or anything window-dependent
91 		TypeUser     = 0x0002, //!< actions with TypeUser type requires access to one or more users from user list
92 		TypeChat     = 0x0004, //!< actions with TypeChat type requires access to chat window
93 		TypeSearch   = 0x0008, //!< actions with TypeSearch type requires access to search window
94 		TypeUserList = 0x0010, //!< actions with TypeUserList type requires access to user list widget
95 		TypeHistory  = 0x0020, //!< actions with TypeHistory type requires access to history window
96 		TypeMainMenu = 0x0040,
97 		TypePrivate  = 0x0080, //!< actions with TypePrivate can not be placed on toolbars by users
98 		TypeAll      = 0xFFFF  //!< TypeAll is used to set masks for all types of actions
99 	};
100 
101 private:
102 	friend class Action;
103 
104 	QPointer<Actions> m_actions;
105 	QPointer<Configuration> m_configuration;
106 	QPointer<InjectedFactory> m_injectedFactory;
107 	bool m_selfRegister;
108 
109 	QMap<ActionContext *, Action *> MappedActions;
110 	bool Deleting;
111 
112 	ActionType Type;
113 	QString Name;
114 	QObject *Object;
115 	const char *Slot;
116 	KaduIcon Icon;
117 	QString Text;
118 	bool Checkable;
119 	ActionBoolCallback EnableCallback;
120 	QString ShortcutItem;
121 	Qt::ShortcutContext ShortcutContext;
122 
123 private slots:
124 	INJEQT_SET void setActions(Actions *actions);
125 	INJEQT_SET void setConfiguration(Configuration *configuration);
126 	INJEQT_SET void setInjectedFactory(InjectedFactory *injectedFactory);
127 	INJEQT_INIT void init();
128 
129 	void actionAboutToBeDestroyed(Action *action);
130 	void actionTriggeredSlot(QAction *sender, bool toggled);
131 
132 protected:
133 	Configuration * configuration() const;
134 	InjectedFactory * injectedFactory() const;
135 
136 	/**
137 	 * @author Rafał 'Vogel' Malinowski
138 	 * @short Creates new instance of ActionDescription with given parent.
139 	 * @param parent QObject parent of ActionDescription.
140 	 *
141 	 * Created new empty instance of ActionDescription. Call setters and registerActions to
142 	 * make this action description useable.
143 	 */
144 	ActionDescription(QObject *parent);
145 
146 	Actions * actionsRegistry() const;
147 
148 	/**
149 	 * @author Rafał 'Vogel' Malinowski
150 	 * @short Registers this action in global action list.
151 	 *
152 	 * Registers this action in global action list. Called automatically by depreceated public
153 	 * constructor. In new implementation this should be called from subclasses after all apprioprate
154 	 * setters were called.
155 	 */
156 	void registerAction(Actions *actions);
157 
158 	/**
159 	 * @author Rafał 'Vogel' Malinowski
160 	 * @short Unregisters this action from global action list.
161 	 *
162 	 * Registers this action from global action list. Called automatically by destructor. No need to call
163 	 * this manually.
164 	 */
165 	void unregisterAction(Actions *actions);
166 
167 	/**
168 	 * @author Rafał 'Vogel' Malinowski
169 	 * @todo rename to actionCreated after actionCreated slot is removed
170 	 * @short Called when new instance of Action is created.
171 	 * @param action newly created action
172 	 *
173 	 * This method is called automatically when new instance of Action is created. It allows to set uo
174 	 * additional Action parameters.
175 	 *
176 	 * By defult this method checks if this instance of Actions should have menu attached and creates it
177 	 * if needed (see menuForAction).
178 	 *
179 	 * Old implementations of actions uses actionCreated signal that is now depreceated.
180 	 */
181 	virtual void actionInstanceCreated(Action *action);
182 
183 	/**
184 	 * @author Rafał 'Vogel' Malinowski
185 	 * @todo make abstract when actions are moved to new API
186 	 * @short Called when instance of Action is triggered.
187 	 * @param sender instance of QAction that was triggered
188 	 * @param toggled true, if action was toggled on
189 	 *
190 	 * This method is called automatically when instance of QAction is triggered.
191 	 *
192 	 * By defult this method does nothing.
193 	 *
194 	 * Old implementations of actions uses object and slot parameters in constructor to get notification
195 	 * about action triggering.
196 	 */
actionTriggered(QAction * sender,bool toggled)197 	virtual void actionTriggered(QAction *sender, bool toggled)
198 	{
199 		Q_UNUSED(sender)
200 		Q_UNUSED(toggled)
201 	}
202 
203 	/**
204 	 * @author Rafał 'Vogel' Malinowski
205 	 * @todo make abstract when actions are moved to new API
206 	 * @short Called when instance of Action is triggered.
207 	 * @param widget parent widget of triggered action
208 	 * @param context context of triggered action
209 	 * @param toggled true, if action was toggled on
210 	 *
211 	 * This method is called automatically when instance of QAction is triggered.
212 	 *
213 	 * By defult this method does nothing.
214 	 *
215 	 * Old implementations of actions uses object and slot parameters in constructor to get notification
216 	 * about action triggering.
217 	 */
triggered(QWidget * widget,ActionContext * context,bool toggled)218 	virtual void triggered(QWidget *widget, ActionContext *context, bool toggled)
219 	{
220 		Q_UNUSED(widget)
221 		Q_UNUSED(context)
222 		Q_UNUSED(toggled)
223 	}
224 
225 	/**
226 	 * @author Rafał 'Vogel' Malinowski
227 	 * @short Updates enabled/disabled state of given action.
228 	 * @param action action to update state for
229 	 *
230 	 * This method is called by by Action class when it requies to update its own state (like disabled/enable).
231 	 * By defult this method calls EnableCallback callback for this action.
232 	 */
233 	virtual void updateActionState(Action *action);
234 
235 	/**
236 	 * @author Rafał 'Vogel' Malinowski
237 	 * @short Creates menu for given new instance of Action.
238 	 * @param action action to create menu for
239 	 *
240 	 * This method is called by default implementation of actionInstanceCreated. This method should
241 	 * return null when no menu for given action is required. New instance of QMenu should be returned
242 	 * when this actions requires menu. Please note that Action takes ownership of this QMenu instance
243 	 * and can delete it at any moment.
244 	 *
245 	 * By defult this method returns null.
246 	 */
247 	virtual QMenu * menuForAction(Action *action);
248 
249 	virtual void connectNotify(const QMetaMethod &signal);
250 	virtual void configurationUpdated();
251 
252 public:
253 	/**
254 	 * @author Rafał 'Vogel' Malinowski
255 	 * @short Depreceated contructor.
256 	 *
257 	 * Depreceated contructor.
258 	 */
259 	ActionDescription(QObject *parent, ActionType type, const QString &name, QObject *object, const char *slot,
260 			const KaduIcon &icon, const QString &text, bool checkable = false, ActionBoolCallback enableCallback = 0);
261 	virtual ~ActionDescription();
262 
263 	/**
264 	 * @author Rafał 'Vogel' Malinowski
265 	 * @short Creates instance of Action for given ActionContext.
266 	 * @param context context of new Action instance
267 	 * @param parent parent of new Action instance
268 	 *
269 	 * This method creates new instance of Action for given ActionContext or returns existing one, if action for
270 	 * given ActionContext was already created. Each ActionContext will have different instance of Actions.
271 	 *
272 	 * This method calls actionInstanceCreated and emits actionCreated if new instance were created.
273 	 */
274 	Action * createAction(ActionContext *context, QObject *parent);
275 
276 	/**
277 	 * @author Rafał 'Vogel' Malinowski
278 	 * @short Returns list of all Actions created from this ActionDescription.
279 	 *
280 	 * Returns list of all Actions created from this ActionDescription.
281 	 */
282 	QList<Action *> actions();
283 
284 	/**
285 	 * @author Rafał 'Vogel' Malinowski
286 	 * @short Returns Action instance connected with given ActionContext.
287 	 * @param context ActionContext to search Action for
288 	 *
289 	 * Returns Action instance connected with given ActionContext or 0 when no Action was created.
290 	 */
291 	Action * action(ActionContext *context);
292 
293 	void setType(ActionType type);
294 	void setName(const QString &name);
295 	void setConnection(QObject *object, const char *slot);
296 	void setIcon(const KaduIcon &icon);
297 	void setText(const QString &text);
298 	void setCheckable(bool checkable);
299 	void setActionCallback(ActionBoolCallback enableCallback);
300 
type()301 	ActionType type() const { return Type; }
name()302 	const QString & name() const { return Name; }
icon()303 	const KaduIcon & icon() const { return Icon; }
text()304 	const QString & text() const { return Text; }
isCheckable()305 	bool isCheckable() const { return Checkable; }
306 
307 	void setShortcut(QString configItem, Qt::ShortcutContext context = Qt::WindowShortcut);
308 
309 	/**
310 	 * @author Rafał 'Vogel' Malinowski
311 	 * @short Returns QToolButton::ToolButtonPopupMode for given action.
312 	 *
313 	 * Returns QToolButton::ToolButtonPopupMode for given action. This allows actions with menu that
314 	 * can have default behavior or not. By default actions have default behavior - QToolButton::MenuButtonPopup
315 	 * is returned.
316 	 *
317 	 * If action does not have default behavior no method will be called after clicking on method. Reimplementing
318 	 * actionTriggered is then not required.
319 	 */
buttonPopupMode()320 	virtual QToolButton::ToolButtonPopupMode buttonPopupMode() const
321 	{
322 		return QToolButton::MenuButtonPopup;
323 	}
324 
325 	/**
326 	 * @short Updates states of all actions of this type.
327 	 */
328 	void updateActionStates();
329 
330 signals:
331 	void actionCreated(Action *);
332 
333 };
334 
335 /**
336  * @}
337  */
338 
339 #endif // ACTION_DESCRIPTION_H
340