1 /**
2  * \file ButtonPolicy.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Allan Rae
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10 
11 #include <config.h>
12 
13 #include "ButtonPolicy.h"
14 
15 #include "support/debug.h"
16 
17 #include <iostream>
18 #include <vector>
19 
20 using namespace std;
21 
22 namespace lyx {
23 namespace frontend {
24 
printState(ButtonPolicy::State const & state)25 static char const * printState(ButtonPolicy::State const & state)
26 {
27 	switch (state) {
28 		case ButtonPolicy::INITIAL:
29 			return "INITIAL";
30 		case ButtonPolicy::VALID:
31 			return "VALID";
32 		case ButtonPolicy::INVALID:
33 			return "INVALID";
34 		case ButtonPolicy::APPLIED:
35 			return "APPLIED";
36 		case ButtonPolicy::AUTOAPPLY_INITIAL:
37 			return "AUTOAPPLY_INITIAL";
38 		case ButtonPolicy::AUTOAPPLY_CHANGED:
39 			return "AUTOAPPLY_CHANGED";
40 		case ButtonPolicy::RO_INITIAL:
41 			return "RO_INITIAL";
42 		case ButtonPolicy::RO_VALID:
43 			return "RO_VALID";
44 		case ButtonPolicy::RO_INVALID:
45 			return "RO_INVALID";
46 		case ButtonPolicy::RO_APPLIED:
47 			return "RO_APPLIED";
48 		case ButtonPolicy::RO_AUTOAPPLY:
49 			return "RO_AUTOAPPLY";
50 		case ButtonPolicy::BOGUS:
51 			return "BOGUS";
52 		default:
53 			return "";
54 	}
55 }
56 
57 
printInput(ButtonPolicy::SMInput const & input)58 static char const * printInput(ButtonPolicy::SMInput const & input)
59 {
60 	switch (input) {
61 		case ButtonPolicy::SMI_VALID:
62 			return "SMI_VALID";
63 		case ButtonPolicy::SMI_INVALID:
64 			return "SMI_INVALID";
65 		case ButtonPolicy::SMI_OKAY:
66 			return "SMI_OKAY";
67 		case ButtonPolicy::SMI_APPLY:
68 			return "SMI_APPLY";
69 		case ButtonPolicy::SMI_CANCEL:
70 			return "SMI_CANCEL";
71 		case ButtonPolicy::SMI_RESTORE:
72 			return "SMI_RESTORE";
73 		case ButtonPolicy::SMI_AUTOAPPLY:
74 			return "SMI_AUTOAPPLY";
75 		case ButtonPolicy::SMI_HIDE:
76 			return "SMI_HIDE";
77 		case ButtonPolicy::SMI_READ_ONLY:
78 			return "SMI_READ_ONLY";
79 		case ButtonPolicy::SMI_READ_WRITE:
80 			return "SMI_READ_WRITE";
81 		case ButtonPolicy::SMI_NOOP:
82 			return "SMI_NOOP";
83 		case ButtonPolicy::SMI_TOTAL:
84 			return "SMI_TOTAL";
85 		default:
86 			return "";
87 	}
88 }
89 
90 
functionName(ButtonPolicy::Policy policy)91 char const * functionName(ButtonPolicy::Policy policy)
92 {
93 	switch (policy) {
94 		case ButtonPolicy::PreferencesPolicy:
95 			return "PreferencesPolicy";
96 		case ButtonPolicy::OkCancelPolicy:
97 			return "OkCancelPolicy";
98 		case ButtonPolicy::OkCancelReadOnlyPolicy:
99 			return "OkCancelReadOnlyPolicy";
100 		case ButtonPolicy::OkApplyCancelPolicy:
101 			return "OkApplyCancelPolicy";
102 		case ButtonPolicy::OkApplyCancelReadOnlyPolicy:
103 			return "OkApplyCancelReadOnlyPolicy";
104 		case ButtonPolicy::OkApplyCancelAutoReadOnlyPolicy:
105 			return "OkApplyCancelAutoReadOnlyPolicy";
106 		case ButtonPolicy::NoRepeatedApplyPolicy:
107 			return "NoRepeatedApplyPolicy";
108 		case ButtonPolicy::NoRepeatedApplyReadOnlyPolicy:
109 			return "NoRepeatedApplyReadOnlyPolicy";
110 		case ButtonPolicy::IgnorantPolicy:
111 			return "IgnorantPolicy";
112 		default:
113 			return "Unknown policy";
114 	}
115 }
116 
117 
operator <<(ostream & os,ButtonPolicy::State st)118 ostream & operator<<(ostream & os, ButtonPolicy::State st)
119 {
120 	return os << int(st);
121 }
122 
123 
operator <<(ostream & os,ButtonPolicy::SMInput smi)124 ostream & operator<<(ostream & os, ButtonPolicy::SMInput smi)
125 {
126 	return os << int(smi);
127 }
128 
129 
130 /////////////////////////////////////////////////////////////////////////
131 //
132 // ButtonPolicy::Private
133 //
134 /////////////////////////////////////////////////////////////////////////
135 
136 class ButtonPolicy::Private
137 {
138 public:
139 	typedef ButtonPolicy::SMInput SMInput;
140 	typedef ButtonPolicy::Policy Policy;
141 	typedef ButtonPolicy::State State;
142 
143 	Private(Policy policy);
144 
145 	void nextState(SMInput input);
146 
147 	void initOkCancel();
148 	void initOkCancelReadOnly();
149 	void initNoRepeatedApplyReadOnly();
150 	void initOkApplyCancelReadOnly();
151 	void initOkApplyCancelAutoReadOnly();
152 	void initOkApplyCancel();
153 	void initNoRepeatedApply();
154 	void initPreferences();
155 
156 public:
157 	///
158 	Policy policy_;
159 
160 	/// Transition map of the state machine.
161 	typedef std::vector<State> StateArray;
162 	///
163 	typedef std::vector<StateArray> StateMachine;
164 	/// The state outputs are the status of the buttons.
165 	typedef std::vector<int> StateOutputs;
166 
167 	/// Current state.
168 	State state_;
169 	/// Which buttons are active for a given state.
170 	StateOutputs outputs_;
171 	///
172 	StateMachine state_machine_;
173 };
174 
175 
Private(Policy policy)176 ButtonPolicy::Private::Private(Policy policy)
177 {
178 	policy_ = policy;
179 	state_ = INITIAL;
180 
181 	switch (policy_) {
182 		case OkCancelPolicy:
183 			initOkCancel();
184 			break;
185 		case OkCancelReadOnlyPolicy:
186 			initOkCancelReadOnly();
187 			break;
188 		case OkApplyCancelPolicy:
189 			initOkApplyCancel();
190 			break;
191 		case OkApplyCancelReadOnlyPolicy:
192 			initOkApplyCancelReadOnly();
193 			break;
194 		case OkApplyCancelAutoReadOnlyPolicy:
195 			initOkApplyCancelAutoReadOnly();
196 			break;
197 		case NoRepeatedApplyPolicy:
198 			initNoRepeatedApply();
199 			break;
200 		case NoRepeatedApplyReadOnlyPolicy:
201 			initNoRepeatedApplyReadOnly();
202 			break;
203 		case PreferencesPolicy:
204 			initPreferences();
205 			break;
206 		case IgnorantPolicy:
207 			break;
208 	}
209 }
210 
211 
nextState(SMInput input)212 void ButtonPolicy::Private::nextState(SMInput input)
213 {
214 	if (SMI_NOOP == input)
215 		return;
216 
217 	State tmp = state_machine_[state_][input];
218 
219 	LYXERR(Debug::GUI, "Transition from state "
220 			   << printState(state_) << " to state "
221 			   << printState(tmp) << " after input "
222 			   << printInput(input));
223 
224 	if (tmp != BOGUS) {
225 		state_ = tmp;
226 	} else {
227 		LYXERR0(functionName(policy_) << ": No transition for input "
228 	    << printInput(input) << " from state " << printState(state_));
229 	}
230 }
231 
232 
initPreferences()233 void ButtonPolicy::Private::initPreferences()
234 {
235 	outputs_ = StateOutputs(APPLIED + 1, ButtonPolicy::ALL_BUTTONS);
236 	state_machine_ = StateMachine(APPLIED + 1,
237 			 StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS));
238 
239 	// Build the state output map
240 	outputs_[INITIAL] = CLOSE;
241 	outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL;
242 	outputs_[INVALID] = RESTORE | CANCEL;
243 	outputs_[APPLIED] = OKAY | CLOSE;
244 
245 	// Build the state machine one state at a time
246 	// NOTE:  Since CANCEL and HIDE always go to INITIAL they are
247 	//        left out of the state machine and handled explicitly
248 	//        in input().  This won't necessarily be true for all
249 	//        policies though so I'll leave those two as distinct
250 	//        inputs rather than merge them.  For example, a dialog
251 	//        that doesn't update it's input fields when reshown
252 	//        after being hidden needs a policy where CANCEL and
253 	//        HIDE are treated differently.
254 	//
255 	// State::INITIAL
256 	state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL;
257 	state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL;
258 	state_machine_[INITIAL][SMI_VALID] = VALID;
259 	state_machine_[INITIAL][SMI_INVALID] = INVALID;
260 	// State::VALID
261 	state_machine_[VALID][SMI_VALID] = VALID;
262 	state_machine_[VALID][SMI_READ_ONLY] = VALID;
263 	state_machine_[VALID][SMI_READ_WRITE] = VALID;
264 	state_machine_[VALID][SMI_INVALID] = INVALID;
265 	state_machine_[VALID][SMI_APPLY] = APPLIED;
266 	state_machine_[VALID][SMI_OKAY] = INITIAL;
267 	state_machine_[VALID][SMI_RESTORE] = INITIAL;
268 	// State::INVALID
269 	state_machine_[INVALID][SMI_VALID] = VALID;
270 	state_machine_[INVALID][SMI_INVALID] = INVALID;
271 	state_machine_[INVALID][SMI_READ_ONLY] = INVALID;
272 	state_machine_[INVALID][SMI_READ_WRITE] = INVALID;
273 	state_machine_[INVALID][SMI_RESTORE] = INITIAL;
274 	// State::APPLIED
275 	state_machine_[APPLIED][SMI_VALID] = VALID;
276 	state_machine_[APPLIED][SMI_INVALID] = INVALID;
277 	state_machine_[APPLIED][SMI_OKAY] = INITIAL;
278 	state_machine_[APPLIED][SMI_READ_ONLY] = APPLIED;
279 	state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED;
280 }
281 
282 
initOkCancel()283 void ButtonPolicy::Private::initOkCancel()
284 {
285 	outputs_ = StateOutputs(INVALID + 1, ButtonPolicy::ALL_BUTTONS);
286 	state_machine_ = StateMachine(INVALID + 1,
287 			 StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS));
288 
289 	// Build the state output map
290 	outputs_[INITIAL] = CLOSE;
291 	outputs_[VALID] = RESTORE | OKAY | CANCEL;
292 	outputs_[INVALID] = RESTORE | CANCEL;
293 
294 	// Build the state machine one state at a time
295 	// NOTE:  Since CANCEL and HIDE always go to INITIAL they are
296 	//        left out of the state machine and handled explicitly
297 	//        in input()
298 	//
299 	// State::INITIAL
300 	state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL;
301 	state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL;
302 	state_machine_[INITIAL][SMI_VALID] = VALID;
303 	state_machine_[INITIAL][SMI_INVALID] = INVALID;
304 	// State::VALID
305 	state_machine_[VALID][SMI_VALID] = VALID;
306 	state_machine_[VALID][SMI_READ_ONLY] = VALID;
307 	state_machine_[VALID][SMI_READ_WRITE] = VALID;
308 	state_machine_[VALID][SMI_INVALID] = INVALID;
309 	state_machine_[VALID][SMI_OKAY] = INITIAL;
310 	state_machine_[VALID][SMI_RESTORE] = INITIAL;
311 	// State::INVALID
312 	state_machine_[INVALID][SMI_VALID] = VALID;
313 	state_machine_[INVALID][SMI_INVALID] = INVALID;
314 	state_machine_[INVALID][SMI_READ_ONLY] = INVALID;
315 	state_machine_[INVALID][SMI_READ_WRITE] = INVALID;
316 	state_machine_[INVALID][SMI_RESTORE] = INITIAL;
317 }
318 
319 
initOkCancelReadOnly()320 void ButtonPolicy::Private::initOkCancelReadOnly()
321 {
322 	outputs_ = StateOutputs(RO_INVALID + 1, ButtonPolicy::ALL_BUTTONS);
323 	state_machine_ = StateMachine(RO_INVALID + 1,
324 			 StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS));
325 
326 	// Build the state output map
327 	outputs_[INITIAL] = CLOSE;
328 	outputs_[VALID] = RESTORE | OKAY | CANCEL;
329 	outputs_[INVALID] = RESTORE | CANCEL;
330 	outputs_[RO_INITIAL] = CLOSE;
331 	outputs_[RO_VALID] = RESTORE | CANCEL;
332 	outputs_[RO_INVALID] = RESTORE | CANCEL;
333 
334 	// Build the state machine one state at a time
335 	// NOTE:  Since CANCEL and HIDE always go to INITIAL they are
336 	//        left out of the state machine and handled explicitly
337 	//        in input()
338 	//
339 	// State::INITIAL
340 	state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL;
341 	state_machine_[INITIAL][SMI_VALID] = VALID;
342 	state_machine_[INITIAL][SMI_INVALID] = INVALID;
343 	state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL;
344 	// State::VALID
345 	state_machine_[VALID][SMI_VALID] = VALID;
346 	state_machine_[VALID][SMI_READ_WRITE] = VALID;
347 	state_machine_[VALID][SMI_INVALID] = INVALID;
348 	state_machine_[VALID][SMI_OKAY] = INITIAL;
349 	state_machine_[VALID][SMI_RESTORE] = INITIAL;
350 	state_machine_[VALID][SMI_READ_ONLY] = RO_VALID;
351 	// State::INVALID
352 	state_machine_[INVALID][SMI_INVALID] = INVALID;
353 	state_machine_[INVALID][SMI_READ_WRITE] = INVALID;
354 	state_machine_[INVALID][SMI_VALID] = VALID;
355 	state_machine_[INVALID][SMI_RESTORE] = INITIAL;
356 	state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID;
357 	// State::RO_INITIAL
358 	state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL;
359 	state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID;
360 	state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID;
361 	state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL;
362 	// State::RO_VALID
363 	state_machine_[RO_VALID][SMI_VALID] = RO_VALID;
364 	state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID;
365 	state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID;
366 	state_machine_[RO_VALID][SMI_READ_WRITE] = VALID;
367 	state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL;
368 	// State::RO_INVALID
369 	state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID;
370 	state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID;
371 	state_machine_[RO_INVALID][SMI_VALID] = RO_VALID;
372 	state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID;
373 	state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL;
374 }
375 
376 
initNoRepeatedApplyReadOnly()377 void ButtonPolicy::Private::initNoRepeatedApplyReadOnly()
378 {
379 	outputs_ = StateOutputs(RO_INVALID + 1, ButtonPolicy::ALL_BUTTONS);
380 	state_machine_ = StateMachine(RO_INVALID + 1,
381 			 StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS));
382 
383 	// Build the state output map
384 	outputs_[INITIAL] = CLOSE;
385 	outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL;
386 	outputs_[INVALID] = RESTORE | CANCEL;
387 	outputs_[RO_INITIAL] = CLOSE;
388 	outputs_[RO_VALID] = RESTORE | CANCEL;
389 	outputs_[RO_INVALID] = RESTORE | CANCEL;
390 
391 	// Build the state machine one state at a time
392 	// NOTE:  Since CANCEL and HIDE always go to INITIAL they are
393 	//        left out of the state machine and handled explicitly
394 	//        in input()
395 	//
396 	// State::INITIAL
397 	state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL;
398 	state_machine_[INITIAL][SMI_VALID] = VALID;
399 	state_machine_[INITIAL][SMI_INVALID] = INVALID;
400 	state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL;
401 	// State::VALID
402 	state_machine_[VALID][SMI_VALID] = VALID;
403 	state_machine_[VALID][SMI_READ_WRITE] = VALID;
404 	state_machine_[VALID][SMI_INVALID] = INVALID;
405 	state_machine_[VALID][SMI_OKAY] = INITIAL;
406 	state_machine_[VALID][SMI_APPLY] = INITIAL;
407 	state_machine_[VALID][SMI_RESTORE] = INITIAL;
408 	state_machine_[VALID][SMI_READ_ONLY] = RO_VALID;
409 	// State::INVALID
410 	state_machine_[INVALID][SMI_INVALID] = INVALID;
411 	state_machine_[INVALID][SMI_READ_WRITE] = INVALID;
412 	state_machine_[INVALID][SMI_VALID] = VALID;
413 	state_machine_[INVALID][SMI_OKAY] = INITIAL;
414 	state_machine_[INVALID][SMI_APPLY] = INITIAL;
415 	state_machine_[INVALID][SMI_RESTORE] = INITIAL;
416 	state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID;
417 	// State::RO_INITIAL
418 	state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL;
419 	state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID;
420 	state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID;
421 	state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL;
422 	// State::RO_VALID
423 	state_machine_[RO_VALID][SMI_VALID] = RO_VALID;
424 	state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID;
425 	state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID;
426 	state_machine_[RO_VALID][SMI_READ_WRITE] = VALID;
427 	state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL;
428 	// State::RO_INVALID
429 	state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID;
430 	state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID;
431 	state_machine_[RO_INVALID][SMI_VALID] = RO_VALID;
432 	state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID;
433 	state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL;
434 }
435 
436 
initOkApplyCancelReadOnly()437 void ButtonPolicy::Private::initOkApplyCancelReadOnly()
438 {
439 	outputs_ = StateOutputs(RO_APPLIED + 1, ButtonPolicy::ALL_BUTTONS);
440 	state_machine_ = StateMachine(RO_APPLIED + 1,
441 			 StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS));
442 
443 	// Build the state output map
444 	outputs_[INITIAL] = CLOSE;
445 	outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL;
446 	outputs_[INVALID] = RESTORE | CANCEL;
447 	outputs_[APPLIED] = OKAY | APPLY | CLOSE;
448 	outputs_[RO_INITIAL] = CLOSE;
449 	outputs_[RO_VALID] = RESTORE | CANCEL;
450 	outputs_[RO_INVALID] = RESTORE | CANCEL;
451 	outputs_[RO_APPLIED] = CLOSE;
452 
453 	// Build the state machine one state at a time
454 	// NOTE:  Since CANCEL and HIDE always go to INITIAL they are
455 	//        left out of the state machine and handled explicitly
456 	//        in input()
457 	//
458 	// State::INITIAL
459 	state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL;
460 	state_machine_[INITIAL][SMI_VALID] = VALID;
461 	state_machine_[INITIAL][SMI_INVALID] = INVALID;
462 	state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL;
463 	// State::VALID
464 	state_machine_[VALID][SMI_VALID] = VALID;
465 	state_machine_[VALID][SMI_READ_WRITE] = VALID;
466 	state_machine_[VALID][SMI_INVALID] = INVALID;
467 	state_machine_[VALID][SMI_OKAY] = INITIAL;
468 	state_machine_[VALID][SMI_RESTORE] = INITIAL;
469 	state_machine_[VALID][SMI_APPLY] = APPLIED;
470 	state_machine_[VALID][SMI_READ_ONLY] = RO_VALID;
471 	// State::INVALID
472 	state_machine_[INVALID][SMI_INVALID] = INVALID;
473 	state_machine_[INVALID][SMI_READ_WRITE] = INVALID;
474 	state_machine_[INVALID][SMI_VALID] = VALID;
475 	state_machine_[INVALID][SMI_RESTORE] = INITIAL;
476 	state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID;
477 	// State::APPLIED
478 	state_machine_[APPLIED][SMI_APPLY] = APPLIED;
479 	state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED;
480 	state_machine_[APPLIED][SMI_VALID] = VALID;
481 	state_machine_[APPLIED][SMI_INVALID] = INVALID;
482 	state_machine_[APPLIED][SMI_OKAY] = INITIAL;
483 	state_machine_[APPLIED][SMI_READ_ONLY] = RO_APPLIED;
484 	// State::RO_INITIAL
485 	state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL;
486 	state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID;
487 	state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID;
488 	state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL;
489 	// State::RO_VALID
490 	state_machine_[RO_VALID][SMI_VALID] = RO_VALID;
491 	state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID;
492 	state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID;
493 	state_machine_[RO_VALID][SMI_READ_WRITE] = VALID;
494 	state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL;
495 	// State::RO_INVALID
496 	state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID;
497 	state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID;
498 	state_machine_[RO_INVALID][SMI_VALID] = RO_VALID;
499 	state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID;
500 	state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL;
501 	// State::RO_APPLIED
502 	state_machine_[RO_APPLIED][SMI_READ_ONLY] = RO_APPLIED;
503 	state_machine_[RO_APPLIED][SMI_INVALID] = RO_INVALID;
504 	state_machine_[RO_APPLIED][SMI_VALID] = RO_VALID;
505 	state_machine_[RO_APPLIED][SMI_READ_WRITE] = APPLIED;
506 }
507 
508 
initOkApplyCancel()509 void ButtonPolicy::Private::initOkApplyCancel()
510 {
511 	outputs_ = StateOutputs(APPLIED + 1, ButtonPolicy::ALL_BUTTONS);
512 	state_machine_ = StateMachine(APPLIED + 1,
513 			 StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS));
514 
515 	// Build the state output map
516 	outputs_[INITIAL] = CLOSE;
517 	outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL;
518 	outputs_[INVALID] = RESTORE | CANCEL;
519 	outputs_[APPLIED] = OKAY | APPLY | CLOSE;
520 
521 	// Build the state machine one state at a time
522 	// NOTE:  Since CANCEL and HIDE always go to INITIAL they are
523 	//        left out of the state machine and handled explicitly
524 	//        in input()
525 	//
526 	// State::INITIAL
527 	state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL;
528 	state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL;
529 	state_machine_[INITIAL][SMI_VALID] = VALID;
530 	state_machine_[INITIAL][SMI_INVALID] = INVALID;
531 	// State::VALID
532 	state_machine_[VALID][SMI_VALID] = VALID;
533 	state_machine_[VALID][SMI_READ_ONLY] = VALID;
534 	state_machine_[VALID][SMI_READ_WRITE] = VALID;
535 	state_machine_[VALID][SMI_INVALID] = INVALID;
536 	state_machine_[VALID][SMI_OKAY] = INITIAL;
537 	state_machine_[VALID][SMI_RESTORE] = INITIAL;
538 	state_machine_[VALID][SMI_APPLY] = APPLIED;
539 	// State::INVALID
540 	state_machine_[INVALID][SMI_INVALID] = INVALID;
541 	state_machine_[INVALID][SMI_READ_ONLY] = INVALID;
542 	state_machine_[INVALID][SMI_READ_WRITE] = INVALID;
543 	state_machine_[INVALID][SMI_VALID] = VALID;
544 	state_machine_[INVALID][SMI_RESTORE] = INITIAL;
545 	// State::APPLIED
546 	state_machine_[APPLIED][SMI_APPLY] = APPLIED;
547 	state_machine_[APPLIED][SMI_READ_ONLY] = APPLIED;
548 	state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED;
549 	state_machine_[APPLIED][SMI_VALID] = VALID;
550 	state_machine_[APPLIED][SMI_INVALID] = INVALID;
551 	state_machine_[APPLIED][SMI_OKAY] = INITIAL;
552 }
553 
554 
initOkApplyCancelAutoReadOnly()555 void ButtonPolicy::Private::initOkApplyCancelAutoReadOnly()
556 {
557 	outputs_ = StateOutputs(RO_AUTOAPPLY + 1, ButtonPolicy::ALL_BUTTONS);
558 	state_machine_ = StateMachine(RO_AUTOAPPLY + 1,
559 			 StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS));
560 
561 	// Build the state output map
562 	outputs_[INITIAL] = CLOSE | AUTOAPPLY;
563 	outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL | AUTOAPPLY;
564 	outputs_[INVALID] = RESTORE | CANCEL | AUTOAPPLY;
565 	outputs_[APPLIED] = OKAY | CLOSE | AUTOAPPLY;
566 	outputs_[AUTOAPPLY_INITIAL] = CLOSE | AUTOAPPLY;
567 	outputs_[AUTOAPPLY_CHANGED] = CLOSE | RESTORE | AUTOAPPLY | OKAY;
568 	outputs_[RO_INITIAL] = CLOSE;
569 	outputs_[RO_VALID] = RESTORE | CANCEL;
570 	outputs_[RO_INVALID] = RESTORE | CANCEL;
571 	outputs_[RO_APPLIED] = CLOSE;
572 	outputs_[RO_AUTOAPPLY] = CLOSE;
573 
574 	// Build the state machine one state at a time
575 	// NOTE:  Since CANCEL and HIDE always go to INITIAL they are
576 	//        left out of the state machine and handled explicitly
577 	//        in input()
578 	//
579 	// State::INITIAL
580 	state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL;
581 	state_machine_[INITIAL][SMI_VALID] = VALID;
582 	state_machine_[INITIAL][SMI_INVALID] = INVALID;
583 	state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL;
584 	state_machine_[INITIAL][SMI_AUTOAPPLY] = AUTOAPPLY_INITIAL;
585 	// State::VALID
586 	state_machine_[VALID][SMI_VALID] = VALID;
587 	state_machine_[VALID][SMI_READ_WRITE] = VALID;
588 	state_machine_[VALID][SMI_INVALID] = INVALID;
589 	state_machine_[VALID][SMI_OKAY] = INITIAL;
590 	state_machine_[VALID][SMI_RESTORE] = INITIAL;
591 	state_machine_[VALID][SMI_APPLY] = APPLIED;
592 	state_machine_[VALID][SMI_READ_ONLY] = RO_VALID;
593 	state_machine_[VALID][SMI_AUTOAPPLY] = AUTOAPPLY_INITIAL;
594 	// State::INVALID
595 	state_machine_[INVALID][SMI_INVALID] = INVALID;
596 	state_machine_[INVALID][SMI_READ_WRITE] = INVALID;
597 	state_machine_[INVALID][SMI_VALID] = VALID;
598 	state_machine_[INVALID][SMI_RESTORE] = INITIAL;
599 	state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID;
600 	state_machine_[INVALID][SMI_AUTOAPPLY] = AUTOAPPLY_CHANGED;
601 	// State::APPLIED
602 	state_machine_[APPLIED][SMI_APPLY] = APPLIED;
603 	state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED;
604 	state_machine_[APPLIED][SMI_VALID] = VALID;
605 	state_machine_[APPLIED][SMI_INVALID] = INVALID;
606 	state_machine_[APPLIED][SMI_OKAY] = INITIAL;
607 	state_machine_[APPLIED][SMI_READ_ONLY] = RO_APPLIED;
608 	state_machine_[APPLIED][SMI_AUTOAPPLY] = AUTOAPPLY_INITIAL;
609 	// State::AUTOAPPLY_INITIAL
610 	state_machine_[AUTOAPPLY_INITIAL][SMI_AUTOAPPLY] = APPLIED;
611 	state_machine_[AUTOAPPLY_INITIAL][SMI_READ_ONLY] = RO_AUTOAPPLY;
612 	state_machine_[AUTOAPPLY_INITIAL][SMI_VALID] = AUTOAPPLY_CHANGED;
613 	state_machine_[AUTOAPPLY_INITIAL][SMI_INVALID] = AUTOAPPLY_CHANGED;
614 	state_machine_[AUTOAPPLY_INITIAL][SMI_READ_WRITE] = AUTOAPPLY_INITIAL;
615 	// State::AUTOAPPLY_CHANGED
616 	state_machine_[AUTOAPPLY_CHANGED][SMI_AUTOAPPLY] = APPLIED;
617 	state_machine_[AUTOAPPLY_CHANGED][SMI_READ_ONLY] = RO_AUTOAPPLY;
618 	state_machine_[AUTOAPPLY_CHANGED][SMI_RESTORE] = AUTOAPPLY_INITIAL;
619 	state_machine_[AUTOAPPLY_CHANGED][SMI_VALID] = AUTOAPPLY_CHANGED;
620 	state_machine_[AUTOAPPLY_CHANGED][SMI_INVALID] = AUTOAPPLY_CHANGED;
621 	state_machine_[AUTOAPPLY_CHANGED][SMI_READ_WRITE] = AUTOAPPLY_CHANGED;
622 	state_machine_[AUTOAPPLY_CHANGED][SMI_APPLY] = AUTOAPPLY_INITIAL;
623 	// State::RO_INITIAL
624 	state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL;
625 	state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID;
626 	state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID;
627 	state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL;
628 	state_machine_[RO_INITIAL][SMI_AUTOAPPLY] = RO_AUTOAPPLY;
629 	// State::RO_VALID
630 	state_machine_[RO_VALID][SMI_VALID] = RO_VALID;
631 	state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID;
632 	state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID;
633 	state_machine_[RO_VALID][SMI_READ_WRITE] = VALID;
634 	state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL;
635 	state_machine_[RO_VALID][SMI_AUTOAPPLY] = RO_AUTOAPPLY;
636 	// State::RO_INVALID
637 	state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID;
638 	state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID;
639 	state_machine_[RO_INVALID][SMI_VALID] = RO_VALID;
640 	state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID;
641 	state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL;
642 	state_machine_[RO_INVALID][SMI_AUTOAPPLY] = RO_AUTOAPPLY;
643 	// State::RO_APPLIED
644 	state_machine_[RO_APPLIED][SMI_READ_ONLY] = RO_APPLIED;
645 	state_machine_[RO_APPLIED][SMI_INVALID] = RO_INVALID;
646 	state_machine_[RO_APPLIED][SMI_VALID] = RO_VALID;
647 	state_machine_[RO_APPLIED][SMI_READ_WRITE] = APPLIED;
648 	state_machine_[RO_APPLIED][SMI_AUTOAPPLY] = RO_AUTOAPPLY;
649 	// State::RO_AUTOAPPLY
650 	state_machine_[RO_AUTOAPPLY][SMI_READ_WRITE] = AUTOAPPLY_INITIAL;
651 }
652 
653 
initNoRepeatedApply()654 void ButtonPolicy::Private::initNoRepeatedApply()
655 {
656 	outputs_ = StateOutputs(INVALID + 1, ButtonPolicy::ALL_BUTTONS);
657 	state_machine_ = StateMachine(INVALID + 1,
658 			 StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS));
659 
660 	// Build the state output map
661 	outputs_[INITIAL] = CLOSE;
662 	outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL;
663 	outputs_[INVALID] = RESTORE | CANCEL;
664 
665 	// Build the state machine one state at a time
666 	// NOTE:  Since CANCEL and HIDE always go to INITIAL they are
667 	//        left out of the state machine and handled explicitly
668 	//        in input()
669 	//
670 	// State::INITIAL
671 	state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL;
672 	state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL;
673 	state_machine_[INITIAL][SMI_VALID] = VALID;
674 	state_machine_[INITIAL][SMI_INVALID] = INVALID;
675 	// State::VALID
676 	state_machine_[VALID][SMI_VALID] = VALID;
677 	state_machine_[VALID][SMI_READ_ONLY] = VALID;
678 	state_machine_[VALID][SMI_READ_WRITE] = VALID;
679 	state_machine_[VALID][SMI_INVALID] = INVALID;
680 	state_machine_[VALID][SMI_OKAY] = INITIAL;
681 	state_machine_[VALID][SMI_APPLY] = INITIAL;
682 	state_machine_[VALID][SMI_RESTORE] = INITIAL;
683 	// State::INVALID
684 	state_machine_[INVALID][SMI_INVALID] = INVALID;
685 	state_machine_[INVALID][SMI_READ_ONLY] = INVALID;
686 	state_machine_[INVALID][SMI_READ_WRITE] = INVALID;
687 	state_machine_[INVALID][SMI_VALID] = VALID;
688 	state_machine_[INVALID][SMI_RESTORE] = INITIAL;
689 }
690 
691 
692 /////////////////////////////////////////////////////////////////////////
693 //
694 // ButtonPolicy
695 //
696 /////////////////////////////////////////////////////////////////////////
697 
ButtonPolicy(Policy policy)698 ButtonPolicy::ButtonPolicy(Policy policy)
699 	: d(new Private(policy))
700 {}
701 
702 
~ButtonPolicy()703 ButtonPolicy::~ButtonPolicy()
704 {
705 	delete d;
706 }
707 
708 
setPolicy(Policy policy)709 void ButtonPolicy::setPolicy(Policy policy)
710 {
711 	*d = Private(policy);
712 }
713 
714 
input(SMInput input)715 void ButtonPolicy::input(SMInput input)
716 {
717 	switch (d->policy_) {
718 		case PreferencesPolicy:
719 			// The APPLIED state is persistent. Next time the dialog is opened,
720 			// the user will be able to press 'Save'.
721 			if (SMI_CANCEL == input || SMI_HIDE == input) {
722 				if (d->state_ != APPLIED)
723 					d->state_ = INITIAL;
724 			} else {
725 				d->nextState(input);
726 			}
727 			break;
728 		case IgnorantPolicy:
729 			break;
730 		default:
731 			// CANCEL and HIDE always take us to INITIAL for all cases
732 			if (SMI_CANCEL == input || SMI_HIDE == input) {
733 				if (d->state_ == AUTOAPPLY_INITIAL
734 					  || d->state_ == AUTOAPPLY_CHANGED)
735 					d->state_ = AUTOAPPLY_INITIAL;
736 				else
737 					d->state_ = INITIAL;
738 			} else
739 				d->nextState(input);
740 			break;
741 	}
742 }
743 
744 
buttonStatus(Button button) const745 bool ButtonPolicy::buttonStatus(Button button) const
746 {
747 	return d->policy_ == IgnorantPolicy || (button & d->outputs_[d->state_]);
748 }
749 
750 
isReadOnly() const751 bool ButtonPolicy::isReadOnly() const
752 {
753 	switch (d->policy_) {
754 		case NoRepeatedApplyReadOnlyPolicy:
755 		case OkCancelReadOnlyPolicy:
756 		case OkApplyCancelReadOnlyPolicy:
757 			return RO_INITIAL == d->state_
758 				|| RO_VALID == d->state_
759 				|| RO_INVALID == d->state_
760 				|| RO_APPLIED == d->state_;
761 		default:
762 			return false;
763 	}
764 }
765 
766 
767 
768 } // namespace frontend
769 } // namespace lyx
770