1 // -*- C++ -*-
2 /**
3  * \file ButtonPolicy.h
4  * This file is part of LyX, the document processor.
5  * Licence details can be found in the file COPYING.
6  *
7  * \author Allan Rae
8  *
9  * Full author contact details are available in file CREDITS.
10  *
11  * Provides a state machine implementation of the various button policies
12  * used by the dialogs.
13  */
14 
15 #ifndef BUTTONPOLICY_H
16 #define BUTTONPOLICY_H
17 
18 namespace lyx {
19 namespace frontend {
20 
21 /** A class for button policies.
22     A state machine implementation of the various button policies used by the
23     dialogs. Only the policy is implemented here.  Separate ButtonController
24     classes are needed for each GUI implementation.
25 
26     Policy                    | ReadOnly | Apply Button | Repeated Apply
27     ========================================================================
28     OkCancel                  |     N    |      N        |      -
29     OkCancelReadOnly          |     Y    |      N        |      -
30     OkApplyCancel             |     N    |      Y        |      Y
31     OkApplyCancelReadOnly     |     Y    |      Y        |      Y
32     NoRepeatedApply           |     N    |      Y        |      N
33     NoRepeatedApplyReadOnly   |     Y    |      Y        |      N
34     OkApplyCancelAutoReadOnly |     Y    |      Y        |      Y
35     Preferences               |     N    |      Y        | No (Ok-Close)
36     Ignorant                  |    N/A   |     N/A       |     N/A
37     ========================================================================
38 
39     Policy
40 	The name of the policy
41     ReadOnly
42 	Does the policy treat read-only docs differently to read-write docs?
43 	This usually means that when an SMI_READ_ONLY input arrives then
44 	all the buttons are disabled except Cancel/Close.  The state
45 	machine tracks the inputs (valid/invalid) and has states for all
46 	combinations. When an SMI_READ_WRITE input arrives the appropriate
47 	machine state is entered (just as if the document had always been
48 	read-write).
49 	NOTE: If a dialog doesn't care about the read-only status of a document
50 	(and uses an appropriate policy) it can never get into a read-only state
51 	so isReadOnly() can only ever return false even though the document may
52 	be read-only.
53     Repeated Apply
54 	Simply means that it is alright to use the Apply button multiple times
55 	without requiring a change of the dialog contents.  If no repeating is
56 	allowed the Ok+Apply buttons are deactivated.  The Preferences dialog
57 	has its own special version of repeated apply handling because its Ok
58 	button is actually a Save button -- it is always reasonable to Save the
59 	preferences if the dialog has changed since the last save.
60 
61     The IgnorantPolicy is a special case that allows anything.
62  */
63 
64 class ButtonPolicy
65 {
66 public:
67 
68 	// The various poicies
69 	enum Policy {
70 		/** Ok and Cancel buttons for dialogs with read-only operation.
71 			Note: This scheme supports the relabelling of Cancel to Close and
72 			vice versa.
73 			This is based on the value of the bool state of the Button::CANCEL.
74 			true == Cancel, false == Close
75 		 */
76 		OkCancelPolicy,
77 
78 
79 		/** Ok and Cancel buttons for dialogs where read-only operation is blocked.
80 			The state machine design for this policy allows changes to occur within
81 			the dialog while a file is read-only -- the okay button is disabled until
82 			a read-write input is given.  When the file is made read-write the dialog
83 			will then be in the correct state (as if the file had always been
84 			read-write).
85 			Note: This scheme supports the relabelling of Cancel to Close
86 			and vice versa.
87 			This is based on the value of the bool state of the Button::CANCEL.
88 			true == Cancel, false == Close
89 		 */
90 		OkCancelReadOnlyPolicy,
91 
92 		/** Ok, Apply and Cancel buttons for dialogs where read-only operation
93 			is blocked.
94 			Repeated Apply are not allowed.  Likewise,  Ok cannot follow Apply without
95 			some valid input. That is, the dialog contents must change between
96 			each Apply or Apply and Ok.
97 			The state machine design for this policy allows changes to occur within
98 			the dialog while a file is read-only -- the Ok+Apply buttons are disabled
99 			until a read-write input is given.  When the file is made read-write the
100 			dialog will then be in the correct state (as if the file had always been
101 			read-write).
102 			Note: This scheme supports the relabelling of Cancel to Close
103 			and vice versa.
104 			This is based on the value of the bool state of the Button::CANCEL.
105 			true == Cancel, false == Close
106 		 */
107 		NoRepeatedApplyReadOnlyPolicy,
108 
109 		/** Ok, Apply and Cancel buttons for dialogs where read-only
110 			operation is blocked.
111 			Repeated Apply is allowed.  Likewise,  Ok can follow Apply.
112 			The state machine design for this policy allows changes to occur within
113 			the dialog while a file is read-only -- the Ok+Apply buttons are disabled
114 			until a read-write input is given.  When the file is made read-write the
115 			dialog will then be in the correct state (as if the file had always been
116 			read-write).
117 			Note: This scheme supports the relabelling of Cancel to Close
118 			and vice versa.
119 			This is based on the value of the bool state of the Button::CANCEL.
120 			true == Cancel, false == Close
121 		 */
122 		OkApplyCancelReadOnlyPolicy,
123 
124 		/** Ok, Apply and Cancel buttons for dialogs where repeated
125 			Apply is allowed.
126 			Note: This scheme supports the relabelling of Cancel to Close
127 			and vice versa.
128 			This is based on the value of the bool state of the Button::CANCEL.
129 			true == Cancel, false == Close
130 		 */
131 		OkApplyCancelPolicy,
132 
133 		/** Ok, Apply and Cancel buttons for dialogs with no repeated Apply.
134 			Note: This scheme supports the relabelling of Cancel to Close
135 			and vice versa.
136 			This is based on the value of the bool state of the Button::CANCEL.
137 			true == Cancel, false == Close
138 		 */
139 		NoRepeatedApplyPolicy,
140 
141 		/** Ok, Apply and Cancel buttons and an AutoApply checkbox.
142 			Note: This scheme supports the relabelling of Cancel to Close
143 			and vice versa.
144 			This is based on the value of the bool state of the Button::CANCEL.
145 			true == Cancel, false == Close
146 		 */
147 		OkApplyCancelAutoReadOnlyPolicy,
148 
149 		/** Defines the policy used by the Preferences dialog.
150 			Four buttons: Ok (Save), Apply, Cancel/Close, Restore.
151 			Note: This scheme supports the relabelling of Cancel to Close
152 			and vice versa.
153 			This is based on the value of the bool state of the Button::CANCEL.
154 			true == Cancel, false == Close
155 		 */
156 		PreferencesPolicy,
157 
158 		/** Defines the policy used by dialogs that are forced to support a button
159 			controller when they either don't have a use for one or are not ready to
160 			use one.  This may be useful when testing a new button policy but wishing
161 			to minimise problems to users by supplying an anything-goes policy via a
162 			preprocessor directive.
163 		 */
164 		IgnorantPolicy
165 	};
166 
167 	/// Constructor
168 	explicit ButtonPolicy(Policy policy);
169 	/// Destructor
170 	~ButtonPolicy();
171 	///
172 	void setPolicy(Policy policy);
173 
174 	/** The various possible state names.
175 	    Not all state-machines have this many states.  However, we need
176 	    to define them all here so we can share the code.
177 	*/
178 	enum State {
179 		///
180 		INITIAL = 0,
181 		///
182 		VALID,
183 		///
184 		INVALID,
185 		///
186 		APPLIED,
187 		///
188 		AUTOAPPLY_INITIAL,
189 		///
190 		AUTOAPPLY_CHANGED,
191 		///
192 		RO_INITIAL,
193 		///
194 		RO_VALID,
195 		///
196 		RO_INVALID,
197 		///
198 		RO_APPLIED,
199 		///
200 		RO_AUTOAPPLY,
201 		///
202 		BOGUS = 55
203 	};
204 
205 	/// The various button types.
206 	enum Button {
207 		///
208 		CLOSE     = 0,  // Not a real button, but effectively !CANCEL
209 		///
210 		OKAY      = 1,
211 		///
212 		APPLY     = 2,
213 		///
214 		CANCEL    = 4,
215 		///
216 		RESTORE   = 8,
217 		///
218 		AUTOAPPLY = 16  // This is usually a checkbox
219 	};
220 	///
221 	static const Button ALL_BUTTONS =
222 		Button(OKAY | APPLY | CANCEL | RESTORE | AUTOAPPLY);
223 
224 	/** State machine inputs.
225 	    All the policies so far have both CANCEL and HIDE always going to
226 	    INITIAL. This won't necessarily be true for all [future] policies
227 	    though so I'll leave those two as distinct inputs rather than merge
228 	    them.  For example, a dialog that doesn't update it's input fields
229 	    when reshown after being hidden needs a policy where CANCEL and
230 	    HIDE are treated differently.
231 	 */
232 	enum SMInput {
233 		/// the dialog contents are now valid
234 		SMI_VALID = 0,
235 		/// the dialog contents are now invalid
236 		SMI_INVALID,
237 		/// an apply-and-hide action has happened
238 		SMI_OKAY,
239 		/// an apply action has happened
240 		SMI_APPLY,
241 		/// a cancel action has happened
242 		SMI_CANCEL,
243 		/// a restore action has happened
244 		SMI_RESTORE,
245 		/// apply auto-apply
246 		SMI_AUTOAPPLY,
247 		/// the dialog has been hidden
248 		SMI_HIDE,
249 		/// the dialog contents are read-only
250 		SMI_READ_ONLY,
251 		/// the dialog contents can be modified
252 		SMI_READ_WRITE,
253 		/// the state of the dialog contents has not changed
254 		SMI_NOOP,
255 		/// for internal use
256 		SMI_TOTAL
257 	};
258 
259 	/// Trigger a transition with this input.
260 	void input(SMInput);
261 	/** Activation status of a button.
262 	    We assume that we haven't gotten into an undefined state.
263 	    This is reasonable since we can only reach states defined
264 	    in the state machine and they should all have been defined in
265 	    the outputs_ variable.  Perhaps we can do something at compile
266 	    time to check that all the states have corresponding outputs.
267 	 */
268 	bool buttonStatus(Button) const;
269 	/// Are we in a read-only state?
270 	bool isReadOnly() const;
271 
272 private:
273 	/// noncopyable
274 	ButtonPolicy(ButtonPolicy const &);
275 	void operator=(ButtonPolicy const &);
276 
277 	/// pimpl
278 	class Private;
279 	Private * d;
280 };
281 
282 
283 } // namespace frontend
284 } // namespace lyx
285 
286 #endif
287