From: André Pönitz Date: Sun, 7 Oct 2007 21:14:24 +0000 (+0000) Subject: move stuff around. probably not the final destination... X-Git-Tag: 1.6.10~7943 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=8500da8691d94748523a7c66ae349853ed7fc38c;p=lyx.git move stuff around. probably not the final destination... git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@20829 a592a061-630c-0410-9148-cb99ea01b6c8 --- diff --git a/src/frontends/ButtonPolicy.cpp b/src/frontends/ButtonPolicy.cpp new file mode 100644 index 0000000000..69c15f9772 --- /dev/null +++ b/src/frontends/ButtonPolicy.cpp @@ -0,0 +1,569 @@ +/** + * \file ButtonPolicy.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Allan Rae + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "ButtonPolicy.h" +#include "debug.h" + + +namespace lyx { +namespace frontend { + + +ButtonPolicy::ButtonPolicy(Policy policy) +{ + policy_ = policy; + state_ = INITIAL; + + switch (policy_) { + case OkCancelPolicy: + initOkCancel(); + break; + case OkCancelReadOnlyPolicy: + initOkCancelReadOnly(); + break; + case OkApplyCancelPolicy: + initOkApplyCancel(); + break; + case OkApplyCancelReadOnlyPolicy: + initOkApplyCancelReadOnly(); + break; + case NoRepeatedApplyPolicy: + initNoRepeatedApply(); + break; + case NoRepeatedApplyReadOnlyPolicy: + initNoRepeatedApplyReadOnly(); + break; + case PreferencesPolicy: + initPreferences(); + break; + case IgnorantPolicy: + break; + } +} + + +char const * functionName(ButtonPolicy::Policy policy) +{ + switch (policy) { + case ButtonPolicy::PreferencesPolicy: + return "PreferencesPolicy"; + case ButtonPolicy::OkCancelPolicy: + return "OkCancelPolicy"; + case ButtonPolicy::OkCancelReadOnlyPolicy: + return "OkCancelReadOnlyPolicy"; + case ButtonPolicy::OkApplyCancelPolicy: + return "OkApplyCancelPolicy"; + case ButtonPolicy::OkApplyCancelReadOnlyPolicy: + return "OkApplyCancelReadOnlyPolicy"; + case ButtonPolicy::NoRepeatedApplyPolicy: + return "NoRepeatedApplyPolicy"; + case ButtonPolicy::NoRepeatedApplyReadOnlyPolicy: + return "NoRepeatedApplyReadOnlyPolicy"; + case ButtonPolicy::IgnorantPolicy: + return "IgnorantPolicy"; + default: + return "Unknown policy"; + } +} + + +void ButtonPolicy::input(SMInput input) +{ + switch (policy_) { + case PreferencesPolicy: + // The APPLIED state is persistent. Next time the dialog is opened, + // the user will be able to press 'Save'. + if (SMI_CANCEL == input || SMI_HIDE == input) { + if (state_ != APPLIED) + state_ = INITIAL; + } else { + nextState(input); + } + break; + case IgnorantPolicy: + break; + default: + // CANCEL and HIDE always take us to INITIAL for all cases + if (SMI_CANCEL == input || SMI_HIDE == input) + state_ = INITIAL; + else + nextState(input); + break; + } +} + + +bool ButtonPolicy::buttonStatus(Button button) const +{ + return policy_ == IgnorantPolicy ? true : button & outputs_[state_]; +} + + +bool ButtonPolicy::isReadOnly() const +{ + switch(policy_) { + case NoRepeatedApplyReadOnlyPolicy: + case OkCancelReadOnlyPolicy: + case OkApplyCancelReadOnlyPolicy: + return RO_INITIAL == state_ + || RO_VALID == state_ + || RO_INVALID == state_ + || RO_APPLIED == state_; + default: + return false; + } +} + + +static char const * printState(ButtonPolicy::State const & state) +{ + switch (state) { + case ButtonPolicy::INITIAL: + return "INITIAL"; + case ButtonPolicy::VALID: + return "VALID"; + case ButtonPolicy::INVALID: + return "INVALID"; + case ButtonPolicy::APPLIED: + return "APPLIED"; + case ButtonPolicy::RO_INITIAL: + return "RO_INITIAL"; + case ButtonPolicy::RO_VALID: + return "RO_VALID"; + case ButtonPolicy::RO_INVALID: + return "RO_INVALID"; + case ButtonPolicy::RO_APPLIED: + return "RO_APPLIED"; + case ButtonPolicy::BOGUS: + return "BOGUS"; + default: + return ""; + } +} + + +static char const * printInput(ButtonPolicy::SMInput const & input) +{ + switch (input) { + case ButtonPolicy::SMI_VALID: + return "SMI_VALID"; + case ButtonPolicy::SMI_INVALID: + return "SMI_INVALID"; + case ButtonPolicy::SMI_OKAY: + return "SMI_OKAY"; + case ButtonPolicy::SMI_APPLY: + return "SMI_APPLY"; + case ButtonPolicy::SMI_CANCEL: + return "SMI_CANCEL"; + case ButtonPolicy::SMI_RESTORE: + return "SMI_RESTORE"; + case ButtonPolicy::SMI_HIDE: + return "SMI_HIDE"; + case ButtonPolicy::SMI_READ_ONLY: + return "SMI_READ_ONLY"; + case ButtonPolicy::SMI_READ_WRITE: + return "SMI_READ_WRITE"; + case ButtonPolicy::SMI_NOOP: + return "SMI_NOOP"; + case ButtonPolicy::SMI_TOTAL: + return "SMI_TOTAL"; + default: + return ""; + } +} + + +void ButtonPolicy::nextState(SMInput input) +{ + if (SMI_NOOP == input) + return; + + State tmp = state_machine_[state_][input]; + + LYXERR(Debug::GUI) << "Transition from state " + << printState(state_) << " to state " + << printState(tmp) << " after input " + << printInput(input) << std::endl; + + if (tmp != BOGUS) { + state_ = tmp; + } else { + lyxerr << functionName(policy_) + << ": No transition for input " + << printInput(input) + << " from state " + << printState(state_) + << std::endl; + } +} + + +void ButtonPolicy::initPreferences() +{ + outputs_ = StateOutputs(APPLIED + 1, ButtonPolicy::ALL_BUTTONS); + state_machine_ = StateMachine(APPLIED + 1, + StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); + + // Build the state output map + outputs_[INITIAL] = CLOSE; + outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; + outputs_[INVALID] = RESTORE | CANCEL; + outputs_[APPLIED] = OKAY | CLOSE; + + // Build the state machine one state at a time + // NOTE: Since CANCEL and HIDE always go to INITIAL they are + // left out of the state machine and handled explicitly + // in input(). This won't necessarily be true for all + // policies though so I'll leave those two as distinct + // inputs rather than merge them. For example, a dialog + // that doesn't update it's input fields when reshown + // after being hidden needs a policy where CANCEL and + // HIDE are treated differently. + // + // State::INITIAL + state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL; + state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; + state_machine_[INITIAL][SMI_VALID] = VALID; + state_machine_[INITIAL][SMI_INVALID] = INVALID; + // State::VALID + state_machine_[VALID][SMI_VALID] = VALID; + state_machine_[VALID][SMI_READ_ONLY] = VALID; + state_machine_[VALID][SMI_READ_WRITE] = VALID; + state_machine_[VALID][SMI_INVALID] = INVALID; + state_machine_[VALID][SMI_APPLY] = APPLIED; + state_machine_[VALID][SMI_OKAY] = INITIAL; + state_machine_[VALID][SMI_RESTORE] = INITIAL; + // State::INVALID + state_machine_[INVALID][SMI_VALID] = VALID; + state_machine_[INVALID][SMI_INVALID] = INVALID; + state_machine_[INVALID][SMI_READ_ONLY] = INVALID; + state_machine_[INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[INVALID][SMI_RESTORE] = INITIAL; + // State::APPLIED + state_machine_[APPLIED][SMI_VALID] = VALID; + state_machine_[APPLIED][SMI_INVALID] = INVALID; + state_machine_[APPLIED][SMI_OKAY] = INITIAL; + state_machine_[APPLIED][SMI_READ_ONLY] = APPLIED; + state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED; +} + + +void ButtonPolicy::initOkCancel() +{ + outputs_ = StateOutputs(INVALID + 1, ButtonPolicy::ALL_BUTTONS); + state_machine_ = StateMachine(INVALID + 1, + StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); + + // Build the state output map + outputs_[INITIAL] = CLOSE; + outputs_[VALID] = RESTORE | OKAY | CANCEL; + outputs_[INVALID] = RESTORE | CANCEL; + + // Build the state machine one state at a time + // NOTE: Since CANCEL and HIDE always go to INITIAL they are + // left out of the state machine and handled explicitly + // in input() + // + // State::INITIAL + state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL; + state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; + state_machine_[INITIAL][SMI_VALID] = VALID; + state_machine_[INITIAL][SMI_INVALID] = INVALID; + // State::VALID + state_machine_[VALID][SMI_VALID] = VALID; + state_machine_[VALID][SMI_READ_ONLY] = VALID; + state_machine_[VALID][SMI_READ_WRITE] = VALID; + state_machine_[VALID][SMI_INVALID] = INVALID; + state_machine_[VALID][SMI_OKAY] = INITIAL; + state_machine_[VALID][SMI_RESTORE] = INITIAL; + // State::INVALID + state_machine_[INVALID][SMI_VALID] = VALID; + state_machine_[INVALID][SMI_INVALID] = INVALID; + state_machine_[INVALID][SMI_READ_ONLY] = INVALID; + state_machine_[INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[INVALID][SMI_RESTORE] = INITIAL; +} + + +void ButtonPolicy::initOkCancelReadOnly() +{ + outputs_ = StateOutputs(RO_INVALID + 1, ButtonPolicy::ALL_BUTTONS); + state_machine_ = StateMachine(RO_INVALID + 1, + StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); + + // Build the state output map + outputs_[INITIAL] = CLOSE; + outputs_[VALID] = RESTORE | OKAY | CANCEL; + outputs_[INVALID] = RESTORE | CANCEL; + outputs_[RO_INITIAL] = CLOSE; + outputs_[RO_VALID] = RESTORE | CANCEL; + outputs_[RO_INVALID] = RESTORE | CANCEL; + + // Build the state machine one state at a time + // NOTE: Since CANCEL and HIDE always go to INITIAL they are + // left out of the state machine and handled explicitly + // in input() + // + // State::INITIAL + state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; + state_machine_[INITIAL][SMI_VALID] = VALID; + state_machine_[INITIAL][SMI_INVALID] = INVALID; + state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL; + // State::VALID + state_machine_[VALID][SMI_VALID] = VALID; + state_machine_[VALID][SMI_READ_WRITE] = VALID; + state_machine_[VALID][SMI_INVALID] = INVALID; + state_machine_[VALID][SMI_OKAY] = INITIAL; + state_machine_[VALID][SMI_RESTORE] = INITIAL; + state_machine_[VALID][SMI_READ_ONLY] = RO_VALID; + // State::INVALID + state_machine_[INVALID][SMI_INVALID] = INVALID; + state_machine_[INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[INVALID][SMI_VALID] = VALID; + state_machine_[INVALID][SMI_RESTORE] = INITIAL; + state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID; + // State::RO_INITIAL + state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL; + state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID; + state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID; + state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL; + // State::RO_VALID + state_machine_[RO_VALID][SMI_VALID] = RO_VALID; + state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID; + state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID; + state_machine_[RO_VALID][SMI_READ_WRITE] = VALID; + state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL; + // State::RO_INVALID + state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID; + state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID; + state_machine_[RO_INVALID][SMI_VALID] = RO_VALID; + state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL; +} + + +void ButtonPolicy::initNoRepeatedApplyReadOnly() +{ + outputs_ = StateOutputs(RO_INVALID + 1, ButtonPolicy::ALL_BUTTONS); + state_machine_ = StateMachine(RO_INVALID + 1, + StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); + + // Build the state output map + outputs_[INITIAL] = CLOSE; + outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; + outputs_[INVALID] = RESTORE | CANCEL; + outputs_[RO_INITIAL] = CLOSE; + outputs_[RO_VALID] = RESTORE | CANCEL; + outputs_[RO_INVALID] = RESTORE | CANCEL; + + // Build the state machine one state at a time + // NOTE: Since CANCEL and HIDE always go to INITIAL they are + // left out of the state machine and handled explicitly + // in input() + // + // State::INITIAL + state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; + state_machine_[INITIAL][SMI_VALID] = VALID; + state_machine_[INITIAL][SMI_INVALID] = INVALID; + state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL; + // State::VALID + state_machine_[VALID][SMI_VALID] = VALID; + state_machine_[VALID][SMI_READ_WRITE] = VALID; + state_machine_[VALID][SMI_INVALID] = INVALID; + state_machine_[VALID][SMI_OKAY] = INITIAL; + state_machine_[VALID][SMI_APPLY] = INITIAL; + state_machine_[VALID][SMI_RESTORE] = INITIAL; + state_machine_[VALID][SMI_READ_ONLY] = RO_VALID; + // State::INVALID + state_machine_[INVALID][SMI_INVALID] = INVALID; + state_machine_[INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[INVALID][SMI_VALID] = VALID; + state_machine_[INVALID][SMI_RESTORE] = INITIAL; + state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID; + // State::RO_INITIAL + state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL; + state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID; + state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID; + state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL; + // State::RO_VALID + state_machine_[RO_VALID][SMI_VALID] = RO_VALID; + state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID; + state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID; + state_machine_[RO_VALID][SMI_READ_WRITE] = VALID; + state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL; + // State::RO_INVALID + state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID; + state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID; + state_machine_[RO_INVALID][SMI_VALID] = RO_VALID; + state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL; +} + + +void ButtonPolicy::initOkApplyCancelReadOnly() +{ + outputs_ = StateOutputs(RO_APPLIED + 1, ButtonPolicy::ALL_BUTTONS); + state_machine_ = StateMachine(RO_APPLIED + 1, + StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); + + // Build the state output map + outputs_[INITIAL] = CLOSE; + outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; + outputs_[INVALID] = RESTORE | CANCEL; + outputs_[APPLIED] = OKAY | APPLY | CLOSE; + outputs_[RO_INITIAL] = CLOSE; + outputs_[RO_VALID] = RESTORE | CANCEL; + outputs_[RO_INVALID] = RESTORE | CANCEL; + outputs_[RO_APPLIED] = CLOSE; + + // Build the state machine one state at a time + // NOTE: Since CANCEL and HIDE always go to INITIAL they are + // left out of the state machine and handled explicitly + // in input() + // + // State::INITIAL + state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; + state_machine_[INITIAL][SMI_VALID] = VALID; + state_machine_[INITIAL][SMI_INVALID] = INVALID; + state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL; + // State::VALID + state_machine_[VALID][SMI_VALID] = VALID; + state_machine_[VALID][SMI_READ_WRITE] = VALID; + state_machine_[VALID][SMI_INVALID] = INVALID; + state_machine_[VALID][SMI_OKAY] = INITIAL; + state_machine_[VALID][SMI_RESTORE] = INITIAL; + state_machine_[VALID][SMI_APPLY] = APPLIED; + state_machine_[VALID][SMI_READ_ONLY] = RO_VALID; + // State::INVALID + state_machine_[INVALID][SMI_INVALID] = INVALID; + state_machine_[INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[INVALID][SMI_VALID] = VALID; + state_machine_[INVALID][SMI_RESTORE] = INITIAL; + state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID; + // State::APPLIED + state_machine_[APPLIED][SMI_APPLY] = APPLIED; + state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED; + state_machine_[APPLIED][SMI_VALID] = VALID; + state_machine_[APPLIED][SMI_INVALID] = INVALID; + state_machine_[APPLIED][SMI_OKAY] = INITIAL; + state_machine_[APPLIED][SMI_READ_ONLY] = RO_APPLIED; + // State::RO_INITIAL + state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL; + state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID; + state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID; + state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL; + // State::RO_VALID + state_machine_[RO_VALID][SMI_VALID] = RO_VALID; + state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID; + state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID; + state_machine_[RO_VALID][SMI_READ_WRITE] = VALID; + state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL; + // State::RO_INVALID + state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID; + state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID; + state_machine_[RO_INVALID][SMI_VALID] = RO_VALID; + state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL; + // State::RO_APPLIED + state_machine_[RO_APPLIED][SMI_READ_ONLY] = RO_APPLIED; + state_machine_[RO_APPLIED][SMI_INVALID] = RO_INVALID; + state_machine_[RO_APPLIED][SMI_VALID] = RO_VALID; + state_machine_[RO_APPLIED][SMI_READ_WRITE] = APPLIED; +} + + +void ButtonPolicy::initOkApplyCancel() +{ + outputs_ = StateOutputs(APPLIED + 1, ButtonPolicy::ALL_BUTTONS); + state_machine_ = StateMachine(APPLIED + 1, + StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); + + // Build the state output map + outputs_[INITIAL] = CLOSE; + outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; + outputs_[INVALID] = RESTORE | CANCEL; + outputs_[APPLIED] = OKAY | APPLY | CLOSE; + + // Build the state machine one state at a time + // NOTE: Since CANCEL and HIDE always go to INITIAL they are + // left out of the state machine and handled explicitly + // in input() + // + // State::INITIAL + state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL; + state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; + state_machine_[INITIAL][SMI_VALID] = VALID; + state_machine_[INITIAL][SMI_INVALID] = INVALID; + // State::VALID + state_machine_[VALID][SMI_VALID] = VALID; + state_machine_[VALID][SMI_READ_ONLY] = VALID; + state_machine_[VALID][SMI_READ_WRITE] = VALID; + state_machine_[VALID][SMI_INVALID] = INVALID; + state_machine_[VALID][SMI_OKAY] = INITIAL; + state_machine_[VALID][SMI_RESTORE] = INITIAL; + state_machine_[VALID][SMI_APPLY] = APPLIED; + // State::INVALID + state_machine_[INVALID][SMI_INVALID] = INVALID; + state_machine_[INVALID][SMI_READ_ONLY] = INVALID; + state_machine_[INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[INVALID][SMI_VALID] = VALID; + state_machine_[INVALID][SMI_RESTORE] = INITIAL; + // State::APPLIED + state_machine_[APPLIED][SMI_APPLY] = APPLIED; + state_machine_[APPLIED][SMI_READ_ONLY] = APPLIED; + state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED; + state_machine_[APPLIED][SMI_VALID] = VALID; + state_machine_[APPLIED][SMI_INVALID] = INVALID; + state_machine_[APPLIED][SMI_OKAY] = INITIAL; +} + + +void ButtonPolicy::initNoRepeatedApply() +{ + outputs_ = StateOutputs(INVALID + 1, ButtonPolicy::ALL_BUTTONS); + state_machine_ = StateMachine(INVALID + 1, + StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); + + // Build the state output map + outputs_[INITIAL] = CLOSE; + outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; + outputs_[INVALID] = RESTORE | CANCEL; + + // Build the state machine one state at a time + // NOTE: Since CANCEL and HIDE always go to INITIAL they are + // left out of the state machine and handled explicitly + // in input() + // + // State::INITIAL + state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL; + state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; + state_machine_[INITIAL][SMI_VALID] = VALID; + state_machine_[INITIAL][SMI_INVALID] = INVALID; + // State::VALID + state_machine_[VALID][SMI_VALID] = VALID; + state_machine_[VALID][SMI_READ_ONLY] = VALID; + state_machine_[VALID][SMI_READ_WRITE] = VALID; + state_machine_[VALID][SMI_INVALID] = INVALID; + state_machine_[VALID][SMI_OKAY] = INITIAL; + state_machine_[VALID][SMI_APPLY] = INITIAL; + state_machine_[VALID][SMI_RESTORE] = INITIAL; + // State::INVALID + state_machine_[INVALID][SMI_INVALID] = INVALID; + state_machine_[INVALID][SMI_READ_ONLY] = INVALID; + state_machine_[INVALID][SMI_READ_WRITE] = INVALID; + state_machine_[INVALID][SMI_VALID] = VALID; + state_machine_[INVALID][SMI_RESTORE] = INITIAL; +} + + +} // namespace frontend +} // namespace lyx diff --git a/src/frontends/ButtonPolicy.h b/src/frontends/ButtonPolicy.h new file mode 100644 index 0000000000..beebc62c79 --- /dev/null +++ b/src/frontends/ButtonPolicy.h @@ -0,0 +1,300 @@ +// -*- C++ -*- +/** + * \file ButtonPolicy.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Allan Rae + * + * Full author contact details are available in file CREDITS. + * + * Provides a state machine implementation of the various button policies + * used by the dialogs. + */ + +#ifndef BUTTONPOLICY_H +#define BUTTONPOLICY_H + +#include +#include + +namespace lyx { +namespace frontend { + +/** A class for button policies. + A state machine implementation of the various button policies used by the + dialogs. Only the policy is implemented here. Separate ButtonController + classes are needed for each GUI implementation. + + Policy | ReadOnly | Apply Button | Repeated Apply + ======================================================================== + OkCancel | N | N | - + OkCancelReadOnly | Y | N | - + OkApplyCancel | N | Y | Y + OkApplyCancelReadOnly | Y | Y | Y + NoRepeatedApply | N | Y | N + NoRepeatedApplyReadOnly | Y | Y | N + Preferences | N | Y | No (Ok-Close) + Ignorant | N/A | N/A | N/A + ======================================================================== + + Policy + The name of the policy + ReadOnly + Does the policy treat read-only docs differently to read-write docs? + This usually means that when an SMI_READ_ONLY input arrives then + all the buttons are disabled except Cancel/Close. The state + machine tracks the inputs (valid/invalid) and has states for all + combinations. When an SMI_READ_WRITE input arrives the appropriate + machine state is entered (just as if the document had always been + read-write). + NOTE: If a dialog doesn't care about the read-only status of a document + (and uses an appropriate policy) it can never get into a read-only state + so isReadOnly() can only ever return false even though the document may + be read-only. + Repeated Apply + Simply means that it is alright to use the Apply button multiple times + without requiring a change of the dialog contents. If no repeating is + allowed the Ok+Apply buttons are deactivated. The Preferences dialog + has its own special version of repeated apply handling because its Ok + button is actually a Save button -- it is always reasonable to Save the + preferences if the dialog has changed since the last save. + + The IgnorantPolicy is a special case that allows anything. + */ + +class ButtonPolicy { +public: + + // The various poicies + enum Policy { + /** Ok and Cancel buttons for dialogs with read-only operation. + Note: This scheme supports the relabelling of Cancel to Close and + vice versa. + This is based on the value of the bool state of the Button::CANCEL. + true == Cancel, false == Close + */ + OkCancelPolicy, + + + /** Ok and Cancel buttons for dialogs where read-only operation is blocked. + The state machine design for this policy allows changes to occur within + the dialog while a file is read-only -- the okay button is disabled until + a read-write input is given. When the file is made read-write the dialog + will then be in the correct state (as if the file had always been + read-write). + Note: This scheme supports the relabelling of Cancel to Close + and vice versa. + This is based on the value of the bool state of the Button::CANCEL. + true == Cancel, false == Close + */ + OkCancelReadOnlyPolicy, + + /** Ok, Apply and Cancel buttons for dialogs where read-only operation + is blocked. + Repeated Apply are not allowed. Likewise, Ok cannot follow Apply without + some valid input. That is, the dialog contents must change between + each Apply or Apply and Ok. + The state machine design for this policy allows changes to occur within + the dialog while a file is read-only -- the Ok+Apply buttons are disabled + until a read-write input is given. When the file is made read-write the + dialog will then be in the correct state (as if the file had always been + read-write). + Note: This scheme supports the relabelling of Cancel to Close + and vice versa. + This is based on the value of the bool state of the Button::CANCEL. + true == Cancel, false == Close + */ + NoRepeatedApplyReadOnlyPolicy, + + /** Ok, Apply and Cancel buttons for dialogs where read-only + operation is blocked. + Repeated Apply is allowed. Likewise, Ok can follow Apply. + The state machine design for this policy allows changes to occur within + the dialog while a file is read-only -- the Ok+Apply buttons are disabled + until a read-write input is given. When the file is made read-write the + dialog will then be in the correct state (as if the file had always been + read-write). + Note: This scheme supports the relabelling of Cancel to Close + and vice versa. + This is based on the value of the bool state of the Button::CANCEL. + true == Cancel, false == Close + */ + OkApplyCancelReadOnlyPolicy, + + /** Ok, Apply and Cancel buttons for dialogs where repeated + * Apply is allowed. + Note: This scheme supports the relabelling of Cancel to Close + and vice versa. + This is based on the value of the bool state of the Button::CANCEL. + true == Cancel, false == Close + */ + OkApplyCancelPolicy, + + /** Ok, Apply and Cancel buttons for dialogs with no repeated Apply. + Note: This scheme supports the relabelling of Cancel to Close + and vice versa. + This is based on the value of the bool state of the Button::CANCEL. + true == Cancel, false == Close + */ + NoRepeatedApplyPolicy, + + /** Defines the policy used by the Preferences dialog. + Four buttons: Ok (Save), Apply, Cancel/Close, Restore. + Note: This scheme supports the relabelling of Cancel to Close + and vice versa. + This is based on the value of the bool state of the Button::CANCEL. + true == Cancel, false == Close + */ + PreferencesPolicy, + + /** Defines the policy used by dialogs that are forced to support a button + controller when they either don't have a use for one or are not ready to + use one. This may be useful when testing a new button policy but wishing + to minimise problems to users by supplying an anything-goes policy via a + preprocessor directive. + */ + IgnorantPolicy, + }; + + /// Constructor + explicit ButtonPolicy(Policy policy); + + /** The various possible state names. + Not all state-machines have this many states. However, we need + to define them all here so we can share the code. + */ + enum State { + /// + INITIAL = 0, + /// + VALID, + /// + INVALID, + /// + APPLIED, + /// + RO_INITIAL, + /// + RO_VALID, + /// + RO_INVALID, + /// + RO_APPLIED, + /// + BOGUS = 55 + }; + + /// The various button types. + enum Button { + /// + CLOSE = 0, // Not a real button, but effectively !CANCEL + /// + OKAY = 1, + /// + APPLY = 2, + /// + CANCEL = 4, + /// + RESTORE = 8 + }; + /// + static const Button ALL_BUTTONS = + Button(OKAY | APPLY | CANCEL | RESTORE); + + /** State machine inputs. + All the policies so far have both CANCEL and HIDE always going to + INITIAL. This won't necessarily be true for all [future] policies + though so I'll leave those two as distinct inputs rather than merge + them. For example, a dialog that doesn't update it's input fields + when reshown after being hidden needs a policy where CANCEL and + HIDE are treated differently. + */ + enum SMInput { + /// the dialog contents are now valid + SMI_VALID = 0, + /// the dialog contents are now invalid + SMI_INVALID, + /// an apply-and-hide action has happened + SMI_OKAY, + /// an apply action has happened + SMI_APPLY, + /// a cancel action has happened + SMI_CANCEL, + /// a restore action has happened + SMI_RESTORE, + /// the dialog has been hidden + SMI_HIDE, + /// the dialog contents are read-only + SMI_READ_ONLY, + /// the dialog contents can be modified + SMI_READ_WRITE, + /// the state of the dialog contents has not changed + SMI_NOOP, + /// for internal use + SMI_TOTAL + }; + + /// Trigger a transition with this input. + void input(SMInput); + /** Activation status of a button. + We assume that we haven't gotten into an undefined state. + This is reasonable since we can only reach states defined + in the state machine and they should all have been defined in + the outputs_ variable. Perhaps we can do something at compile + time to check that all the states have corresponding outputs. + */ + bool buttonStatus(Button) const; + /// Are we in a read-only state? + bool isReadOnly() const; + +private: + /// + Policy policy_; + + /// Transition map of the state machine. + typedef std::vector StateArray; + /// + typedef std::vector StateMachine; + /// The state outputs are the status of the buttons. + typedef std::vector StateOutputs; + + /// Current state. + State state_; + /// Which buttons are active for a given state. + StateOutputs outputs_; + /// + StateMachine state_machine_; + +private: + // Helpers + void nextState(SMInput input); + + void initOkCancel(); + void initOkCancelReadOnly(); + void initNoRepeatedApplyReadOnly(); + void initOkApplyCancelReadOnly(); + void initOkApplyCancel(); + void initNoRepeatedApply(); + void initPreferences(); +}; + + +inline +std::ostream & operator<<(std::ostream & os, ButtonPolicy::State st) +{ + return os << int(st); +} + + +inline +std::ostream & operator<<(std::ostream & os, ButtonPolicy::SMInput smi) +{ + return os << int(smi); +} + + +} // namespace frontend +} // namespace lyx + +#endif diff --git a/src/frontends/Dialog.cpp b/src/frontends/Dialog.cpp new file mode 100644 index 0000000000..88d2312ef4 --- /dev/null +++ b/src/frontends/Dialog.cpp @@ -0,0 +1,130 @@ +/** + * \file Dialog.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "Dialog.h" + +#include "FuncRequest.h" +#include "FuncStatus.h" +#include "LyXFunc.h" + +#include "frontends/LyXView.h" +#include "frontends/Dialogs.h" // FIXME + +#include "Buffer.h" + + +namespace lyx { +namespace frontend { + + +Dialog::~Dialog() +{} + + +Controller::Controller(Dialog & parent) + : parent_(parent), lyxview_(0) +{} + + +Controller::Controller(Dialog * parent) + : parent_(*parent), lyxview_(0) +{} + + +Controller::~Controller() +{} + + +bool Controller::canApply() const +{ + FuncRequest const fr(getLfun(), dialog().name()); + FuncStatus const fs(getStatus(fr)); + return fs.enabled(); +} + + +void Controller::dispatch(FuncRequest const & fr) const +{ + lyxview_->dispatch(fr); +} + + +void Controller::updateDialog(std::string const & name) const +{ + dispatch(FuncRequest(LFUN_DIALOG_UPDATE, name)); +} + + +void Controller::disconnect(std::string const & name) const +{ + lyxview_->getDialogs().disconnect(name); +} + + +bool Controller::isBufferAvailable() const +{ + return lyxview_->buffer() != 0; +} + + +bool Controller::isBufferReadonly() const +{ + if (!lyxview_->buffer()) + return true; + return lyxview_->buffer()->isReadonly(); +} + + +std::string const Controller::bufferFilepath() const +{ + return buffer().filePath(); +} + + +KernelDocType Controller::docType() const +{ + if (buffer().isLatex()) + return LATEX; + if (buffer().isLiterate()) + return LITERATE; + + return DOCBOOK; +} + + +BufferView * Controller::bufferview() +{ + return lyxview_->view(); +} + + +BufferView const * Controller::bufferview() const +{ + return lyxview_->view(); +} + + +Buffer & Controller::buffer() +{ + BOOST_ASSERT(lyxview_->buffer()); + return *lyxview_->buffer(); +} + + +Buffer const & Controller::buffer() const +{ + BOOST_ASSERT(lyxview_->buffer()); + return *lyxview_->buffer(); +} + +} // namespace frontend +} // namespace lyx diff --git a/src/frontends/Dialog.h b/src/frontends/Dialog.h new file mode 100644 index 0000000000..e7d56fc84d --- /dev/null +++ b/src/frontends/Dialog.h @@ -0,0 +1,312 @@ +// -*- C++ -*- +/** + * \file Dialog.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef DIALOG_H +#define DIALOG_H + +#include "lfuns.h" + +#include "support/docstring.h" +#include + +namespace lyx { + +class Buffer; +class BufferView; +class FuncRequest; + +namespace frontend { + +class LyXView; + +/** \enum KernelDocType used to flag the different kinds of buffer + * without making the kernel header files available to the + * dialog's Controller or View. + */ +enum KernelDocType +{ + LATEX, + LITERATE, + DOCBOOK +}; + + +/** Different dialogs will have different Controllers and Views. + * deriving from these base classes. + */ +//@{ +class Controller; +//@} + +/** \c Dialog collects the different parts of a Model-Controller-View + * split of a generic dialog together. + */ +class Dialog +{ +public: + /// \param lv is the access point for the dialog to the LyX kernel. + /// \param name is the identifier given to the dialog by its parent + /// container. + Dialog() {} + virtual ~Dialog(); + + /** \name Container Access + * These methods are publicly accessible because they are invoked + * by the parent container acting on commands from the LyX kernel. + */ + //@{ + /// \param data is a string encoding of the data to be displayed. + /// It is passed to the Controller to be translated into a useable form. + virtual void showData(std::string const & /*data*/) {} + virtual void updateData(std::string const & /*data*/) {} + + virtual void hide() {} + + // Override in GuiDialog + virtual void slotOK() {} + virtual void slotApply() {} + virtual void slotRestore() {} + virtual void slotClose() {} + + /** This function is called, for example, if the GUI colours + * have been changed. + */ + virtual void redraw() {} + //@} + + /** Check whether we may apply our data. + * + * The buttons are disabled if not and (re-)enabled if yes. + */ + virtual void checkStatus() {} + + /** When applying, it's useful to know whether the dialog is about + * to close or not (no point refreshing the display for example). + */ + virtual bool isClosing() const { return false; } + + /** \name Dialog Specialization + * Methods to set the Controller and View and so specialise + * to a particular dialog. + */ + //@{ + virtual Controller & controller() = 0; + //@} + + /** \c Button controller part + */ + virtual void setButtonsValid(bool /*valid*/) {} + + + /** \c View part + * of a Model-Controller-View split of a generic dialog. + * These few methods are all that a generic dialog needs of a + * view. + */ + //@{ + /** A request to modify the data structures stored by the + * accompanying Controller in preparation for their dispatch to + * the LyX kernel. + */ + virtual void applyView() = 0; + + /// Hide the dialog from sight + virtual void hideView() = 0; + + /// Redraw the dialog (e.g. if the colors have been remapped). + virtual void redrawView() = 0; + + /// Create the dialog if necessary, update it and display it. + virtual void showView() = 0; + + /// Update the display of the dialog whilst it is still visible. + virtual void updateView() = 0; + + /// \return true if the dialog is visible. + virtual bool isVisibleView() const = 0; + //@} + + /** Defaults to nothing. Can be used by the Controller, however, to + * indicate to the View that something has changed and that the + * dialog therefore needs updating. + * \param id identifies what should be updated. + */ + virtual void partialUpdateView(int /*id*/) = 0; + + /// + virtual std::string name() const = 0; + +protected: + virtual void apply() {} + +private: + /// intentionally unimplemented, therefore uncopiable + Dialog(Dialog const &); + void operator=(Dialog const &); +}; + + +/** \c Controller is an abstract base class for the Controller + * of a Model-Controller-View split of a generic dialog. + */ +class Controller +{ +public: + /// \param parent Dialog owning this Controller. + Controller(Dialog & parent); + // the same. avoids ambiguity with the (non-existent) copy constructor + Controller(Dialog * parent); + virtual ~Controller(); + void setLyXView(LyXView & lv) { lyxview_ = &lv; } + + /** \name Generic Controller + * These few methods are all that a generic dialog needs of a + * controller. + */ + //@{ + /** Enable the controller to initialise its data structures. + * \param data is a string encoding of the parameters to be displayed. + * \return true if the translation was successful. + */ + virtual bool initialiseParams(std::string const & data) = 0; + + /// Enable the controller to clean up its data structures. + virtual void clearParams() = 0; + + /// Enable the Controller to dispatch its data back to the LyX kernel. + virtual void dispatchParams() = 0; + + /** \return true if the dialog should be shown only when + * a buffer is open. + */ + virtual bool isBufferDependent() const = 0; + + /** \return true if the dialog can apply data also + * for ReadOnly buffers. + * This has to be distinguished from isBufferDependent() + */ + virtual bool canApplyToReadOnly() const { return false; } + + /** The lfun that is sent for applying the data. + * + * This method is used by the default implementation of canApply() + * for buffer dependent dialogs that send one lfun when applying the + * data. + * It should be used in dispatchParams(), too for consistency reasons. + * \returns the lfun that is sent for applying the data. + */ + virtual kb_action getLfun() const { return LFUN_INSET_APPLY; } + + /** Check whether we may apply our data. + * + * The default implementation works for all dialogs that send one + * lfun when applying the data. Dialogs that send none or more than + * one lfun need to reimplement it. + * \returns whether the data can be applied or not. + */ + virtual bool canApply() const; + + /** \return true if the kernel should disconnect the dialog from + * a particular inset after the data has been applied to it. + * Clearly this makes sense only for dialogs modifying the contents + * of an inset :-) + * In practise, only a very few dialogs (e.g. the citation dialog) + * return true. + */ + virtual bool disconnectOnApply() const { return false; } + + /** \return true if Dialog::View::show() should not display the dialog + * after running update. Currently, only ControlSpellchecker + * makes use of that. + */ + virtual bool exitEarly() const { return false; } + //@} +public: + /** \name Controller Access + * Enable the derived classes to access the other parts of the whole. + */ + //@{ + Dialog & dialog() { return parent_; } + Dialog const & dialog() const { return parent_; } + //@} + + /** \c Kernel part: a wrapper making the LyX kernel available to the dialog. + * (Ie, it provides an interface to the Model part of the Model-Controller- + * View split. + * In an ideal world, it will shrink as more info is passed to the + * Dialog::show() and Dialog::update() methods. + */ + + + /** This method is the primary purpose of the class. It provides + * the "gateway" by which the dialog can send a request (of a + * change in the data, for more information) to the kernel. + * \param fr is the encoding of the request. + */ + void dispatch(FuncRequest const & fr) const; + + /** The dialog has received a request from the user + * (who pressed the "Restore" button) to update contents. + * It must, therefore, ask the kernel to provide this information. + * \param name is used to identify the dialog to the kernel. + */ + void updateDialog(std::string const & name) const; + + /** A request from the Controller that future changes to the data + * stored by the dialog are not applied to the inset currently + * connected to the dialog. Instead, they will be used to generate + * a new inset at the cursor position. + * \param name is used to identify the dialog to the kernel. + */ + void disconnect(std::string const & name) const; + + /** \name Kernel Wrappers + * Simple wrapper functions to Buffer methods. + */ + //@{ + bool isBufferAvailable() const; + bool isBufferReadonly() const; + std::string const bufferFilepath() const; + //@} + + /// The type of the current buffer. + KernelDocType docType() const; + + /** \name Kernel Nasties + * Unpleasantly public internals of the LyX kernel. + * We should aim to reduce/remove these from the interface. + */ + //@{ + LyXView & lyxview() { return *lyxview_; } + LyXView const & lyxview() const { return *lyxview_; } + + Buffer & buffer(); + Buffer const & buffer() const; + + BufferView * bufferview(); + BufferView const * bufferview() const; + //@} + +private: + /// intentionally unimplemented, therefore uncopiable + Controller(Controller const &); + void operator=(Controller const &); + +private: + Dialog & parent_; + LyXView * lyxview_; +}; + + +} // namespace frontend +} // namespace lyx + +#endif // DIALOG_H diff --git a/src/frontends/Dialogs.cpp b/src/frontends/Dialogs.cpp index ac3467e0ab..1d04db58c7 100644 --- a/src/frontends/Dialogs.cpp +++ b/src/frontends/Dialogs.cpp @@ -13,7 +13,7 @@ #include #include "Dialogs.h" -#include "controllers/Dialog.h" +#include "Dialog.h" #include #include diff --git a/src/frontends/Makefile.am b/src/frontends/Makefile.am index 4387df5853..b18690c243 100644 --- a/src/frontends/Makefile.am +++ b/src/frontends/Makefile.am @@ -1,8 +1,8 @@ include $(top_srcdir)/config/common.am -SUBDIRS = controllers $(FRONTENDS_SUBDIRS) +SUBDIRS = $(FRONTENDS_SUBDIRS) -DIST_SUBDIRS = controllers qt4 +DIST_SUBDIRS = qt4 EXTRA_DIST = pch.h @@ -13,6 +13,12 @@ noinst_LTLIBRARIES = liblyxfrontends.la AM_CPPFLAGS += $(PCH_FLAGS) -I$(srcdir)/.. $(BOOST_INCLUDES) liblyxfrontends_la_SOURCES = \ + ButtonPolicy.cpp \ + ButtonPolicy.h \ + Dialog.cpp \ + Dialog.h \ + frontend_helpers.cpp \ + frontend_helpers.h \ alert.cpp \ alert.h \ Alert_pimpl.h \ diff --git a/src/frontends/controllers/ButtonPolicy.cpp b/src/frontends/controllers/ButtonPolicy.cpp deleted file mode 100644 index 69c15f9772..0000000000 --- a/src/frontends/controllers/ButtonPolicy.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/** - * \file ButtonPolicy.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Allan Rae - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "ButtonPolicy.h" -#include "debug.h" - - -namespace lyx { -namespace frontend { - - -ButtonPolicy::ButtonPolicy(Policy policy) -{ - policy_ = policy; - state_ = INITIAL; - - switch (policy_) { - case OkCancelPolicy: - initOkCancel(); - break; - case OkCancelReadOnlyPolicy: - initOkCancelReadOnly(); - break; - case OkApplyCancelPolicy: - initOkApplyCancel(); - break; - case OkApplyCancelReadOnlyPolicy: - initOkApplyCancelReadOnly(); - break; - case NoRepeatedApplyPolicy: - initNoRepeatedApply(); - break; - case NoRepeatedApplyReadOnlyPolicy: - initNoRepeatedApplyReadOnly(); - break; - case PreferencesPolicy: - initPreferences(); - break; - case IgnorantPolicy: - break; - } -} - - -char const * functionName(ButtonPolicy::Policy policy) -{ - switch (policy) { - case ButtonPolicy::PreferencesPolicy: - return "PreferencesPolicy"; - case ButtonPolicy::OkCancelPolicy: - return "OkCancelPolicy"; - case ButtonPolicy::OkCancelReadOnlyPolicy: - return "OkCancelReadOnlyPolicy"; - case ButtonPolicy::OkApplyCancelPolicy: - return "OkApplyCancelPolicy"; - case ButtonPolicy::OkApplyCancelReadOnlyPolicy: - return "OkApplyCancelReadOnlyPolicy"; - case ButtonPolicy::NoRepeatedApplyPolicy: - return "NoRepeatedApplyPolicy"; - case ButtonPolicy::NoRepeatedApplyReadOnlyPolicy: - return "NoRepeatedApplyReadOnlyPolicy"; - case ButtonPolicy::IgnorantPolicy: - return "IgnorantPolicy"; - default: - return "Unknown policy"; - } -} - - -void ButtonPolicy::input(SMInput input) -{ - switch (policy_) { - case PreferencesPolicy: - // The APPLIED state is persistent. Next time the dialog is opened, - // the user will be able to press 'Save'. - if (SMI_CANCEL == input || SMI_HIDE == input) { - if (state_ != APPLIED) - state_ = INITIAL; - } else { - nextState(input); - } - break; - case IgnorantPolicy: - break; - default: - // CANCEL and HIDE always take us to INITIAL for all cases - if (SMI_CANCEL == input || SMI_HIDE == input) - state_ = INITIAL; - else - nextState(input); - break; - } -} - - -bool ButtonPolicy::buttonStatus(Button button) const -{ - return policy_ == IgnorantPolicy ? true : button & outputs_[state_]; -} - - -bool ButtonPolicy::isReadOnly() const -{ - switch(policy_) { - case NoRepeatedApplyReadOnlyPolicy: - case OkCancelReadOnlyPolicy: - case OkApplyCancelReadOnlyPolicy: - return RO_INITIAL == state_ - || RO_VALID == state_ - || RO_INVALID == state_ - || RO_APPLIED == state_; - default: - return false; - } -} - - -static char const * printState(ButtonPolicy::State const & state) -{ - switch (state) { - case ButtonPolicy::INITIAL: - return "INITIAL"; - case ButtonPolicy::VALID: - return "VALID"; - case ButtonPolicy::INVALID: - return "INVALID"; - case ButtonPolicy::APPLIED: - return "APPLIED"; - case ButtonPolicy::RO_INITIAL: - return "RO_INITIAL"; - case ButtonPolicy::RO_VALID: - return "RO_VALID"; - case ButtonPolicy::RO_INVALID: - return "RO_INVALID"; - case ButtonPolicy::RO_APPLIED: - return "RO_APPLIED"; - case ButtonPolicy::BOGUS: - return "BOGUS"; - default: - return ""; - } -} - - -static char const * printInput(ButtonPolicy::SMInput const & input) -{ - switch (input) { - case ButtonPolicy::SMI_VALID: - return "SMI_VALID"; - case ButtonPolicy::SMI_INVALID: - return "SMI_INVALID"; - case ButtonPolicy::SMI_OKAY: - return "SMI_OKAY"; - case ButtonPolicy::SMI_APPLY: - return "SMI_APPLY"; - case ButtonPolicy::SMI_CANCEL: - return "SMI_CANCEL"; - case ButtonPolicy::SMI_RESTORE: - return "SMI_RESTORE"; - case ButtonPolicy::SMI_HIDE: - return "SMI_HIDE"; - case ButtonPolicy::SMI_READ_ONLY: - return "SMI_READ_ONLY"; - case ButtonPolicy::SMI_READ_WRITE: - return "SMI_READ_WRITE"; - case ButtonPolicy::SMI_NOOP: - return "SMI_NOOP"; - case ButtonPolicy::SMI_TOTAL: - return "SMI_TOTAL"; - default: - return ""; - } -} - - -void ButtonPolicy::nextState(SMInput input) -{ - if (SMI_NOOP == input) - return; - - State tmp = state_machine_[state_][input]; - - LYXERR(Debug::GUI) << "Transition from state " - << printState(state_) << " to state " - << printState(tmp) << " after input " - << printInput(input) << std::endl; - - if (tmp != BOGUS) { - state_ = tmp; - } else { - lyxerr << functionName(policy_) - << ": No transition for input " - << printInput(input) - << " from state " - << printState(state_) - << std::endl; - } -} - - -void ButtonPolicy::initPreferences() -{ - outputs_ = StateOutputs(APPLIED + 1, ButtonPolicy::ALL_BUTTONS); - state_machine_ = StateMachine(APPLIED + 1, - StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); - - // Build the state output map - outputs_[INITIAL] = CLOSE; - outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; - outputs_[INVALID] = RESTORE | CANCEL; - outputs_[APPLIED] = OKAY | CLOSE; - - // Build the state machine one state at a time - // NOTE: Since CANCEL and HIDE always go to INITIAL they are - // left out of the state machine and handled explicitly - // in input(). This won't necessarily be true for all - // policies though so I'll leave those two as distinct - // inputs rather than merge them. For example, a dialog - // that doesn't update it's input fields when reshown - // after being hidden needs a policy where CANCEL and - // HIDE are treated differently. - // - // State::INITIAL - state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL; - state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; - state_machine_[INITIAL][SMI_VALID] = VALID; - state_machine_[INITIAL][SMI_INVALID] = INVALID; - // State::VALID - state_machine_[VALID][SMI_VALID] = VALID; - state_machine_[VALID][SMI_READ_ONLY] = VALID; - state_machine_[VALID][SMI_READ_WRITE] = VALID; - state_machine_[VALID][SMI_INVALID] = INVALID; - state_machine_[VALID][SMI_APPLY] = APPLIED; - state_machine_[VALID][SMI_OKAY] = INITIAL; - state_machine_[VALID][SMI_RESTORE] = INITIAL; - // State::INVALID - state_machine_[INVALID][SMI_VALID] = VALID; - state_machine_[INVALID][SMI_INVALID] = INVALID; - state_machine_[INVALID][SMI_READ_ONLY] = INVALID; - state_machine_[INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[INVALID][SMI_RESTORE] = INITIAL; - // State::APPLIED - state_machine_[APPLIED][SMI_VALID] = VALID; - state_machine_[APPLIED][SMI_INVALID] = INVALID; - state_machine_[APPLIED][SMI_OKAY] = INITIAL; - state_machine_[APPLIED][SMI_READ_ONLY] = APPLIED; - state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED; -} - - -void ButtonPolicy::initOkCancel() -{ - outputs_ = StateOutputs(INVALID + 1, ButtonPolicy::ALL_BUTTONS); - state_machine_ = StateMachine(INVALID + 1, - StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); - - // Build the state output map - outputs_[INITIAL] = CLOSE; - outputs_[VALID] = RESTORE | OKAY | CANCEL; - outputs_[INVALID] = RESTORE | CANCEL; - - // Build the state machine one state at a time - // NOTE: Since CANCEL and HIDE always go to INITIAL they are - // left out of the state machine and handled explicitly - // in input() - // - // State::INITIAL - state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL; - state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; - state_machine_[INITIAL][SMI_VALID] = VALID; - state_machine_[INITIAL][SMI_INVALID] = INVALID; - // State::VALID - state_machine_[VALID][SMI_VALID] = VALID; - state_machine_[VALID][SMI_READ_ONLY] = VALID; - state_machine_[VALID][SMI_READ_WRITE] = VALID; - state_machine_[VALID][SMI_INVALID] = INVALID; - state_machine_[VALID][SMI_OKAY] = INITIAL; - state_machine_[VALID][SMI_RESTORE] = INITIAL; - // State::INVALID - state_machine_[INVALID][SMI_VALID] = VALID; - state_machine_[INVALID][SMI_INVALID] = INVALID; - state_machine_[INVALID][SMI_READ_ONLY] = INVALID; - state_machine_[INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[INVALID][SMI_RESTORE] = INITIAL; -} - - -void ButtonPolicy::initOkCancelReadOnly() -{ - outputs_ = StateOutputs(RO_INVALID + 1, ButtonPolicy::ALL_BUTTONS); - state_machine_ = StateMachine(RO_INVALID + 1, - StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); - - // Build the state output map - outputs_[INITIAL] = CLOSE; - outputs_[VALID] = RESTORE | OKAY | CANCEL; - outputs_[INVALID] = RESTORE | CANCEL; - outputs_[RO_INITIAL] = CLOSE; - outputs_[RO_VALID] = RESTORE | CANCEL; - outputs_[RO_INVALID] = RESTORE | CANCEL; - - // Build the state machine one state at a time - // NOTE: Since CANCEL and HIDE always go to INITIAL they are - // left out of the state machine and handled explicitly - // in input() - // - // State::INITIAL - state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; - state_machine_[INITIAL][SMI_VALID] = VALID; - state_machine_[INITIAL][SMI_INVALID] = INVALID; - state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL; - // State::VALID - state_machine_[VALID][SMI_VALID] = VALID; - state_machine_[VALID][SMI_READ_WRITE] = VALID; - state_machine_[VALID][SMI_INVALID] = INVALID; - state_machine_[VALID][SMI_OKAY] = INITIAL; - state_machine_[VALID][SMI_RESTORE] = INITIAL; - state_machine_[VALID][SMI_READ_ONLY] = RO_VALID; - // State::INVALID - state_machine_[INVALID][SMI_INVALID] = INVALID; - state_machine_[INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[INVALID][SMI_VALID] = VALID; - state_machine_[INVALID][SMI_RESTORE] = INITIAL; - state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID; - // State::RO_INITIAL - state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL; - state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID; - state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID; - state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL; - // State::RO_VALID - state_machine_[RO_VALID][SMI_VALID] = RO_VALID; - state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID; - state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID; - state_machine_[RO_VALID][SMI_READ_WRITE] = VALID; - state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL; - // State::RO_INVALID - state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID; - state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID; - state_machine_[RO_INVALID][SMI_VALID] = RO_VALID; - state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL; -} - - -void ButtonPolicy::initNoRepeatedApplyReadOnly() -{ - outputs_ = StateOutputs(RO_INVALID + 1, ButtonPolicy::ALL_BUTTONS); - state_machine_ = StateMachine(RO_INVALID + 1, - StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); - - // Build the state output map - outputs_[INITIAL] = CLOSE; - outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; - outputs_[INVALID] = RESTORE | CANCEL; - outputs_[RO_INITIAL] = CLOSE; - outputs_[RO_VALID] = RESTORE | CANCEL; - outputs_[RO_INVALID] = RESTORE | CANCEL; - - // Build the state machine one state at a time - // NOTE: Since CANCEL and HIDE always go to INITIAL they are - // left out of the state machine and handled explicitly - // in input() - // - // State::INITIAL - state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; - state_machine_[INITIAL][SMI_VALID] = VALID; - state_machine_[INITIAL][SMI_INVALID] = INVALID; - state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL; - // State::VALID - state_machine_[VALID][SMI_VALID] = VALID; - state_machine_[VALID][SMI_READ_WRITE] = VALID; - state_machine_[VALID][SMI_INVALID] = INVALID; - state_machine_[VALID][SMI_OKAY] = INITIAL; - state_machine_[VALID][SMI_APPLY] = INITIAL; - state_machine_[VALID][SMI_RESTORE] = INITIAL; - state_machine_[VALID][SMI_READ_ONLY] = RO_VALID; - // State::INVALID - state_machine_[INVALID][SMI_INVALID] = INVALID; - state_machine_[INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[INVALID][SMI_VALID] = VALID; - state_machine_[INVALID][SMI_RESTORE] = INITIAL; - state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID; - // State::RO_INITIAL - state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL; - state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID; - state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID; - state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL; - // State::RO_VALID - state_machine_[RO_VALID][SMI_VALID] = RO_VALID; - state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID; - state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID; - state_machine_[RO_VALID][SMI_READ_WRITE] = VALID; - state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL; - // State::RO_INVALID - state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID; - state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID; - state_machine_[RO_INVALID][SMI_VALID] = RO_VALID; - state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL; -} - - -void ButtonPolicy::initOkApplyCancelReadOnly() -{ - outputs_ = StateOutputs(RO_APPLIED + 1, ButtonPolicy::ALL_BUTTONS); - state_machine_ = StateMachine(RO_APPLIED + 1, - StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); - - // Build the state output map - outputs_[INITIAL] = CLOSE; - outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; - outputs_[INVALID] = RESTORE | CANCEL; - outputs_[APPLIED] = OKAY | APPLY | CLOSE; - outputs_[RO_INITIAL] = CLOSE; - outputs_[RO_VALID] = RESTORE | CANCEL; - outputs_[RO_INVALID] = RESTORE | CANCEL; - outputs_[RO_APPLIED] = CLOSE; - - // Build the state machine one state at a time - // NOTE: Since CANCEL and HIDE always go to INITIAL they are - // left out of the state machine and handled explicitly - // in input() - // - // State::INITIAL - state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; - state_machine_[INITIAL][SMI_VALID] = VALID; - state_machine_[INITIAL][SMI_INVALID] = INVALID; - state_machine_[INITIAL][SMI_READ_ONLY] = RO_INITIAL; - // State::VALID - state_machine_[VALID][SMI_VALID] = VALID; - state_machine_[VALID][SMI_READ_WRITE] = VALID; - state_machine_[VALID][SMI_INVALID] = INVALID; - state_machine_[VALID][SMI_OKAY] = INITIAL; - state_machine_[VALID][SMI_RESTORE] = INITIAL; - state_machine_[VALID][SMI_APPLY] = APPLIED; - state_machine_[VALID][SMI_READ_ONLY] = RO_VALID; - // State::INVALID - state_machine_[INVALID][SMI_INVALID] = INVALID; - state_machine_[INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[INVALID][SMI_VALID] = VALID; - state_machine_[INVALID][SMI_RESTORE] = INITIAL; - state_machine_[INVALID][SMI_READ_ONLY] = RO_INVALID; - // State::APPLIED - state_machine_[APPLIED][SMI_APPLY] = APPLIED; - state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED; - state_machine_[APPLIED][SMI_VALID] = VALID; - state_machine_[APPLIED][SMI_INVALID] = INVALID; - state_machine_[APPLIED][SMI_OKAY] = INITIAL; - state_machine_[APPLIED][SMI_READ_ONLY] = RO_APPLIED; - // State::RO_INITIAL - state_machine_[RO_INITIAL][SMI_READ_ONLY] = RO_INITIAL; - state_machine_[RO_INITIAL][SMI_VALID] = RO_VALID; - state_machine_[RO_INITIAL][SMI_INVALID] = RO_INVALID; - state_machine_[RO_INITIAL][SMI_READ_WRITE] = INITIAL; - // State::RO_VALID - state_machine_[RO_VALID][SMI_VALID] = RO_VALID; - state_machine_[RO_VALID][SMI_READ_ONLY] = RO_VALID; - state_machine_[RO_VALID][SMI_INVALID] = RO_INVALID; - state_machine_[RO_VALID][SMI_READ_WRITE] = VALID; - state_machine_[RO_VALID][SMI_RESTORE] = RO_INITIAL; - // State::RO_INVALID - state_machine_[RO_INVALID][SMI_INVALID] = RO_INVALID; - state_machine_[RO_INVALID][SMI_READ_ONLY] = RO_INVALID; - state_machine_[RO_INVALID][SMI_VALID] = RO_VALID; - state_machine_[RO_INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[RO_INVALID][SMI_RESTORE] = RO_INITIAL; - // State::RO_APPLIED - state_machine_[RO_APPLIED][SMI_READ_ONLY] = RO_APPLIED; - state_machine_[RO_APPLIED][SMI_INVALID] = RO_INVALID; - state_machine_[RO_APPLIED][SMI_VALID] = RO_VALID; - state_machine_[RO_APPLIED][SMI_READ_WRITE] = APPLIED; -} - - -void ButtonPolicy::initOkApplyCancel() -{ - outputs_ = StateOutputs(APPLIED + 1, ButtonPolicy::ALL_BUTTONS); - state_machine_ = StateMachine(APPLIED + 1, - StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); - - // Build the state output map - outputs_[INITIAL] = CLOSE; - outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; - outputs_[INVALID] = RESTORE | CANCEL; - outputs_[APPLIED] = OKAY | APPLY | CLOSE; - - // Build the state machine one state at a time - // NOTE: Since CANCEL and HIDE always go to INITIAL they are - // left out of the state machine and handled explicitly - // in input() - // - // State::INITIAL - state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL; - state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; - state_machine_[INITIAL][SMI_VALID] = VALID; - state_machine_[INITIAL][SMI_INVALID] = INVALID; - // State::VALID - state_machine_[VALID][SMI_VALID] = VALID; - state_machine_[VALID][SMI_READ_ONLY] = VALID; - state_machine_[VALID][SMI_READ_WRITE] = VALID; - state_machine_[VALID][SMI_INVALID] = INVALID; - state_machine_[VALID][SMI_OKAY] = INITIAL; - state_machine_[VALID][SMI_RESTORE] = INITIAL; - state_machine_[VALID][SMI_APPLY] = APPLIED; - // State::INVALID - state_machine_[INVALID][SMI_INVALID] = INVALID; - state_machine_[INVALID][SMI_READ_ONLY] = INVALID; - state_machine_[INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[INVALID][SMI_VALID] = VALID; - state_machine_[INVALID][SMI_RESTORE] = INITIAL; - // State::APPLIED - state_machine_[APPLIED][SMI_APPLY] = APPLIED; - state_machine_[APPLIED][SMI_READ_ONLY] = APPLIED; - state_machine_[APPLIED][SMI_READ_WRITE] = APPLIED; - state_machine_[APPLIED][SMI_VALID] = VALID; - state_machine_[APPLIED][SMI_INVALID] = INVALID; - state_machine_[APPLIED][SMI_OKAY] = INITIAL; -} - - -void ButtonPolicy::initNoRepeatedApply() -{ - outputs_ = StateOutputs(INVALID + 1, ButtonPolicy::ALL_BUTTONS); - state_machine_ = StateMachine(INVALID + 1, - StateArray(int(SMI_TOTAL), ButtonPolicy::BOGUS)); - - // Build the state output map - outputs_[INITIAL] = CLOSE; - outputs_[VALID] = RESTORE | OKAY | APPLY | CANCEL; - outputs_[INVALID] = RESTORE | CANCEL; - - // Build the state machine one state at a time - // NOTE: Since CANCEL and HIDE always go to INITIAL they are - // left out of the state machine and handled explicitly - // in input() - // - // State::INITIAL - state_machine_[INITIAL][SMI_READ_ONLY] = INITIAL; - state_machine_[INITIAL][SMI_READ_WRITE] = INITIAL; - state_machine_[INITIAL][SMI_VALID] = VALID; - state_machine_[INITIAL][SMI_INVALID] = INVALID; - // State::VALID - state_machine_[VALID][SMI_VALID] = VALID; - state_machine_[VALID][SMI_READ_ONLY] = VALID; - state_machine_[VALID][SMI_READ_WRITE] = VALID; - state_machine_[VALID][SMI_INVALID] = INVALID; - state_machine_[VALID][SMI_OKAY] = INITIAL; - state_machine_[VALID][SMI_APPLY] = INITIAL; - state_machine_[VALID][SMI_RESTORE] = INITIAL; - // State::INVALID - state_machine_[INVALID][SMI_INVALID] = INVALID; - state_machine_[INVALID][SMI_READ_ONLY] = INVALID; - state_machine_[INVALID][SMI_READ_WRITE] = INVALID; - state_machine_[INVALID][SMI_VALID] = VALID; - state_machine_[INVALID][SMI_RESTORE] = INITIAL; -} - - -} // namespace frontend -} // namespace lyx diff --git a/src/frontends/controllers/ButtonPolicy.h b/src/frontends/controllers/ButtonPolicy.h deleted file mode 100644 index beebc62c79..0000000000 --- a/src/frontends/controllers/ButtonPolicy.h +++ /dev/null @@ -1,300 +0,0 @@ -// -*- C++ -*- -/** - * \file ButtonPolicy.h - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Allan Rae - * - * Full author contact details are available in file CREDITS. - * - * Provides a state machine implementation of the various button policies - * used by the dialogs. - */ - -#ifndef BUTTONPOLICY_H -#define BUTTONPOLICY_H - -#include -#include - -namespace lyx { -namespace frontend { - -/** A class for button policies. - A state machine implementation of the various button policies used by the - dialogs. Only the policy is implemented here. Separate ButtonController - classes are needed for each GUI implementation. - - Policy | ReadOnly | Apply Button | Repeated Apply - ======================================================================== - OkCancel | N | N | - - OkCancelReadOnly | Y | N | - - OkApplyCancel | N | Y | Y - OkApplyCancelReadOnly | Y | Y | Y - NoRepeatedApply | N | Y | N - NoRepeatedApplyReadOnly | Y | Y | N - Preferences | N | Y | No (Ok-Close) - Ignorant | N/A | N/A | N/A - ======================================================================== - - Policy - The name of the policy - ReadOnly - Does the policy treat read-only docs differently to read-write docs? - This usually means that when an SMI_READ_ONLY input arrives then - all the buttons are disabled except Cancel/Close. The state - machine tracks the inputs (valid/invalid) and has states for all - combinations. When an SMI_READ_WRITE input arrives the appropriate - machine state is entered (just as if the document had always been - read-write). - NOTE: If a dialog doesn't care about the read-only status of a document - (and uses an appropriate policy) it can never get into a read-only state - so isReadOnly() can only ever return false even though the document may - be read-only. - Repeated Apply - Simply means that it is alright to use the Apply button multiple times - without requiring a change of the dialog contents. If no repeating is - allowed the Ok+Apply buttons are deactivated. The Preferences dialog - has its own special version of repeated apply handling because its Ok - button is actually a Save button -- it is always reasonable to Save the - preferences if the dialog has changed since the last save. - - The IgnorantPolicy is a special case that allows anything. - */ - -class ButtonPolicy { -public: - - // The various poicies - enum Policy { - /** Ok and Cancel buttons for dialogs with read-only operation. - Note: This scheme supports the relabelling of Cancel to Close and - vice versa. - This is based on the value of the bool state of the Button::CANCEL. - true == Cancel, false == Close - */ - OkCancelPolicy, - - - /** Ok and Cancel buttons for dialogs where read-only operation is blocked. - The state machine design for this policy allows changes to occur within - the dialog while a file is read-only -- the okay button is disabled until - a read-write input is given. When the file is made read-write the dialog - will then be in the correct state (as if the file had always been - read-write). - Note: This scheme supports the relabelling of Cancel to Close - and vice versa. - This is based on the value of the bool state of the Button::CANCEL. - true == Cancel, false == Close - */ - OkCancelReadOnlyPolicy, - - /** Ok, Apply and Cancel buttons for dialogs where read-only operation - is blocked. - Repeated Apply are not allowed. Likewise, Ok cannot follow Apply without - some valid input. That is, the dialog contents must change between - each Apply or Apply and Ok. - The state machine design for this policy allows changes to occur within - the dialog while a file is read-only -- the Ok+Apply buttons are disabled - until a read-write input is given. When the file is made read-write the - dialog will then be in the correct state (as if the file had always been - read-write). - Note: This scheme supports the relabelling of Cancel to Close - and vice versa. - This is based on the value of the bool state of the Button::CANCEL. - true == Cancel, false == Close - */ - NoRepeatedApplyReadOnlyPolicy, - - /** Ok, Apply and Cancel buttons for dialogs where read-only - operation is blocked. - Repeated Apply is allowed. Likewise, Ok can follow Apply. - The state machine design for this policy allows changes to occur within - the dialog while a file is read-only -- the Ok+Apply buttons are disabled - until a read-write input is given. When the file is made read-write the - dialog will then be in the correct state (as if the file had always been - read-write). - Note: This scheme supports the relabelling of Cancel to Close - and vice versa. - This is based on the value of the bool state of the Button::CANCEL. - true == Cancel, false == Close - */ - OkApplyCancelReadOnlyPolicy, - - /** Ok, Apply and Cancel buttons for dialogs where repeated - * Apply is allowed. - Note: This scheme supports the relabelling of Cancel to Close - and vice versa. - This is based on the value of the bool state of the Button::CANCEL. - true == Cancel, false == Close - */ - OkApplyCancelPolicy, - - /** Ok, Apply and Cancel buttons for dialogs with no repeated Apply. - Note: This scheme supports the relabelling of Cancel to Close - and vice versa. - This is based on the value of the bool state of the Button::CANCEL. - true == Cancel, false == Close - */ - NoRepeatedApplyPolicy, - - /** Defines the policy used by the Preferences dialog. - Four buttons: Ok (Save), Apply, Cancel/Close, Restore. - Note: This scheme supports the relabelling of Cancel to Close - and vice versa. - This is based on the value of the bool state of the Button::CANCEL. - true == Cancel, false == Close - */ - PreferencesPolicy, - - /** Defines the policy used by dialogs that are forced to support a button - controller when they either don't have a use for one or are not ready to - use one. This may be useful when testing a new button policy but wishing - to minimise problems to users by supplying an anything-goes policy via a - preprocessor directive. - */ - IgnorantPolicy, - }; - - /// Constructor - explicit ButtonPolicy(Policy policy); - - /** The various possible state names. - Not all state-machines have this many states. However, we need - to define them all here so we can share the code. - */ - enum State { - /// - INITIAL = 0, - /// - VALID, - /// - INVALID, - /// - APPLIED, - /// - RO_INITIAL, - /// - RO_VALID, - /// - RO_INVALID, - /// - RO_APPLIED, - /// - BOGUS = 55 - }; - - /// The various button types. - enum Button { - /// - CLOSE = 0, // Not a real button, but effectively !CANCEL - /// - OKAY = 1, - /// - APPLY = 2, - /// - CANCEL = 4, - /// - RESTORE = 8 - }; - /// - static const Button ALL_BUTTONS = - Button(OKAY | APPLY | CANCEL | RESTORE); - - /** State machine inputs. - All the policies so far have both CANCEL and HIDE always going to - INITIAL. This won't necessarily be true for all [future] policies - though so I'll leave those two as distinct inputs rather than merge - them. For example, a dialog that doesn't update it's input fields - when reshown after being hidden needs a policy where CANCEL and - HIDE are treated differently. - */ - enum SMInput { - /// the dialog contents are now valid - SMI_VALID = 0, - /// the dialog contents are now invalid - SMI_INVALID, - /// an apply-and-hide action has happened - SMI_OKAY, - /// an apply action has happened - SMI_APPLY, - /// a cancel action has happened - SMI_CANCEL, - /// a restore action has happened - SMI_RESTORE, - /// the dialog has been hidden - SMI_HIDE, - /// the dialog contents are read-only - SMI_READ_ONLY, - /// the dialog contents can be modified - SMI_READ_WRITE, - /// the state of the dialog contents has not changed - SMI_NOOP, - /// for internal use - SMI_TOTAL - }; - - /// Trigger a transition with this input. - void input(SMInput); - /** Activation status of a button. - We assume that we haven't gotten into an undefined state. - This is reasonable since we can only reach states defined - in the state machine and they should all have been defined in - the outputs_ variable. Perhaps we can do something at compile - time to check that all the states have corresponding outputs. - */ - bool buttonStatus(Button) const; - /// Are we in a read-only state? - bool isReadOnly() const; - -private: - /// - Policy policy_; - - /// Transition map of the state machine. - typedef std::vector StateArray; - /// - typedef std::vector StateMachine; - /// The state outputs are the status of the buttons. - typedef std::vector StateOutputs; - - /// Current state. - State state_; - /// Which buttons are active for a given state. - StateOutputs outputs_; - /// - StateMachine state_machine_; - -private: - // Helpers - void nextState(SMInput input); - - void initOkCancel(); - void initOkCancelReadOnly(); - void initNoRepeatedApplyReadOnly(); - void initOkApplyCancelReadOnly(); - void initOkApplyCancel(); - void initNoRepeatedApply(); - void initPreferences(); -}; - - -inline -std::ostream & operator<<(std::ostream & os, ButtonPolicy::State st) -{ - return os << int(st); -} - - -inline -std::ostream & operator<<(std::ostream & os, ButtonPolicy::SMInput smi) -{ - return os << int(smi); -} - - -} // namespace frontend -} // namespace lyx - -#endif diff --git a/src/frontends/controllers/Dialog.cpp b/src/frontends/controllers/Dialog.cpp deleted file mode 100644 index 88d2312ef4..0000000000 --- a/src/frontends/controllers/Dialog.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/** - * \file Dialog.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "Dialog.h" - -#include "FuncRequest.h" -#include "FuncStatus.h" -#include "LyXFunc.h" - -#include "frontends/LyXView.h" -#include "frontends/Dialogs.h" // FIXME - -#include "Buffer.h" - - -namespace lyx { -namespace frontend { - - -Dialog::~Dialog() -{} - - -Controller::Controller(Dialog & parent) - : parent_(parent), lyxview_(0) -{} - - -Controller::Controller(Dialog * parent) - : parent_(*parent), lyxview_(0) -{} - - -Controller::~Controller() -{} - - -bool Controller::canApply() const -{ - FuncRequest const fr(getLfun(), dialog().name()); - FuncStatus const fs(getStatus(fr)); - return fs.enabled(); -} - - -void Controller::dispatch(FuncRequest const & fr) const -{ - lyxview_->dispatch(fr); -} - - -void Controller::updateDialog(std::string const & name) const -{ - dispatch(FuncRequest(LFUN_DIALOG_UPDATE, name)); -} - - -void Controller::disconnect(std::string const & name) const -{ - lyxview_->getDialogs().disconnect(name); -} - - -bool Controller::isBufferAvailable() const -{ - return lyxview_->buffer() != 0; -} - - -bool Controller::isBufferReadonly() const -{ - if (!lyxview_->buffer()) - return true; - return lyxview_->buffer()->isReadonly(); -} - - -std::string const Controller::bufferFilepath() const -{ - return buffer().filePath(); -} - - -KernelDocType Controller::docType() const -{ - if (buffer().isLatex()) - return LATEX; - if (buffer().isLiterate()) - return LITERATE; - - return DOCBOOK; -} - - -BufferView * Controller::bufferview() -{ - return lyxview_->view(); -} - - -BufferView const * Controller::bufferview() const -{ - return lyxview_->view(); -} - - -Buffer & Controller::buffer() -{ - BOOST_ASSERT(lyxview_->buffer()); - return *lyxview_->buffer(); -} - - -Buffer const & Controller::buffer() const -{ - BOOST_ASSERT(lyxview_->buffer()); - return *lyxview_->buffer(); -} - -} // namespace frontend -} // namespace lyx diff --git a/src/frontends/controllers/Dialog.h b/src/frontends/controllers/Dialog.h deleted file mode 100644 index e7d56fc84d..0000000000 --- a/src/frontends/controllers/Dialog.h +++ /dev/null @@ -1,312 +0,0 @@ -// -*- C++ -*- -/** - * \file Dialog.h - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#ifndef DIALOG_H -#define DIALOG_H - -#include "lfuns.h" - -#include "support/docstring.h" -#include - -namespace lyx { - -class Buffer; -class BufferView; -class FuncRequest; - -namespace frontend { - -class LyXView; - -/** \enum KernelDocType used to flag the different kinds of buffer - * without making the kernel header files available to the - * dialog's Controller or View. - */ -enum KernelDocType -{ - LATEX, - LITERATE, - DOCBOOK -}; - - -/** Different dialogs will have different Controllers and Views. - * deriving from these base classes. - */ -//@{ -class Controller; -//@} - -/** \c Dialog collects the different parts of a Model-Controller-View - * split of a generic dialog together. - */ -class Dialog -{ -public: - /// \param lv is the access point for the dialog to the LyX kernel. - /// \param name is the identifier given to the dialog by its parent - /// container. - Dialog() {} - virtual ~Dialog(); - - /** \name Container Access - * These methods are publicly accessible because they are invoked - * by the parent container acting on commands from the LyX kernel. - */ - //@{ - /// \param data is a string encoding of the data to be displayed. - /// It is passed to the Controller to be translated into a useable form. - virtual void showData(std::string const & /*data*/) {} - virtual void updateData(std::string const & /*data*/) {} - - virtual void hide() {} - - // Override in GuiDialog - virtual void slotOK() {} - virtual void slotApply() {} - virtual void slotRestore() {} - virtual void slotClose() {} - - /** This function is called, for example, if the GUI colours - * have been changed. - */ - virtual void redraw() {} - //@} - - /** Check whether we may apply our data. - * - * The buttons are disabled if not and (re-)enabled if yes. - */ - virtual void checkStatus() {} - - /** When applying, it's useful to know whether the dialog is about - * to close or not (no point refreshing the display for example). - */ - virtual bool isClosing() const { return false; } - - /** \name Dialog Specialization - * Methods to set the Controller and View and so specialise - * to a particular dialog. - */ - //@{ - virtual Controller & controller() = 0; - //@} - - /** \c Button controller part - */ - virtual void setButtonsValid(bool /*valid*/) {} - - - /** \c View part - * of a Model-Controller-View split of a generic dialog. - * These few methods are all that a generic dialog needs of a - * view. - */ - //@{ - /** A request to modify the data structures stored by the - * accompanying Controller in preparation for their dispatch to - * the LyX kernel. - */ - virtual void applyView() = 0; - - /// Hide the dialog from sight - virtual void hideView() = 0; - - /// Redraw the dialog (e.g. if the colors have been remapped). - virtual void redrawView() = 0; - - /// Create the dialog if necessary, update it and display it. - virtual void showView() = 0; - - /// Update the display of the dialog whilst it is still visible. - virtual void updateView() = 0; - - /// \return true if the dialog is visible. - virtual bool isVisibleView() const = 0; - //@} - - /** Defaults to nothing. Can be used by the Controller, however, to - * indicate to the View that something has changed and that the - * dialog therefore needs updating. - * \param id identifies what should be updated. - */ - virtual void partialUpdateView(int /*id*/) = 0; - - /// - virtual std::string name() const = 0; - -protected: - virtual void apply() {} - -private: - /// intentionally unimplemented, therefore uncopiable - Dialog(Dialog const &); - void operator=(Dialog const &); -}; - - -/** \c Controller is an abstract base class for the Controller - * of a Model-Controller-View split of a generic dialog. - */ -class Controller -{ -public: - /// \param parent Dialog owning this Controller. - Controller(Dialog & parent); - // the same. avoids ambiguity with the (non-existent) copy constructor - Controller(Dialog * parent); - virtual ~Controller(); - void setLyXView(LyXView & lv) { lyxview_ = &lv; } - - /** \name Generic Controller - * These few methods are all that a generic dialog needs of a - * controller. - */ - //@{ - /** Enable the controller to initialise its data structures. - * \param data is a string encoding of the parameters to be displayed. - * \return true if the translation was successful. - */ - virtual bool initialiseParams(std::string const & data) = 0; - - /// Enable the controller to clean up its data structures. - virtual void clearParams() = 0; - - /// Enable the Controller to dispatch its data back to the LyX kernel. - virtual void dispatchParams() = 0; - - /** \return true if the dialog should be shown only when - * a buffer is open. - */ - virtual bool isBufferDependent() const = 0; - - /** \return true if the dialog can apply data also - * for ReadOnly buffers. - * This has to be distinguished from isBufferDependent() - */ - virtual bool canApplyToReadOnly() const { return false; } - - /** The lfun that is sent for applying the data. - * - * This method is used by the default implementation of canApply() - * for buffer dependent dialogs that send one lfun when applying the - * data. - * It should be used in dispatchParams(), too for consistency reasons. - * \returns the lfun that is sent for applying the data. - */ - virtual kb_action getLfun() const { return LFUN_INSET_APPLY; } - - /** Check whether we may apply our data. - * - * The default implementation works for all dialogs that send one - * lfun when applying the data. Dialogs that send none or more than - * one lfun need to reimplement it. - * \returns whether the data can be applied or not. - */ - virtual bool canApply() const; - - /** \return true if the kernel should disconnect the dialog from - * a particular inset after the data has been applied to it. - * Clearly this makes sense only for dialogs modifying the contents - * of an inset :-) - * In practise, only a very few dialogs (e.g. the citation dialog) - * return true. - */ - virtual bool disconnectOnApply() const { return false; } - - /** \return true if Dialog::View::show() should not display the dialog - * after running update. Currently, only ControlSpellchecker - * makes use of that. - */ - virtual bool exitEarly() const { return false; } - //@} -public: - /** \name Controller Access - * Enable the derived classes to access the other parts of the whole. - */ - //@{ - Dialog & dialog() { return parent_; } - Dialog const & dialog() const { return parent_; } - //@} - - /** \c Kernel part: a wrapper making the LyX kernel available to the dialog. - * (Ie, it provides an interface to the Model part of the Model-Controller- - * View split. - * In an ideal world, it will shrink as more info is passed to the - * Dialog::show() and Dialog::update() methods. - */ - - - /** This method is the primary purpose of the class. It provides - * the "gateway" by which the dialog can send a request (of a - * change in the data, for more information) to the kernel. - * \param fr is the encoding of the request. - */ - void dispatch(FuncRequest const & fr) const; - - /** The dialog has received a request from the user - * (who pressed the "Restore" button) to update contents. - * It must, therefore, ask the kernel to provide this information. - * \param name is used to identify the dialog to the kernel. - */ - void updateDialog(std::string const & name) const; - - /** A request from the Controller that future changes to the data - * stored by the dialog are not applied to the inset currently - * connected to the dialog. Instead, they will be used to generate - * a new inset at the cursor position. - * \param name is used to identify the dialog to the kernel. - */ - void disconnect(std::string const & name) const; - - /** \name Kernel Wrappers - * Simple wrapper functions to Buffer methods. - */ - //@{ - bool isBufferAvailable() const; - bool isBufferReadonly() const; - std::string const bufferFilepath() const; - //@} - - /// The type of the current buffer. - KernelDocType docType() const; - - /** \name Kernel Nasties - * Unpleasantly public internals of the LyX kernel. - * We should aim to reduce/remove these from the interface. - */ - //@{ - LyXView & lyxview() { return *lyxview_; } - LyXView const & lyxview() const { return *lyxview_; } - - Buffer & buffer(); - Buffer const & buffer() const; - - BufferView * bufferview(); - BufferView const * bufferview() const; - //@} - -private: - /// intentionally unimplemented, therefore uncopiable - Controller(Controller const &); - void operator=(Controller const &); - -private: - Dialog & parent_; - LyXView * lyxview_; -}; - - -} // namespace frontend -} // namespace lyx - -#endif // DIALOG_H diff --git a/src/frontends/controllers/Makefile.am b/src/frontends/controllers/Makefile.am index 42b3989eca..4dd8e30f53 100644 --- a/src/frontends/controllers/Makefile.am +++ b/src/frontends/controllers/Makefile.am @@ -6,15 +6,9 @@ EXTRA_DIST = tests/regfiles/biblio noinst_LTLIBRARIES = liblyxcontrollers.la -SOURCEFILES = \ - Dialog.cpp \ - ButtonPolicy.cpp \ - frontend_helpers.cpp - -HEADERFILES = \ - Dialog.h \ - ButtonPolicy.h \ - frontend_helpers.h +SOURCEFILES = + +HEADERFILES = if MONOLITHIC_CONTROLLERS diff --git a/src/frontends/controllers/frontend_helpers.cpp b/src/frontends/controllers/frontend_helpers.cpp deleted file mode 100644 index bf319d488d..0000000000 --- a/src/frontends/controllers/frontend_helpers.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/** - * \file frontend_helpers.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * \author Herbert Voß - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "frontend_helpers.h" - -#include "gettext.h" -#include "Language.h" - -#include "frontends/FileDialog.h" -#include "frontends/alert.h" - -#include "support/filetools.h" -#include "support/lstrings.h" -#include "support/lyxalgo.h" -#include "support/os.h" -#include "support/Package.h" -#include "support/Path.h" -#include "support/Systemcall.h" - -#include - -#include -#include - -using std::string; -using std::vector; -using std::pair; -using std::endl; - -namespace lyx { -namespace frontend { - -using support::addName; -using support::bformat; -using support::FileFilterList; -using support::FileName; -using support::getExtension; -using support::getFileContents; -using support::getVectorFromString; -using support::libFileSearch; -using support::makeAbsPath; -using support::makeRelPath; -using support::onlyFilename; -using support::onlyPath; -using support::package; -using support::prefixIs; -using support::quoteName; -using support::removeExtension; -using support::Systemcall; -using support::token; - - -namespace { - -struct Sorter -{ - bool operator()(LanguagePair const & lhs, LanguagePair const & rhs) const { - return lhs.first < rhs.first; - } -}; - - -} // namespace anon - - -vector const getLanguageData(bool character_dlg) -{ - vector::size_type const size = character_dlg ? - languages.size() + 2 : languages.size(); - - vector langs(size); - - if (character_dlg) { - langs[0].first = _("No change"); - langs[0].second = "ignore"; - langs[1].first = _("Reset"); - langs[1].second = "reset"; - } - - vector::size_type i = character_dlg ? 2 : 0; - for (Languages::const_iterator cit = languages.begin(); - cit != languages.end(); ++cit) { - langs[i].first = _(cit->second.display()); - langs[i].second = cit->second.lang(); - ++i; - } - - // Don't sort "ignore" and "reset" - vector::iterator begin = character_dlg ? - langs.begin() + 2 : langs.begin(); - - std::sort(begin, langs.end(), Sorter()); - - return langs; -} - - -docstring const browseFile(docstring const & filename, - docstring const & title, - FileFilterList const & filters, - bool save, - pair const & dir1, - pair const & dir2) -{ - docstring lastPath = from_ascii("."); - if (!filename.empty()) - lastPath = from_utf8(onlyPath(to_utf8(filename))); - - FileDialog fileDlg(title, LFUN_SELECT_FILE_SYNC, dir1, dir2); - - FileDialog::Result result; - - if (save) - result = fileDlg.save(lastPath, filters, - from_utf8(onlyFilename(to_utf8(filename)))); - else - result = fileDlg.open(lastPath, filters, - from_utf8(onlyFilename(to_utf8(filename)))); - - return result.second; -} - - -docstring const browseRelFile(docstring const & filename, - docstring const & refpath, - docstring const & title, - FileFilterList const & filters, - bool save, - pair const & dir1, - pair const & dir2) -{ - docstring const fname = from_utf8(makeAbsPath( - to_utf8(filename), to_utf8(refpath)).absFilename()); - - docstring const outname = browseFile(fname, title, filters, save, - dir1, dir2); - docstring const reloutname = makeRelPath(outname, refpath); - if (prefixIs(reloutname, from_ascii("../"))) - return outname; - else - return reloutname; -} - - -docstring const browseLibFile(docstring const & dir, - docstring const & name, - docstring const & ext, - docstring const & title, - FileFilterList const & filters) -{ - // FIXME UNICODE - pair const dir1(_("System files|#S#s"), - from_utf8(addName(package().system_support().absFilename(), to_utf8(dir)))); - - pair const dir2(_("User files|#U#u"), - from_utf8(addName(package().user_support().absFilename(), to_utf8(dir)))); - - docstring const result = browseFile(from_utf8( - libFileSearch(to_utf8(dir), to_utf8(name), to_utf8(ext)).absFilename()), - title, filters, false, dir1, dir2); - - // remove the extension if it is the default one - docstring noextresult; - if (from_utf8(getExtension(to_utf8(result))) == ext) - noextresult = from_utf8(removeExtension(to_utf8(result))); - else - noextresult = result; - - // remove the directory, if it is the default one - docstring const file = from_utf8(onlyFilename(to_utf8(noextresult))); - if (from_utf8(libFileSearch(to_utf8(dir), to_utf8(file), to_utf8(ext)).absFilename()) == result) - return file; - else - return noextresult; -} - - -docstring const browseDir(docstring const & pathname, - docstring const & title, - pair const & dir1, - pair const & dir2) -{ - docstring lastPath = from_ascii("."); - if (!pathname.empty()) - lastPath = from_utf8(onlyPath(to_utf8(pathname))); - - FileDialog fileDlg(title, LFUN_SELECT_FILE_SYNC, dir1, dir2); - - FileDialog::Result const result = - fileDlg.opendir(lastPath, from_utf8(onlyFilename(to_utf8(pathname)))); - - return result.second; -} - - -void rescanTexStyles() -{ - // Run rescan in user lyx directory - support::Path p(package().user_support()); - FileName const command = libFileSearch("scripts", "TeXFiles.py"); - Systemcall one; - int const status = one.startscript(Systemcall::Wait, - lyx::support::os::python() + ' ' + - quoteName(command.toFilesystemEncoding())); - if (status == 0) - return; - // FIXME UNICODE - Alert::error(_("Could not update TeX information"), - bformat(_("The script `%s' failed."), from_utf8(command.absFilename()))); -} - - -void getTexFileList(string const & filename, std::vector & list) -{ - list.clear(); - FileName const file = libFileSearch("", filename); - if (file.empty()) - return; - - list = getVectorFromString(getFileContents(file), "\n"); - - // Normalise paths like /foo//bar ==> /foo/bar - boost::RegEx regex("/{2,}"); - std::vector::iterator it = list.begin(); - std::vector::iterator end = list.end(); - for (; it != end; ++it) - *it = regex.Merge((*it), "/"); - - // remove empty items and duplicates - list.erase(std::remove(list.begin(), list.end(), ""), list.end()); - eliminate_duplicates(list); -} - -} // namespace frontend -} // namespace lyx diff --git a/src/frontends/controllers/frontend_helpers.h b/src/frontends/controllers/frontend_helpers.h deleted file mode 100644 index 03356ad67d..0000000000 --- a/src/frontends/controllers/frontend_helpers.h +++ /dev/null @@ -1,111 +0,0 @@ -// -*- C++ -*- -/** - * \file frontend_helpers.h - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * \author Herbert Voß - * - * Full author contact details are available in file CREDITS. - */ - -#ifndef FRONTEND_HELPERS_H -#define FRONTEND_HELPERS_H - -#include "support/docstring.h" - -#include -#include -#include - -namespace lyx { - -namespace support { class FileFilterList; } - -namespace frontend { - -/// -typedef std::pair LanguagePair; - -/** If the caller is the character dialog, add "No change" and "Reset" -* to the vector. -*/ -std::vector const getLanguageData(bool character_dlg); - -/** Launch a file dialog and return the chosen file. - filename: a suggested filename. - title: the title of the dialog. - pattern: *.ps etc. - dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog. -*/ -docstring const -browseFile(docstring const & filename, - docstring const & title, - support::FileFilterList const & filters, - bool save = false, - std::pair const & dir1 = - std::make_pair(docstring(), docstring()), - std::pair const & dir2 = - std::make_pair(docstring(), docstring())); - - -/** Wrapper around browseFile which tries to provide a filename - relative to relpath. If the relative path is of the form "foo.txt" - or "bar/foo.txt", then it is returned as relative. OTOH, if it is - of the form "../baz/foo.txt", an absolute path is returned. This is - intended to be useful for insets which encapsulate files/ -*/ -docstring const -browseRelFile(docstring const & filename, - docstring const & refpath, - docstring const & title, - support::FileFilterList const & filters, - bool save = false, - std::pair const & dir1 = - std::make_pair(docstring(), docstring()), - std::pair const & dir2 = - std::make_pair(docstring(), docstring())); - - -/** Wrapper around browseFile which tries to provide a filename -* relative to the user or system directory. The dir, name and ext -* parameters have the same meaning as in the -* support::LibFileSearch function. -*/ -docstring const -browseLibFile(docstring const & dir, - docstring const & name, - docstring const & ext, - docstring const & title, - support::FileFilterList const & filters); - - -/** Launch a file dialog and return the chosen directory. - pathname: a suggested pathname. - title: the title of the dialog. - dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog. -*/ -docstring const -browseDir(docstring const & pathname, - docstring const & title, - std::pair const & dir1 = - std::make_pair(docstring(), docstring()), - std::pair const & dir2 = - std::make_pair(docstring(), docstring())); - - -/** Build filelists of all availabe bst/cls/sty-files. Done through -* kpsewhich and an external script, saved in *Files.lst. -*/ -void rescanTexStyles(); - -/** Fill \c contents from one of the three texfiles. - * Each entry in the file list is returned as a name_with_path - */ -void getTexFileList(std::string const & filename, std::vector & contents); - -} // namespace frontend -} // namespace lyx - -#endif // FRONTEND_HELPERS_H diff --git a/src/frontends/frontend_helpers.cpp b/src/frontends/frontend_helpers.cpp new file mode 100644 index 0000000000..bf319d488d --- /dev/null +++ b/src/frontends/frontend_helpers.cpp @@ -0,0 +1,245 @@ +/** + * \file frontend_helpers.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * \author Herbert Voß + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "frontend_helpers.h" + +#include "gettext.h" +#include "Language.h" + +#include "frontends/FileDialog.h" +#include "frontends/alert.h" + +#include "support/filetools.h" +#include "support/lstrings.h" +#include "support/lyxalgo.h" +#include "support/os.h" +#include "support/Package.h" +#include "support/Path.h" +#include "support/Systemcall.h" + +#include + +#include +#include + +using std::string; +using std::vector; +using std::pair; +using std::endl; + +namespace lyx { +namespace frontend { + +using support::addName; +using support::bformat; +using support::FileFilterList; +using support::FileName; +using support::getExtension; +using support::getFileContents; +using support::getVectorFromString; +using support::libFileSearch; +using support::makeAbsPath; +using support::makeRelPath; +using support::onlyFilename; +using support::onlyPath; +using support::package; +using support::prefixIs; +using support::quoteName; +using support::removeExtension; +using support::Systemcall; +using support::token; + + +namespace { + +struct Sorter +{ + bool operator()(LanguagePair const & lhs, LanguagePair const & rhs) const { + return lhs.first < rhs.first; + } +}; + + +} // namespace anon + + +vector const getLanguageData(bool character_dlg) +{ + vector::size_type const size = character_dlg ? + languages.size() + 2 : languages.size(); + + vector langs(size); + + if (character_dlg) { + langs[0].first = _("No change"); + langs[0].second = "ignore"; + langs[1].first = _("Reset"); + langs[1].second = "reset"; + } + + vector::size_type i = character_dlg ? 2 : 0; + for (Languages::const_iterator cit = languages.begin(); + cit != languages.end(); ++cit) { + langs[i].first = _(cit->second.display()); + langs[i].second = cit->second.lang(); + ++i; + } + + // Don't sort "ignore" and "reset" + vector::iterator begin = character_dlg ? + langs.begin() + 2 : langs.begin(); + + std::sort(begin, langs.end(), Sorter()); + + return langs; +} + + +docstring const browseFile(docstring const & filename, + docstring const & title, + FileFilterList const & filters, + bool save, + pair const & dir1, + pair const & dir2) +{ + docstring lastPath = from_ascii("."); + if (!filename.empty()) + lastPath = from_utf8(onlyPath(to_utf8(filename))); + + FileDialog fileDlg(title, LFUN_SELECT_FILE_SYNC, dir1, dir2); + + FileDialog::Result result; + + if (save) + result = fileDlg.save(lastPath, filters, + from_utf8(onlyFilename(to_utf8(filename)))); + else + result = fileDlg.open(lastPath, filters, + from_utf8(onlyFilename(to_utf8(filename)))); + + return result.second; +} + + +docstring const browseRelFile(docstring const & filename, + docstring const & refpath, + docstring const & title, + FileFilterList const & filters, + bool save, + pair const & dir1, + pair const & dir2) +{ + docstring const fname = from_utf8(makeAbsPath( + to_utf8(filename), to_utf8(refpath)).absFilename()); + + docstring const outname = browseFile(fname, title, filters, save, + dir1, dir2); + docstring const reloutname = makeRelPath(outname, refpath); + if (prefixIs(reloutname, from_ascii("../"))) + return outname; + else + return reloutname; +} + + +docstring const browseLibFile(docstring const & dir, + docstring const & name, + docstring const & ext, + docstring const & title, + FileFilterList const & filters) +{ + // FIXME UNICODE + pair const dir1(_("System files|#S#s"), + from_utf8(addName(package().system_support().absFilename(), to_utf8(dir)))); + + pair const dir2(_("User files|#U#u"), + from_utf8(addName(package().user_support().absFilename(), to_utf8(dir)))); + + docstring const result = browseFile(from_utf8( + libFileSearch(to_utf8(dir), to_utf8(name), to_utf8(ext)).absFilename()), + title, filters, false, dir1, dir2); + + // remove the extension if it is the default one + docstring noextresult; + if (from_utf8(getExtension(to_utf8(result))) == ext) + noextresult = from_utf8(removeExtension(to_utf8(result))); + else + noextresult = result; + + // remove the directory, if it is the default one + docstring const file = from_utf8(onlyFilename(to_utf8(noextresult))); + if (from_utf8(libFileSearch(to_utf8(dir), to_utf8(file), to_utf8(ext)).absFilename()) == result) + return file; + else + return noextresult; +} + + +docstring const browseDir(docstring const & pathname, + docstring const & title, + pair const & dir1, + pair const & dir2) +{ + docstring lastPath = from_ascii("."); + if (!pathname.empty()) + lastPath = from_utf8(onlyPath(to_utf8(pathname))); + + FileDialog fileDlg(title, LFUN_SELECT_FILE_SYNC, dir1, dir2); + + FileDialog::Result const result = + fileDlg.opendir(lastPath, from_utf8(onlyFilename(to_utf8(pathname)))); + + return result.second; +} + + +void rescanTexStyles() +{ + // Run rescan in user lyx directory + support::Path p(package().user_support()); + FileName const command = libFileSearch("scripts", "TeXFiles.py"); + Systemcall one; + int const status = one.startscript(Systemcall::Wait, + lyx::support::os::python() + ' ' + + quoteName(command.toFilesystemEncoding())); + if (status == 0) + return; + // FIXME UNICODE + Alert::error(_("Could not update TeX information"), + bformat(_("The script `%s' failed."), from_utf8(command.absFilename()))); +} + + +void getTexFileList(string const & filename, std::vector & list) +{ + list.clear(); + FileName const file = libFileSearch("", filename); + if (file.empty()) + return; + + list = getVectorFromString(getFileContents(file), "\n"); + + // Normalise paths like /foo//bar ==> /foo/bar + boost::RegEx regex("/{2,}"); + std::vector::iterator it = list.begin(); + std::vector::iterator end = list.end(); + for (; it != end; ++it) + *it = regex.Merge((*it), "/"); + + // remove empty items and duplicates + list.erase(std::remove(list.begin(), list.end(), ""), list.end()); + eliminate_duplicates(list); +} + +} // namespace frontend +} // namespace lyx diff --git a/src/frontends/frontend_helpers.h b/src/frontends/frontend_helpers.h new file mode 100644 index 0000000000..03356ad67d --- /dev/null +++ b/src/frontends/frontend_helpers.h @@ -0,0 +1,111 @@ +// -*- C++ -*- +/** + * \file frontend_helpers.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * \author Herbert Voß + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef FRONTEND_HELPERS_H +#define FRONTEND_HELPERS_H + +#include "support/docstring.h" + +#include +#include +#include + +namespace lyx { + +namespace support { class FileFilterList; } + +namespace frontend { + +/// +typedef std::pair LanguagePair; + +/** If the caller is the character dialog, add "No change" and "Reset" +* to the vector. +*/ +std::vector const getLanguageData(bool character_dlg); + +/** Launch a file dialog and return the chosen file. + filename: a suggested filename. + title: the title of the dialog. + pattern: *.ps etc. + dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog. +*/ +docstring const +browseFile(docstring const & filename, + docstring const & title, + support::FileFilterList const & filters, + bool save = false, + std::pair const & dir1 = + std::make_pair(docstring(), docstring()), + std::pair const & dir2 = + std::make_pair(docstring(), docstring())); + + +/** Wrapper around browseFile which tries to provide a filename + relative to relpath. If the relative path is of the form "foo.txt" + or "bar/foo.txt", then it is returned as relative. OTOH, if it is + of the form "../baz/foo.txt", an absolute path is returned. This is + intended to be useful for insets which encapsulate files/ +*/ +docstring const +browseRelFile(docstring const & filename, + docstring const & refpath, + docstring const & title, + support::FileFilterList const & filters, + bool save = false, + std::pair const & dir1 = + std::make_pair(docstring(), docstring()), + std::pair const & dir2 = + std::make_pair(docstring(), docstring())); + + +/** Wrapper around browseFile which tries to provide a filename +* relative to the user or system directory. The dir, name and ext +* parameters have the same meaning as in the +* support::LibFileSearch function. +*/ +docstring const +browseLibFile(docstring const & dir, + docstring const & name, + docstring const & ext, + docstring const & title, + support::FileFilterList const & filters); + + +/** Launch a file dialog and return the chosen directory. + pathname: a suggested pathname. + title: the title of the dialog. + dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog. +*/ +docstring const +browseDir(docstring const & pathname, + docstring const & title, + std::pair const & dir1 = + std::make_pair(docstring(), docstring()), + std::pair const & dir2 = + std::make_pair(docstring(), docstring())); + + +/** Build filelists of all availabe bst/cls/sty-files. Done through +* kpsewhich and an external script, saved in *Files.lst. +*/ +void rescanTexStyles(); + +/** Fill \c contents from one of the three texfiles. + * Each entry in the file list is returned as a name_with_path + */ +void getTexFileList(std::string const & filename, std::vector & contents); + +} // namespace frontend +} // namespace lyx + +#endif // FRONTEND_HELPERS_H diff --git a/src/frontends/qt4/GuiBibitem.h b/src/frontends/qt4/GuiBibitem.h index 5429fef806..489f86af28 100644 --- a/src/frontends/qt4/GuiBibitem.h +++ b/src/frontends/qt4/GuiBibitem.h @@ -16,8 +16,6 @@ #include "GuiDialog.h" #include "ui_BibitemUi.h" -#include "controllers/Dialog.h" - #include "insets/InsetCommandParams.h" namespace lyx {