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