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)