]> git.lyx.org Git - lyx.git/blob - src/frontends/controllers/ButtonPolicies.h
fix crash due to invalidated iterator
[lyx.git] / src / frontends / controllers / ButtonPolicies.h
1 // -*- C++ -*-
2 /**
3  * \file ButtonPolicies.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 BUTTONPOLICIES_H
16 #define BUTTONPOLICIES_H
17
18
19 #include <vector>
20 #include <boost/utility.hpp>
21
22 #include "support/std_ostream.h"
23
24 namespace lyx {
25 namespace frontend {
26
27 /** An abstract base class for button policies.
28     A state machine implementation of the various button policies used by the
29     dialogs. Only the policy is implemented here.  Separate ButtonController
30     classes are needed for each GUI implementation.
31
32                 Policy          | ReadOnly | Apply Button | Repeated Apply
33     ========================================================================
34     OkCancel                    |       N  |    N         |     -
35     OkCancelReadOnly            |       Y  |    N         |     -
36     OkApplyCancel               |       N  |    Y         |     Y
37     OkApplyCancelReadOnly       |       Y  |    Y         |     Y
38     NoRepeatedApply             |       N  |    Y         |     N
39     NoRepeatedApplyReadOnly     |       Y  |    Y         |     N
40     Preferences                 |       N  |    Y         | No (Ok-Close)
41     Ignorant                    |      N/A |    N/A       |    N/A
42     ========================================================================
43
44     Policy
45         The name of the policy
46     ReadOnly
47         Does the policy treat read-only docs differently to read-write docs?
48         This usually means that when an SMI_READ_ONLY input arrives then
49         all the buttons are disabled except Cancel/Close.  The state
50         machine tracks the inputs (valid/invalid) and has states for all
51         combinations. When an SMI_READ_WRITE input arrives the appropriate
52         machine state is entered (just as if the document had always been
53         read-write).
54         NOTE: If a dialog doesn't care about the read-only status of a document
55         (and uses an appropriate policy) it can never get into a read-only state
56         so isReadOnly() can only ever return false even though the document may
57         be read-only.
58     Repeated Apply
59         Simply means that it is alright to use the Apply button multiple times
60         without requiring a change of the dialog contents.  If no repeating is
61         allowed the Ok+Apply buttons are deactivated.  The Preferences dialog
62         has its own special version of repeated apply handling because its Ok
63         button is actually a Save button -- its always reasonable to Save the
64         preferences if the dialog has changed since the last save.
65
66     The IgnorantPolicy is a special case that allows anything.
67  */
68 class ButtonPolicy : boost::noncopyable {
69 public:
70         ///
71         virtual ~ButtonPolicy() {}
72
73         /** The various possible state names.
74             Not all state-machines have this many states.  However, we need
75             to define them all here so we can share the code.
76         */
77         enum State {
78                 ///
79                 INITIAL = 0,
80                 ///
81                 VALID,
82                 ///
83                 INVALID,
84                 ///
85                 APPLIED,
86                 ///
87                 RO_INITIAL,
88                 ///
89                 RO_VALID,
90                 ///
91                 RO_INVALID,
92                 ///
93                 RO_APPLIED,
94                 ///
95                 BOGUS = 55
96         };
97
98         /// The various button types.
99         enum Button {
100                 ///
101                 CLOSE    = 0,  // Not a real button, but effectively !CANCEL
102                 ///
103                 OKAY     = 1,
104                 ///
105                 APPLY    = 2,
106                 ///
107                 CANCEL   = 4,
108                 ///
109                 RESTORE = 8
110         };
111         ///
112         static const Button ALL_BUTTONS =
113                 Button(OKAY | APPLY | CANCEL | RESTORE);
114
115         /** State machine inputs.
116             All the policies so far have both CANCEL and HIDE always going to
117             INITIAL. This won't necessarily be true for all [future] policies
118             though so I'll leave those two as distinct inputs rather than merge
119             them.  For example, a dialog that doesn't update it's input fields
120             when reshown after being hidden needs a policy where CANCEL and
121             HIDE are treated differently.
122          */
123         enum SMInput {
124                 /// the dialog contents are now valid
125                 SMI_VALID = 0,
126                 /// the dialog contents are now invalid
127                 SMI_INVALID,
128                 /// an apply-and-hide action has happened
129                 SMI_OKAY,
130                 /// an apply action has happened
131                 SMI_APPLY,
132                 /// a cancel action has happened
133                 SMI_CANCEL,
134                 /// a restore action has happened
135                 SMI_RESTORE,
136                 /// the dialog has been hidden
137                 SMI_HIDE,
138                 /// the dialog contents are read-only
139                 SMI_READ_ONLY,
140                 /// the dialog contents can be modified
141                 SMI_READ_WRITE,
142                 /// the state of the dialog contents has not changed
143                 SMI_NOOP,
144                 /// for internal use
145                 SMI_TOTAL
146         };
147
148         /// Trigger a transition with this input.
149         virtual void input(SMInput) = 0;
150         /// Activation status of a button
151         virtual bool buttonStatus(Button) const = 0;
152         /// Are we in a read-only state?
153         virtual bool isReadOnly() const = 0;
154
155         /// Transition map of the state machine.
156         typedef std::vector<State> StateArray;
157         ///
158         typedef std::vector<StateArray> StateMachine;
159         /// The state outputs are the status of the buttons.
160         typedef std::vector<int> StateOutputs;
161 };
162
163
164 inline
165 std::ostream & operator<<(std::ostream & os, ButtonPolicy::State st)
166 {
167         os << int(st);
168         return os;
169 }
170
171
172 inline
173 std::ostream & operator<<(std::ostream & os, ButtonPolicy::SMInput smi)
174 {
175         os << int(smi);
176         return os;
177 }
178
179
180 //--------------------- Actual Policy Classes -----------------------------
181
182 /** Ok and Cancel buttons for dialogs with read-only operation.
183     Note: This scheme supports the relabelling of Cancel to Close and
184     vice versa.
185     This is based on the value of the bool state of the Button::CANCEL.
186     true == Cancel, false == Close
187  */
188 class OkCancelPolicy : public ButtonPolicy {
189 public:
190         ///
191         OkCancelPolicy();
192         ///
193         //virtual ~OkCancelPolicy() {}
194
195         /// Trigger a transition with this input.
196         virtual void input(SMInput);
197         /** Activation status of a button.
198             We assume that we haven't gotten into an undefined state.
199             This is reasonable since we can only reach states defined
200             in the state machine and they should all have been defined in
201             the outputs_ variable.  Perhaps we can do something at compile
202             time to check that all the states have corresponding outputs.
203          */
204         virtual bool buttonStatus(Button button) const {
205                 return button & outputs_[state_];
206         }
207         /// Are we in a read-only state?
208         virtual bool isReadOnly() const {
209                 return false;
210         }
211 private:
212         /// Current state.
213         State state_;
214         /// Which buttons are active for a given state.
215         StateOutputs outputs_;
216         ///
217         StateMachine state_machine_;
218 };
219
220 /** Ok and Cancel buttons for dialogs where read-only operation is blocked.
221     The state machine design for this policy allows changes to occur within
222     the dialog while a file is read-only -- the okay button is disabled until
223     a read-write input is given.  When the file is made read-write the dialog
224     will then be in the correct state (as if the file had always been
225     read-write).
226     Note: This scheme supports the relabelling of Cancel to Close
227     and vice versa.
228     This is based on the value of the bool state of the Button::CANCEL.
229     true == Cancel, false == Close
230  */
231 class OkCancelReadOnlyPolicy : public ButtonPolicy {
232 public:
233         ///
234         OkCancelReadOnlyPolicy();
235         ///
236         //virtual ~OkCancelReadOnlyPolicy() {}
237
238         /// Trigger a transition with this input.
239         virtual void input(SMInput);
240         /// Activation status of a button.
241         virtual bool buttonStatus(Button button) const {
242                 return button & outputs_[state_];
243         }
244         /// Are we in a read-only state?
245         virtual bool isReadOnly() const {
246                 return RO_INITIAL == state_
247                         || RO_VALID == state_
248                         || RO_INVALID == state_
249                         || RO_APPLIED == state_;
250         }
251 private:
252         /// Current state.
253         State state_;
254         /// Which buttons are active for a given state.
255         StateOutputs outputs_;
256         ///
257         StateMachine state_machine_;
258 };
259
260
261 /** Ok, Apply and Cancel buttons for dialogs where read-only operation
262     is blocked.
263     Repeated Apply are not allowed.  Likewise,  Ok cannot follow Apply without
264     some valid input. That is, the dialog contents must change between
265     each Apply or Apply and Ok.
266     The state machine design for this policy allows changes to occur within
267     the dialog while a file is read-only -- the Ok+Apply buttons are disabled
268     until a read-write input is given.  When the file is made read-write the
269     dialog will then be in the correct state (as if the file had always been
270     read-write).
271     Note: This scheme supports the relabelling of Cancel to Close
272     and vice versa.
273     This is based on the value of the bool state of the Button::CANCEL.
274     true == Cancel, false == Close
275  */
276 class NoRepeatedApplyReadOnlyPolicy : public ButtonPolicy {
277 public:
278         ///
279         NoRepeatedApplyReadOnlyPolicy();
280         ///
281         //virtual ~NoRepeatedApplyReadOnlyPolicy() {}
282
283         /// Trigger a transition with this input.
284         virtual void input(SMInput);
285         /// Activation status of a button.
286         virtual bool buttonStatus(Button button) const {
287                 return button & outputs_[state_];
288         }
289         /// Are we in a read-only state?
290         virtual bool isReadOnly() const {
291                 return RO_INITIAL == state_
292                         || RO_VALID == state_
293                         || RO_INVALID == state_
294                         || RO_APPLIED == state_;
295         }
296 private:
297         /// Current state.
298         State state_;
299         /// Which buttons are active for a given state.
300         StateOutputs outputs_;
301         ///
302         StateMachine state_machine_;
303 };
304
305
306 /** Ok, Apply and Cancel buttons for dialogs where read-only
307     operation is blocked.
308     Repeated Apply is allowed.  Likewise,  Ok can follow Apply.
309     The state machine design for this policy allows changes to occur within
310     the dialog while a file is read-only -- the Ok+Apply buttons are disabled
311     until a read-write input is given.  When the file is made read-write the
312     dialog will then be in the correct state (as if the file had always been
313     read-write).
314     Note: This scheme supports the relabelling of Cancel to Close
315     and vice versa.
316     This is based on the value of the bool state of the Button::CANCEL.
317     true == Cancel, false == Close
318  */
319 class OkApplyCancelReadOnlyPolicy : public ButtonPolicy {
320 public:
321         ///
322         OkApplyCancelReadOnlyPolicy();
323         ///
324         //virtual ~OkApplyCancelReadOnlyPolicy() {}
325
326         /// Trigger a transition with this input.
327         virtual void input(SMInput);
328         /// Activation status of a button.
329         virtual bool buttonStatus(Button button) const {
330                 return button & outputs_[state_];
331         }
332         /// Are we in a read-only state?
333         virtual bool isReadOnly() const {
334                 return RO_INITIAL == state_
335                         || RO_VALID == state_
336                         || RO_INVALID == state_
337                         || RO_APPLIED == state_;
338         }
339 private:
340         /// Current state.
341         State state_;
342         /// Which buttons are active for a given state.
343         StateOutputs outputs_;
344         ///
345         StateMachine state_machine_;
346 };
347
348
349 /** Ok, Apply and Cancel buttons for dialogs where repeated Apply is allowed.
350     Note: This scheme supports the relabelling of Cancel to Close
351     and vice versa.
352     This is based on the value of the bool state of the Button::CANCEL.
353     true == Cancel, false == Close
354  */
355 class OkApplyCancelPolicy : public ButtonPolicy {
356 public:
357         ///
358         OkApplyCancelPolicy();
359         ///
360         //virtual ~OkApplyCancelPolicy() {}
361
362         /// Trigger a transition with this input.
363         virtual void input(SMInput);
364         /// Activation status of a button.
365         virtual bool buttonStatus(Button button) const {
366                 return button & outputs_[state_];
367         }
368         /// Are we in a read-only state?
369         virtual bool isReadOnly() const {
370                 return false;
371         }
372 private:
373         /// Current state.
374         State state_;
375         /// Which buttons are active for a given state.
376         StateOutputs outputs_;
377         ///
378         StateMachine state_machine_;
379 };
380
381
382 /** Ok, Apply and Cancel buttons for dialogs with no repeated Apply.
383     Note: This scheme supports the relabelling of Cancel to Close
384     and vice versa.
385     This is based on the value of the bool state of the Button::CANCEL.
386     true == Cancel, false == Close
387  */
388 class NoRepeatedApplyPolicy : public ButtonPolicy {
389 public:
390         ///
391         NoRepeatedApplyPolicy();
392         ///
393         //virtual ~NoRepeatedApplyPolicy() {}
394
395         /// Trigger a transition with this input.
396         virtual void input(SMInput);
397         /// Activation status of a button.
398         virtual bool buttonStatus(Button button) const {
399                 return button & outputs_[state_];
400         }
401         /// Are we in a read-only state?
402         virtual bool isReadOnly() const {
403                 return false;
404         }
405 private:
406         /// Current state.
407         State state_;
408         /// Which buttons are active for a given state.
409         StateOutputs outputs_;
410         ///
411         StateMachine state_machine_;
412 };
413
414
415 /** Defines the policy used by the Preferences dialog.
416     Four buttons: Ok (Save), Apply, Cancel/Close, Restore.
417     Note: This scheme supports the relabelling of Cancel to Close
418     and vice versa.
419     This is based on the value of the bool state of the Button::CANCEL.
420     true == Cancel, false == Close
421  */
422 class PreferencesPolicy : public ButtonPolicy {
423 public:
424         ///
425         PreferencesPolicy();
426         ///
427         //virtual ~PreferencesPolicy() {}
428
429         /// Trigger a transition with this input.
430         virtual void input(SMInput);
431         /// Activation status of a button.
432         virtual bool buttonStatus(Button button) const {
433                 return button & outputs_[state_];
434         }
435         /// Are we in a read-only state?
436         virtual bool isReadOnly() const {
437                 return false;
438         }
439 private:
440         /// Current state.
441         State state_;
442         /// Which buttons are active for a given state.
443         StateOutputs outputs_;
444         ///
445         StateMachine state_machine_;
446 };
447
448
449 /** Defines the policy used by dialogs that are forced to support a button
450     controller when they either don't have a use for one or are not ready to
451     use one.  This may be useful when testing a new button policy but wishing
452     to minimise problems to users by supplying an anything-goes policy via a
453     preprocessor directive.
454  */
455 class IgnorantPolicy : public ButtonPolicy {
456 public:
457         //virtual ~IgnorantPolicy() {}
458
459         /// Trigger a transition with this input.
460         virtual void input(SMInput) {}
461         /// Activation status of a button.
462         virtual bool buttonStatus(Button) const {
463                 return true;
464         }
465         /// Are we in a read-only state?
466         virtual bool isReadOnly() const {
467                 return false;
468         }
469 };
470
471 } // namespace frontend
472 } // namespace lyx
473
474 #endif