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