From 4daf7b5dfc3ee2372124a75437d17fe9cd5c5f08 Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Mon, 6 Apr 2009 12:12:06 +0000 Subject: [PATCH] The Buffer::dispatch() patch. This patch enhances the Buffer::dispatch() method to make it a full-fledged member of the dispatch sequence. The most immediate payoff is that LFUNs that are handled in Buffer::dispatch() can be used from the command line. We make better use of the DispatchResult object and return error information through it, rather than using return values. (This was JMarc's suggestion.) We also introduce a corresponding Buffer::getStatus() method, and modify BufferView::getStatus() to return a flag indicating whether a decision has been made, as is already done in some other cases. Finally, some LFUNs are moved to Buffer::dispatch(), including LFUN_BUFFER_PRINT. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@29125 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/Buffer.cpp | 192 ++++++++++++++++++++++++++++++++++++++++--- src/Buffer.h | 14 +++- src/BufferView.cpp | 32 ++------ src/BufferView.h | 4 +- src/DispatchResult.h | 16 +++- src/LyX.cpp | 6 +- src/LyXFunc.cpp | 140 ++++--------------------------- 7 files changed, 235 insertions(+), 169 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index a4d78be6b5..43d5c236b2 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -24,12 +24,14 @@ #include "Chktex.h" #include "Converter.h" #include "Counters.h" +#include "DispatchResult.h" #include "DocIterator.h" #include "Encoding.h" #include "ErrorList.h" #include "Exporter.h" #include "Format.h" #include "FuncRequest.h" +#include "FuncStatus.h" #include "InsetIterator.h" #include "InsetList.h" #include "Language.h" @@ -94,6 +96,7 @@ #include "support/os.h" #include "support/Package.h" #include "support/Path.h" +#include "support/Systemcall.h" #include "support/textutils.h" #include "support/types.h" @@ -126,6 +129,14 @@ int const LYX_FORMAT = 349; // jspitzm: initial XeTeX support typedef map DepClean; typedef map > RefCache; +void showPrintError(string const & name) +{ + docstring str = bformat(_("Could not print the document %1$s.\n" + "Check that your printer is set up correctly."), + makeDisplayPath(name, 50)); + Alert::error(_("Print document failed"), str); +} + } // namespace anon class BufferSet : public std::set {}; @@ -1506,21 +1517,61 @@ void Buffer::markDepClean(string const & name) } -bool Buffer::dispatch(string const & command, bool * result) +bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) +{ + switch (cmd.action) { + case LFUN_BUFFER_EXPORT: { + docstring const arg = cmd.argument(); + bool enable = arg == "custom" || isExportable(to_utf8(arg)); + if (!enable) + flag.message(bformat( + _("Don't know how to export to format: %1$s"), arg)); + flag.setEnabled(enable); + break; + } + + case LFUN_BRANCH_ACTIVATE: + case LFUN_BRANCH_DEACTIVATE: { + BranchList const & branchList = params().branchlist(); + docstring const branchName = cmd.argument(); + flag.setEnabled(!branchName.empty() + && branchList.find(branchName)); + break; + } + + case LFUN_BUFFER_PRINT: + // if no Buffer is present, then of course we won't be called! + flag.setEnabled(true); + break; + + default: + return false; + } + return true; +} + + +void Buffer::dispatch(string const & command, DispatchResult & result) { return dispatch(lyxaction.lookupFunc(command), result); } -bool Buffer::dispatch(FuncRequest const & func, bool * result) +// NOTE We can end up here even if we have no GUI, because we are called +// by LyX::exec to handled command-line requests. So we may need to check +// whether we have a GUI or not. The boolean use_gui holds this information. +void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) { + // We'll set this back to false if need be. bool dispatched = true; switch (func.action) { case LFUN_BUFFER_EXPORT: { - bool const tmp = doExport(to_utf8(func.argument()), false); - if (result) - *result = tmp; + bool success = doExport(to_utf8(func.argument()), false); + dr.setError(success); + if (!success) + dr.setMessage(bformat(_("Error exporting to format: %1$s."), + func.argument())); break; } @@ -1534,18 +1585,139 @@ bool Buffer::dispatch(FuncRequest const & func, bool * result) break; } Branch * branch = branchList.find(branchName); - if (!branch) + if (!branch) { LYXERR0("Branch " << branchName << " does not exist."); - else + dr.setError(true); + docstring const msg = + bformat(_("Branch \%1$s\" does not exist."), branchName); + dr.setMessage(msg); + } else { branch->setSelected(func.action == LFUN_BRANCH_ACTIVATE); - if (result) - *result = true; + dr.setError(false); + dr.update(Update::Force); + } + break; + } + + case LFUN_BUFFER_PRINT: { + // we'll assume there's a problem until we succeed + dr.setError(true); + string target = func.getArg(0); + string target_name = func.getArg(1); + string command = func.getArg(2); + + if (target.empty() + || target_name.empty() + || command.empty()) { + LYXERR0("Unable to parse " << func.argument()); + docstring const msg = + bformat(_("Unable to parse \"%1$s\""), func.argument()); + dr.setMessage(msg); + break; + } + if (target != "printer" && target != "file") { + LYXERR0("Unrecognized target \"" << target << '"'); + docstring const msg = + bformat(_("Unrecognized target \"%1$s\""), from_utf8(target)); + dr.setMessage(msg); + break; + } + + if (!doExport("dvi", true)) { + showPrintError(absFileName()); + dr.setMessage(_("Error exporting to DVI.")); + break; + } + + // Push directory path. + string const path = temppath(); + // Prevent the compiler from optimizing away p + FileName pp(path); + PathChanger p(pp); + + // there are three cases here: + // 1. we print to a file + // 2. we print directly to a printer + // 3. we print using a spool command (print to file first) + Systemcall one; + int res = 0; + string const dviname = changeExtension(latexName(true), "dvi"); + + if (target == "printer") { + if (!lyxrc.print_spool_command.empty()) { + // case 3: print using a spool + string const psname = changeExtension(dviname,".ps"); + command += ' ' + lyxrc.print_to_file + + quoteName(psname) + + ' ' + + quoteName(dviname); + + string command2 = lyxrc.print_spool_command + ' '; + if (target_name != "default") { + command2 += lyxrc.print_spool_printerprefix + + target_name + + ' '; + } + command2 += quoteName(psname); + // First run dvips. + // If successful, then spool command + res = one.startscript(Systemcall::Wait, command); + + if (res == 0) { + // If there's no GUI, we have to wait on this command. Otherwise, + // LyX deletes the temporary directory, and with it the spooled + // file, before it can be printed!! + Systemcall::Starttype stype = use_gui ? + Systemcall::DontWait : Systemcall::Wait; + res = one.startscript(stype, command2); + } + } else { + // case 2: print directly to a printer + if (target_name != "default") + command += ' ' + lyxrc.print_to_printer + target_name + ' '; + // as above.... + Systemcall::Starttype stype = use_gui ? + Systemcall::DontWait : Systemcall::Wait; + res = one.startscript(stype, command + quoteName(dviname)); + } + + } else { + // case 1: print to a file + FileName const filename(makeAbsPath(target_name, filePath())); + FileName const dvifile(makeAbsPath(dviname, path)); + if (filename.exists()) { + docstring text = bformat( + _("The file %1$s already exists.\n\n" + "Do you want to overwrite that file?"), + makeDisplayPath(filename.absFilename())); + if (Alert::prompt(_("Overwrite file?"), + text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0) + break; + } + command += ' ' + lyxrc.print_to_file + + quoteName(filename.toFilesystemEncoding()) + + ' ' + + quoteName(dvifile.toFilesystemEncoding()); + // as above.... + Systemcall::Starttype stype = use_gui ? + Systemcall::DontWait : Systemcall::Wait; + res = one.startscript(stype, command); + } + + if (res == 0) + dr.setError(false); + else { + dr.setMessage(_("Error running external commands.")); + showPrintError(absFileName()); + } + break; } default: dispatched = false; + break; } - return dispatched; + dr.dispatched(dispatched); } diff --git a/src/Buffer.h b/src/Buffer.h index 37382e5dff..43d82b6477 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -12,6 +12,8 @@ #ifndef BUFFER_H #define BUFFER_H +#include "update_flags.h" + #include "insets/InsetCode.h" #include "support/strfwd.h" @@ -27,11 +29,13 @@ namespace lyx { class BiblioInfo; class BufferParams; class BufferSet; +class DispatchResult; class DocIterator; class docstring_list; class ErrorItem; class ErrorList; class FuncRequest; +class FuncStatus; class Inset; class InsetRef; class InsetLabel; @@ -125,12 +129,16 @@ public: ~Buffer(); /** High-level interface to buffer functionality. - This function parses a command string and executes it + This function parses a command string and executes it. */ - bool dispatch(std::string const & command, bool * result = 0); + void dispatch(std::string const & command, DispatchResult & result); /// Maybe we know the function already by number... - bool dispatch(FuncRequest const & func, bool * result = 0); + void dispatch(FuncRequest const & func, DispatchResult & result); + + /// Can this function be exectued? + /// \return true if we made a decision + bool getStatus(FuncRequest const & cmd, FuncStatus & flag); /// read a new document from a string bool readString(std::string const &); diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 566a5e94df..ca641a76bc 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -895,10 +895,8 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool recenter) } -FuncStatus BufferView::getStatus(FuncRequest const & cmd) +bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) { - FuncStatus flag; - Cursor & cur = d->cursor_; switch (cmd.action) { @@ -916,6 +914,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) // FIXME: Actually, these LFUNS should be moved to Text flag.setEnabled(cur.inTexted()); break; + case LFUN_FONT_STATE: case LFUN_LABEL_INSERT: case LFUN_INFO_INSERT: @@ -1049,29 +1048,18 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) } case LFUN_DIALOG_SHOW_NEW_INSET: + if (cur.inset().lyxCode() == CAPTION_CODE) + return cur.inset().getStatus(cur, cmd, flag); flag.setEnabled(cur.inset().lyxCode() != ERT_CODE && cur.inset().lyxCode() != LISTINGS_CODE); - if (cur.inset().lyxCode() == CAPTION_CODE) { - FuncStatus flag; - if (cur.inset().getStatus(cur, cmd, flag)) - return flag; - } break; - case LFUN_BRANCH_ACTIVATE: - case LFUN_BRANCH_DEACTIVATE: { - BranchList const & branchList = buffer_.params().branchlist(); - docstring const branchName = cmd.argument(); - flag.setEnabled(!branchName.empty() - && branchList.find(branchName)); - break; - } - default: flag.setEnabled(false); + return false; } - return flag; + return true; } @@ -1506,14 +1494,6 @@ bool BufferView::dispatch(FuncRequest const & cmd) break; } - case LFUN_BRANCH_ACTIVATE: - case LFUN_BRANCH_DEACTIVATE: - if (cmd.argument().empty()) - return false; - buffer_.dispatch(cmd); - processUpdateFlags(Update::Force); - break; - // This could be rewriten using some command like forall // once the insets refactoring is done. case LFUN_NOTES_MUTATE: { diff --git a/src/BufferView.h b/src/BufferView.h index b5de004c3d..6c2b53fcb6 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -195,8 +195,8 @@ public: /// translate and insert a character, using the correct keymap. void translateAndInsert(char_type c, Text * t, Cursor & cur); - /// return true for events that will handle. - FuncStatus getStatus(FuncRequest const & cmd); + /// \return true if we've made a decision + bool getStatus(FuncRequest const & cmd, FuncStatus & flag); /// execute the given function. /// \return true if the function has been processed. bool dispatch(FuncRequest const & argument); diff --git a/src/DispatchResult.h b/src/DispatchResult.h index 8cfdc3313d..5b209ff8f7 100644 --- a/src/DispatchResult.h +++ b/src/DispatchResult.h @@ -15,6 +15,8 @@ #include "update_flags.h" +#include "support/docstring.h" + namespace lyx { /// Maybe this can go entirely @@ -24,19 +26,31 @@ public: DispatchResult() : dispatched_(false), update_(Update::None) {} /// DispatchResult(bool disp, Update::flags f) : dispatched_(disp), update_(f) {} - // + /// bool dispatched() const { return dispatched_; } /// void dispatched(bool disp) { dispatched_ = disp; } /// + bool error() const { return error_; } + /// + void setError(bool e) { error_ = e; } + /// + docstring message() { return message_; } + /// + void setMessage(docstring m) { message_ = m; } + /// Update::flags update() const { return update_; } /// void update(Update::flags f) { update_ = f; } private: /// was the event fully dispatched? bool dispatched_; + /// was there an error? + bool error_; /// do we need to redraw the screen afterwards? Update::flags update_; + /// + docstring message_; }; diff --git a/src/LyX.cpp b/src/LyX.cpp index c30b1215ae..ebfedd1b81 100644 --- a/src/LyX.cpp +++ b/src/LyX.cpp @@ -311,13 +311,13 @@ int LyX::exec(int & argc, char * argv[]) Buffer * buf = *I; if (buf != buf->masterBuffer()) continue; - bool success = false; vector::const_iterator bcit = pimpl_->batch_commands.begin(); vector::const_iterator bcend = pimpl_->batch_commands.end(); + DispatchResult dr; for (; bcit != bcend; bcit++) { LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit); - buf->dispatch(*bcit, &success); - final_success |= success; + buf->dispatch(*bcit, dr); + final_success |= !dr.error(); } } prepareExit(); diff --git a/src/LyXFunc.cpp b/src/LyXFunc.cpp index 96302aef7a..d8f5e9cf4c 100644 --- a/src/LyXFunc.cpp +++ b/src/LyXFunc.cpp @@ -457,11 +457,6 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const flag.setOnOff(true); break; - case LFUN_BUFFER_EXPORT: - enable = cmd.argument() == "custom" - || buf->isExportable(to_utf8(cmd.argument())); - break; - case LFUN_BUFFER_CHKTEX: enable = buf->isLatex() && !lyxrc.chktex_command.empty(); break; @@ -632,7 +627,6 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const case LFUN_KEYMAP_TOGGLE: case LFUN_REPEAT: case LFUN_BUFFER_EXPORT_CUSTOM: - case LFUN_BUFFER_PRINT: case LFUN_PREFERENCES_SAVE: case LFUN_MESSAGE: case LFUN_INSET_EDIT: @@ -666,8 +660,7 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const if (lyx_view_->getStatus(cmd, flag)) break; - // If we have a BufferView, try cursor position and - // then the BufferView. + // If we do not have a BufferView, then other functions are disabled if (!view()) { enable = false; break; @@ -679,8 +672,13 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const && inset && inset->getStatus(view()->cursor(), cmd, flag)) break; - if (!getLocalStatus(view()->cursor(), cmd, flag)) - flag = view()->getStatus(cmd); + bool decided = getLocalStatus(view()->cursor(), cmd, flag); + if (!decided) + // try the BufferView + decided = view()->getStatus(cmd, flag); + if (!decided) + // try the Buffer + view()->buffer().getStatus(cmd, flag); } if (!enable) @@ -743,15 +741,6 @@ bool LyXFunc::ensureBufferClean(BufferView * bv) namespace { -void showPrintError(string const & name) -{ - docstring str = bformat(_("Could not print the document %1$s.\n" - "Check that your printer is set up correctly."), - makeDisplayPath(name, 50)); - Alert::error(_("Print document failed"), str); -} - - bool loadLayoutFile(string const & name, string const & buf_path) { if (!LayoutFileList::get().haveClass(name)) { @@ -956,111 +945,6 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; } - case LFUN_BUFFER_PRINT: { - LASSERT(lyx_view_ && buffer, /**/); - // FIXME: cmd.getArg() might fail if one of the arguments - // contains double quotes - string target = cmd.getArg(0); - string target_name = cmd.getArg(1); - string command = cmd.getArg(2); - - if (target.empty() - || target_name.empty() - || command.empty()) { - lyxerr << "Unable to parse \"" - << argument << '"' << endl; - break; - } - if (target != "printer" && target != "file") { - lyxerr << "Unrecognized target \"" - << target << '"' << endl; - break; - } - - if (!buffer->doExport("dvi", true)) { - showPrintError(buffer->absFileName()); - break; - } - - // Push directory path. - string const path = buffer->temppath(); - // Prevent the compiler from optimizing away p - FileName pp(path); - PathChanger p(pp); - - // there are three cases here: - // 1. we print to a file - // 2. we print directly to a printer - // 3. we print using a spool command (print to file first) - Systemcall one; - int res = 0; - string const dviname = - changeExtension(buffer->latexName(true), "dvi"); - - if (target == "printer") { - if (!lyxrc.print_spool_command.empty()) { - // case 3: print using a spool - string const psname = - changeExtension(dviname,".ps"); - command += ' ' + lyxrc.print_to_file - + quoteName(psname) - + ' ' - + quoteName(dviname); - - string command2 = - lyxrc.print_spool_command + ' '; - if (target_name != "default") { - command2 += lyxrc.print_spool_printerprefix - + target_name - + ' '; - } - command2 += quoteName(psname); - // First run dvips. - // If successful, then spool command - res = one.startscript( - Systemcall::Wait, - command); - - if (res == 0) - res = one.startscript( - Systemcall::DontWait, - command2); - } else { - // case 2: print directly to a printer - if (target_name != "default") - command += ' ' + lyxrc.print_to_printer + target_name + ' '; - res = one.startscript( - Systemcall::DontWait, - command + quoteName(dviname)); - } - - } else { - // case 1: print to a file - FileName const filename(makeAbsPath(target_name, - buffer->filePath())); - FileName const dvifile(makeAbsPath(dviname, path)); - if (filename.exists()) { - docstring text = bformat( - _("The file %1$s already exists.\n\n" - "Do you want to overwrite that file?"), - makeDisplayPath(filename.absFilename())); - if (Alert::prompt(_("Overwrite file?"), - text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0) - break; - } - command += ' ' + lyxrc.print_to_file - + quoteName(filename.toFilesystemEncoding()) - + ' ' - + quoteName(dvifile.toFilesystemEncoding()); - res = one.startscript(Systemcall::DontWait, - command); - } - - if (res != 0) - showPrintError(buffer->absFileName()); - break; - } - // FIXME: There is need for a command-line import. /* case LFUN_BUFFER_IMPORT: @@ -1725,6 +1609,14 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; } + // OK, so try the Buffer itself + DispatchResult dr; + view()->buffer().dispatch(cmd, dr); + if (dr.dispatched()) { + updateFlags = dr.update(); + break; + } + // Is this a function that acts on inset at point? Inset * inset = view()->cursor().nextInset(); if (lyxaction.funcHasFlag(action, LyXAction::AtPoint) -- 2.39.2