3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
24 #include "BranchList.h"
26 #include "buffer_funcs.h"
27 #include "bufferlist.h"
28 #include "bufferparams.h"
29 #include "BufferView.h"
31 #include "CutAndPaste.h"
33 #include "dispatchresult.h"
35 #include "errorlist.h"
38 #include "funcrequest.h"
41 #include "insetiterator.h"
47 #include "LyXAction.h"
52 #include "lyxserver.h"
53 #include "lyxtextclasslist.h"
55 #include "paragraph.h"
56 #include "pariterator.h"
57 #include "ParagraphParameters.h"
60 #include "insets/insetbox.h"
61 #include "insets/insetbranch.h"
62 #include "insets/insetcommand.h"
63 #include "insets/insetert.h"
64 #include "insets/insetexternal.h"
65 #include "insets/insetfloat.h"
66 #include "insets/insetgraphics.h"
67 #include "insets/insetinclude.h"
68 #include "insets/insetnote.h"
69 #include "insets/insettabular.h"
70 #include "insets/insetvspace.h"
71 #include "insets/insetwrap.h"
73 #include "frontends/Alert.h"
74 #include "frontends/Dialogs.h"
75 #include "frontends/FileDialog.h"
76 #include "frontends/lyx_gui.h"
77 #include "frontends/LyXKeySym.h"
78 #include "frontends/LyXView.h"
79 #include "frontends/Menubar.h"
80 #include "frontends/Toolbars.h"
82 #include "support/environment.h"
83 #include "support/filefilterlist.h"
84 #include "support/filetools.h"
85 #include "support/forkedcontr.h"
86 #include "support/fs_extras.h"
87 #include "support/lstrings.h"
88 #include "support/path.h"
89 #include "support/package.h"
90 #include "support/systemcall.h"
91 #include "support/convert.h"
92 #include "support/os.h"
94 #include <boost/current_function.hpp>
95 #include <boost/filesystem/operations.hpp>
99 using bv_funcs::freefont2string;
101 using lyx::support::AbsolutePath;
102 using lyx::support::AddName;
103 using lyx::support::AddPath;
104 using lyx::support::bformat;
105 using lyx::support::ChangeExtension;
106 using lyx::support::contains;
107 using lyx::support::FileFilterList;
108 using lyx::support::FileSearch;
109 using lyx::support::ForkedcallsController;
110 using lyx::support::i18nLibFileSearch;
111 using lyx::support::IsDirWriteable;
112 using lyx::support::IsFileReadable;
113 using lyx::support::isStrInt;
114 using lyx::support::MakeAbsPath;
115 using lyx::support::MakeDisplayPath;
116 using lyx::support::package;
117 using lyx::support::Path;
118 using lyx::support::QuoteName;
119 using lyx::support::rtrim;
120 using lyx::support::split;
121 using lyx::support::subst;
122 using lyx::support::Systemcall;
123 using lyx::support::token;
124 using lyx::support::trim;
125 using lyx::support::prefixIs;
128 using std::make_pair;
131 using std::istringstream;
133 namespace biblio = lyx::biblio;
134 namespace fs = boost::filesystem;
137 extern BufferList bufferlist;
138 extern LyXServer * lyxserver;
140 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
143 extern tex_accent_struct get_accent(kb_action action);
148 bool getStatus(LCursor cursor,
149 FuncRequest const & cmd, FuncStatus & status)
151 // Try to fix cursor in case it is broken.
152 cursor.fixIfBroken();
154 // This is, of course, a mess. Better create a new doc iterator and use
155 // this in Inset::getStatus. This might require an additional
156 // BufferView * arg, though (which should be avoided)
157 //LCursor safe = *this;
159 for ( ; cursor.depth(); cursor.pop()) {
160 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
161 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
162 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
163 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
165 // The inset's getStatus() will return 'true' if it made
166 // a definitive decision on whether it want to handle the
167 // request or not. The result of this decision is put into
168 // the 'status' parameter.
169 if (cursor.inset().getStatus(cursor, cmd, status)) {
178 /** Return the change status at cursor position, taking in account the
179 * status at each level of the document iterator (a table in a deleted
180 * footnote is deleted).
181 * When \param outer is true, the top slice is not looked at.
183 Change::Type lookupChange(DocIterator const & dit, bool outer = false)
185 size_t const depth = dit.depth() - (outer ? 1 : 0);
187 for (size_t i = 0 ; i < depth ; ++i) {
188 CursorSlice const & slice = dit[i];
189 if (!slice.inset().inMathed()
190 && slice.pos() < slice.paragraph().size()) {
191 Change::Type const ch = slice.paragraph().lookupChange(slice.pos());
192 if (ch != Change::UNCHANGED)
196 return Change::UNCHANGED;
201 LyXFunc::LyXFunc(LyXView * lv)
204 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
205 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
206 meta_fake_bit(key_modifier::none)
211 void LyXFunc::handleKeyFunc(kb_action action)
213 char c = encoded_last_key;
215 if (keyseq.length()) {
219 owner->getIntl().getTransManager()
220 .deadkey(c, get_accent(action).accent, view()->getLyXText());
221 // Need to clear, in case the minibuffer calls these
224 // copied verbatim from do_accent_char
225 view()->cursor().resetAnchor();
230 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
232 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
234 // Do nothing if we have nothing (JMarc)
235 if (!keysym->isOK()) {
236 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
241 if (keysym->isModifier()) {
242 lyxerr[Debug::KEY] << "isModifier true" << endl;
246 Encoding const * encoding = view()->cursor().getEncoding();
248 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
250 // Do a one-deep top-level lookup for
251 // cancel and meta-fake keys. RVDK_PATCH_5
252 cancel_meta_seq.reset();
254 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
255 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
256 << " action first set to [" << func.action << ']'
259 // When not cancel or meta-fake, do the normal lookup.
260 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
261 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
262 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
263 // remove Caps Lock and Mod2 as a modifiers
264 func = keyseq.addkey(keysym, (state | meta_fake_bit));
265 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
266 << "action now set to ["
267 << func.action << ']' << endl;
270 // Dont remove this unless you know what you are doing.
271 meta_fake_bit = key_modifier::none;
273 // Can this happen now ?
274 if (func.action == LFUN_NOACTION) {
275 func = FuncRequest(LFUN_PREFIX);
278 if (lyxerr.debugging(Debug::KEY)) {
279 lyxerr << BOOST_CURRENT_FUNCTION
281 << func.action << "]["
282 << keyseq.print() << ']'
286 // already here we know if it any point in going further
287 // why not return already here if action == -1 and
288 // num_bytes == 0? (Lgb)
290 if (keyseq.length() > 1) {
291 owner->message(keyseq.print());
295 // Maybe user can only reach the key via holding down shift.
296 // Let's see. But only if shift is the only modifier
297 if (func.action == LFUN_UNKNOWN_ACTION &&
298 state == key_modifier::shift) {
299 lyxerr[Debug::KEY] << "Trying without shift" << endl;
300 func = keyseq.addkey(keysym, key_modifier::none);
301 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
304 if (func.action == LFUN_UNKNOWN_ACTION) {
305 // Hmm, we didn't match any of the keysequences. See
306 // if it's normal insertable text not already covered
308 if (keysym->isText() && keyseq.length() == 1) {
309 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
310 func = FuncRequest(LFUN_SELFINSERT);
312 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
313 owner->message(_("Unknown function."));
318 if (func.action == LFUN_SELFINSERT) {
319 if (encoded_last_key != 0) {
320 string const arg(1, encoded_last_key);
321 dispatch(FuncRequest(LFUN_SELFINSERT, arg));
323 << "SelfInsert arg[`" << arg << "']" << endl;
331 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
333 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
335 LCursor & cur = view()->cursor();
337 /* In LyX/Mac, when a dialog is open, the menus of the
338 application can still be accessed without giving focus to
339 the main window. In this case, we want to disable the menu
340 entries that are buffer-related.
342 Note that this code is not perfect, as bug 1941 attests:
343 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
346 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
349 buf = owner->buffer();
351 if (cmd.action == LFUN_NOACTION) {
352 flag.message(N_("Nothing to do"));
357 switch (cmd.action) {
358 case LFUN_UNKNOWN_ACTION:
359 #ifndef HAVE_LIBAIKSAURUS
360 case LFUN_THESAURUS_ENTRY:
366 flag |= lyx_gui::getStatus(cmd);
369 if (flag.unknown()) {
370 flag.message(N_("Unknown action"));
374 if (!flag.enabled()) {
375 if (flag.message().empty())
376 flag.message(N_("Command disabled"));
380 // Check whether we need a buffer
381 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
383 flag.message(N_("Command not allowed with"
384 "out any document open"));
389 // I would really like to avoid having this switch and rather try to
390 // encode this in the function itself.
391 // -- And I'd rather let an inset decide which LFUNs it is willing
392 // to handle (Andre')
394 switch (cmd.action) {
395 case LFUN_TOOLTIPS_TOGGLE:
396 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
399 case LFUN_READ_ONLY_TOGGLE:
400 flag.setOnOff(buf->isReadonly());
403 case LFUN_SWITCHBUFFER:
404 // toggle on the current buffer, but do not toggle off
405 // the other ones (is that a good idea?)
406 if (cmd.argument == buf->fileName())
411 enable = cmd.argument == "custom"
412 || Exporter::IsExportable(*buf, cmd.argument);
416 enable = cur.selection();
420 enable = buf->isLatex() && lyxrc.chktex_command != "none";
424 enable = Exporter::IsExportable(*buf, "program");
427 case LFUN_LAYOUT_TABULAR:
428 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
432 case LFUN_LAYOUT_PARAGRAPH:
433 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
436 case LFUN_VC_REGISTER:
437 enable = !buf->lyxvc().inUse();
439 case LFUN_VC_CHECKIN:
440 enable = buf->lyxvc().inUse() && !buf->isReadonly();
442 case LFUN_VC_CHECKOUT:
443 enable = buf->lyxvc().inUse() && buf->isReadonly();
447 enable = buf->lyxvc().inUse();
449 case LFUN_MENURELOAD:
450 enable = !buf->isUnnamed() && !buf->isClean();
453 case LFUN_INSET_SETTINGS: {
457 InsetBase::Code code = cur.inset().lyxCode();
459 case InsetBase::TABULAR_CODE:
460 enable = cmd.argument == "tabular";
462 case InsetBase::ERT_CODE:
463 enable = cmd.argument == "ert";
465 case InsetBase::FLOAT_CODE:
466 enable = cmd.argument == "float";
468 case InsetBase::WRAP_CODE:
469 enable = cmd.argument == "wrap";
471 case InsetBase::NOTE_CODE:
472 enable = cmd.argument == "note";
474 case InsetBase::BRANCH_CODE:
475 enable = cmd.argument == "branch";
477 case InsetBase::BOX_CODE:
478 enable = cmd.argument == "box";
486 case LFUN_INSET_APPLY: {
487 string const name = cmd.getArg(0);
488 InsetBase * inset = owner->getDialogs().getOpenInset(name);
490 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
492 bool const success = inset->getStatus(cur, fr, fs);
493 // Every inset is supposed to handle this
494 BOOST_ASSERT(success);
497 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
498 flag |= getStatus(fr);
500 enable = flag.enabled();
504 case LFUN_DIALOG_SHOW: {
505 string const name = cmd.getArg(0);
507 enable = name == "aboutlyx"
511 || name == "texinfo";
512 else if (name == "print")
513 enable = Exporter::IsExportable(*buf, "dvi")
514 && lyxrc.print_command != "none";
515 else if (name == "character" || name == "mathpanel")
516 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
517 else if (name == "latexlog")
518 enable = IsFileReadable(buf->getLogName().second);
519 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
520 else if (name == "spellchecker")
523 else if (name == "vclog")
524 enable = buf->lyxvc().inUse();
528 case LFUN_DIALOG_SHOW_NEW_INSET:
529 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
532 case LFUN_DIALOG_UPDATE: {
533 string const name = cmd.getArg(0);
535 enable = name == "prefs";
539 // this one is difficult to get right. As a half-baked
540 // solution, we consider only the first action of the sequence
541 case LFUN_SEQUENCE: {
542 // argument contains ';'-terminated commands
543 string const firstcmd = token(cmd.argument, ';', 0);
544 FuncRequest func(lyxaction.lookupFunc(firstcmd));
545 func.origin = cmd.origin;
546 flag = getStatus(func);
550 case LFUN_MENUNEWTMPLT:
551 case LFUN_WORDFINDFORWARD:
552 case LFUN_WORDFINDBACKWARD:
554 case LFUN_EXEC_COMMAND:
557 case LFUN_CLOSEBUFFER:
566 case LFUN_RECONFIGURE:
570 case LFUN_DROP_LAYOUTS_CHOICE:
571 case LFUN_MENU_OPEN_BY_NAME:
574 case LFUN_GOTOFILEROW:
575 case LFUN_DIALOG_SHOW_NEXT_INSET:
576 case LFUN_DIALOG_HIDE:
577 case LFUN_DIALOG_DISCONNECT_INSET:
579 case LFUN_TOGGLECURSORFOLLOW:
583 case LFUN_KMAP_TOGGLE:
585 case LFUN_EXPORT_CUSTOM:
587 case LFUN_SAVEPREFERENCES:
588 case LFUN_SCREEN_FONT_UPDATE:
591 case LFUN_EXTERNAL_EDIT:
592 case LFUN_GRAPHICS_EDIT:
593 case LFUN_ALL_INSETS_TOGGLE:
594 case LFUN_LANGUAGE_BUFFER:
595 case LFUN_TEXTCLASS_APPLY:
596 case LFUN_TEXTCLASS_LOAD:
597 case LFUN_SAVE_AS_DEFAULT:
598 case LFUN_BUFFERPARAMS_APPLY:
599 case LFUN_LYXRC_APPLY:
600 case LFUN_NEXTBUFFER:
601 case LFUN_PREVIOUSBUFFER:
602 // these are handled in our dispatch()
607 if (!::getStatus(cur, cmd, flag))
608 flag = view()->getStatus(cmd);
614 // Can we use a readonly buffer?
615 if (buf && buf->isReadonly()
616 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
617 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
618 flag.message(N_("Document is read-only"));
622 // Are we in a DELETED change-tracking region?
623 if (buf && buf->params().tracking_changes
624 && lookupChange(cur, true) == Change::DELETED
625 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
626 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
627 flag.message(N_("This portion of the document is deleted."));
631 // the default error message if we disable the command
632 if (!flag.enabled() && flag.message().empty())
633 flag.message(N_("Command disabled"));
641 bool ensureBufferClean(BufferView * bv)
643 Buffer & buf = *bv->buffer();
647 string const file = MakeDisplayPath(buf.fileName(), 30);
648 string text = bformat(_("The document %1$s has unsaved "
649 "changes.\n\nDo you want to save "
650 "the document?"), file);
651 int const ret = Alert::prompt(_("Save changed document?"),
652 text, 0, 1, _("&Save"),
656 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
658 return buf.isClean();
662 void showPrintError(string const & name)
664 string str = bformat(_("Could not print the document %1$s.\n"
665 "Check that your printer is set up correctly."),
666 MakeDisplayPath(name, 50));
667 Alert::error(_("Print document failed"), str);
671 void loadTextclass(string const & name)
673 std::pair<bool, lyx::textclass_type> const tc_pair =
674 textclasslist.NumberOfClass(name);
676 if (!tc_pair.first) {
677 lyxerr << "Document class \"" << name
678 << "\" does not exist."
683 lyx::textclass_type const tc = tc_pair.second;
685 if (!textclasslist[tc].load()) {
686 string s = bformat(_("The document could not be converted\n"
687 "into the document class %1$s."),
688 textclasslist[tc].name());
689 Alert::error(_("Could not change class"), s);
694 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
699 void LyXFunc::dispatch(FuncRequest const & cmd)
701 BOOST_ASSERT(view());
702 string const argument = cmd.argument;
703 kb_action const action = cmd.action;
705 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
706 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
708 // we have not done anything wrong yet.
710 dispatch_buffer.erase();
714 FuncStatus const flag = getStatus(cmd);
715 if (!flag.enabled()) {
716 // We cannot use this function here
717 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
718 << lyxaction.getActionName(action)
719 << " [" << action << "] is disabled at this location"
721 setErrorMessage(flag.message());
724 if (view()->available())
725 view()->hideCursor();
729 case LFUN_WORDFINDFORWARD:
730 case LFUN_WORDFINDBACKWARD: {
731 static string last_search;
732 string searched_string;
734 if (!argument.empty()) {
735 last_search = argument;
736 searched_string = argument;
738 searched_string = last_search;
741 if (searched_string.empty())
744 bool const fw = action == LFUN_WORDFINDFORWARD;
746 lyx::find::find2string(searched_string, true, false, fw);
747 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
752 owner->message(keyseq.printOptions());
755 case LFUN_EXEC_COMMAND:
756 owner->getToolbars().display("minibuffer", true);
757 owner->focus_command_buffer();
762 meta_fake_bit = key_modifier::none;
763 if (view()->available())
764 // cancel any selection
765 dispatch(FuncRequest(LFUN_MARK_OFF));
766 setMessage(N_("Cancel"));
770 meta_fake_bit = key_modifier::alt;
771 setMessage(keyseq.print());
774 case LFUN_READ_ONLY_TOGGLE:
775 if (owner->buffer()->lyxvc().inUse())
776 owner->buffer()->lyxvc().toggleReadOnly();
778 owner->buffer()->setReadonly(
779 !owner->buffer()->isReadonly());
782 // --- Menus -----------------------------------------------
784 menuNew(argument, false);
787 case LFUN_MENUNEWTMPLT:
788 menuNew(argument, true);
791 case LFUN_CLOSEBUFFER:
796 if (!owner->buffer()->isUnnamed()) {
797 string const str = bformat(_("Saving document %1$s..."),
798 MakeDisplayPath(owner->buffer()->fileName()));
800 MenuWrite(owner->buffer());
801 owner->message(str + _(" done."));
803 WriteAs(owner->buffer());
807 WriteAs(owner->buffer(), argument);
810 case LFUN_MENURELOAD: {
811 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
812 string text = bformat(_("Any changes will be lost. Are you sure "
813 "you want to revert to the saved version of the document %1$s?"), file);
814 int const ret = Alert::prompt(_("Revert to saved document?"),
815 text, 0, 1, _("&Revert"), _("&Cancel"));
823 Exporter::Export(owner->buffer(), argument, true);
824 view()->showErrorList(BufferFormat(*owner->buffer()));
828 Exporter::Preview(owner->buffer(), argument);
829 view()->showErrorList(BufferFormat(*owner->buffer()));
833 Exporter::Export(owner->buffer(), "program", true);
834 view()->showErrorList(_("Build"));
838 owner->buffer()->runChktex();
839 view()->showErrorList(_("ChkTeX"));
843 if (argument == "custom")
844 owner->getDialogs().show("sendto");
846 Exporter::Export(owner->buffer(), argument, false);
847 view()->showErrorList(BufferFormat(*owner->buffer()));
851 case LFUN_EXPORT_CUSTOM: {
853 string command = split(argument, format_name, ' ');
854 Format const * format = formats.getFormat(format_name);
856 lyxerr << "Format \"" << format_name
857 << "\" not recognized!"
862 Buffer * buffer = owner->buffer();
864 // The name of the file created by the conversion process
867 // Output to filename
868 if (format->name() == "lyx") {
869 string const latexname =
870 buffer->getLatexName(false);
871 filename = ChangeExtension(latexname,
872 format->extension());
873 filename = AddName(buffer->temppath(), filename);
875 if (!buffer->writeFile(filename))
879 Exporter::Export(buffer, format_name, true,
883 // Substitute $$FName for filename
884 if (!contains(command, "$$FName"))
885 command = "( " + command + " ) < $$FName";
886 command = subst(command, "$$FName", filename);
888 // Execute the command in the background
890 call.startscript(Systemcall::DontWait, command);
897 string command = split(split(argument, target, ' '),
901 || target_name.empty()
902 || command.empty()) {
903 lyxerr << "Unable to parse \""
904 << argument << '"' << std::endl;
907 if (target != "printer" && target != "file") {
908 lyxerr << "Unrecognized target \""
909 << target << '"' << std::endl;
913 Buffer * buffer = owner->buffer();
915 if (!Exporter::Export(buffer, "dvi", true)) {
916 showPrintError(buffer->fileName());
920 // Push directory path.
921 string const path = buffer->temppath();
924 // there are three cases here:
925 // 1. we print to a file
926 // 2. we print directly to a printer
927 // 3. we print using a spool command (print to file first)
930 string const dviname =
931 ChangeExtension(buffer->getLatexName(true),
934 if (target == "printer") {
935 if (!lyxrc.print_spool_command.empty()) {
936 // case 3: print using a spool
937 string const psname =
938 ChangeExtension(dviname,".ps");
939 command += lyxrc.print_to_file
942 + QuoteName(dviname);
945 lyxrc.print_spool_command +' ';
946 if (target_name != "default") {
947 command2 += lyxrc.print_spool_printerprefix
951 command2 += QuoteName(psname);
953 // If successful, then spool command
954 res = one.startscript(
959 res = one.startscript(
960 Systemcall::DontWait,
963 // case 2: print directly to a printer
964 res = one.startscript(
965 Systemcall::DontWait,
966 command + QuoteName(dviname));
970 // case 1: print to a file
971 command += lyxrc.print_to_file
972 + QuoteName(MakeAbsPath(target_name,
975 + QuoteName(dviname);
976 res = one.startscript(Systemcall::DontWait,
981 showPrintError(buffer->fileName());
990 QuitLyX(argument == "force");
994 InsetCommandParams p("tableofcontents");
995 string const data = InsetCommandMailer::params2string("toc", p);
996 owner->getDialogs().show("toc", data, 0);
1004 case LFUN_RECONFIGURE:
1005 Reconfigure(view());
1008 case LFUN_HELP_OPEN: {
1009 string const arg = argument;
1011 setErrorMessage(N_("Missing argument"));
1014 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1015 if (fname.empty()) {
1016 lyxerr << "LyX: unable to find documentation file `"
1017 << arg << "'. Bad installation?" << endl;
1020 owner->message(bformat(_("Opening help file %1$s..."),
1021 MakeDisplayPath(fname)));
1022 view()->loadLyXFile(fname, false);
1026 // --- version control -------------------------------
1027 case LFUN_VC_REGISTER:
1028 if (!ensureBufferClean(view()))
1030 if (!owner->buffer()->lyxvc().inUse()) {
1031 owner->buffer()->lyxvc().registrer();
1036 case LFUN_VC_CHECKIN:
1037 if (!ensureBufferClean(view()))
1039 if (owner->buffer()->lyxvc().inUse()
1040 && !owner->buffer()->isReadonly()) {
1041 owner->buffer()->lyxvc().checkIn();
1046 case LFUN_VC_CHECKOUT:
1047 if (!ensureBufferClean(view()))
1049 if (owner->buffer()->lyxvc().inUse()
1050 && owner->buffer()->isReadonly()) {
1051 owner->buffer()->lyxvc().checkOut();
1056 case LFUN_VC_REVERT:
1057 owner->buffer()->lyxvc().revert();
1062 owner->buffer()->lyxvc().undoLast();
1066 // --- buffers ----------------------------------------
1067 case LFUN_SWITCHBUFFER:
1068 view()->setBuffer(bufferlist.getBuffer(argument));
1071 case LFUN_NEXTBUFFER:
1072 view()->setBuffer(bufferlist.next(view()->buffer()));
1075 case LFUN_PREVIOUSBUFFER:
1076 view()->setBuffer(bufferlist.previous(view()->buffer()));
1080 NewFile(view(), argument);
1083 case LFUN_FILE_OPEN:
1087 case LFUN_DROP_LAYOUTS_CHOICE:
1088 owner->getToolbars().openLayoutList();
1091 case LFUN_MENU_OPEN_BY_NAME:
1092 owner->getMenubar().openByName(argument);
1095 // --- lyxserver commands ----------------------------
1097 setMessage(owner->buffer()->fileName());
1098 lyxerr[Debug::INFO] << "FNAME["
1099 << owner->buffer()->fileName()
1104 dispatch_buffer = keyseq.print();
1105 lyxserver->notifyClient(dispatch_buffer);
1108 case LFUN_GOTOFILEROW: {
1111 istringstream is(argument);
1112 is >> file_name >> row;
1113 if (prefixIs(file_name, package().temp_dir())) {
1114 // Needed by inverse dvi search. If it is a file
1115 // in tmpdir, call the apropriated function
1116 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1118 // Must replace extension of the file to be .lyx
1119 // and get full path
1120 string const s = ChangeExtension(file_name, ".lyx");
1121 // Either change buffer or load the file
1122 if (bufferlist.exists(s)) {
1123 view()->setBuffer(bufferlist.getBuffer(s));
1125 view()->loadLyXFile(s);
1129 view()->setCursorFromRow(row);
1132 // see BufferView_pimpl::center()
1133 view()->updateScrollbar();
1137 case LFUN_DIALOG_SHOW: {
1138 string const name = cmd.getArg(0);
1139 string data = trim(cmd.argument.substr(name.size()));
1141 if (name == "character") {
1142 data = freefont2string();
1144 owner->getDialogs().show("character", data);
1147 else if (name == "latexlog") {
1148 pair<Buffer::LogType, string> const logfile =
1149 owner->buffer()->getLogName();
1150 switch (logfile.first) {
1151 case Buffer::latexlog:
1154 case Buffer::buildlog:
1158 data += logfile.second;
1159 owner->getDialogs().show("log", data);
1161 else if (name == "vclog") {
1162 string const data = "vc " +
1163 owner->buffer()->lyxvc().getLogFile();
1164 owner->getDialogs().show("log", data);
1167 owner->getDialogs().show(name, data);
1171 case LFUN_DIALOG_SHOW_NEW_INSET: {
1172 string const name = cmd.getArg(0);
1173 string data = trim(cmd.argument.substr(name.size()));
1174 if (name == "bibitem" ||
1181 InsetCommandParams p(name);
1182 data = InsetCommandMailer::params2string(name, p);
1183 } else if (name == "include") {
1184 InsetCommandParams p(data);
1185 data = InsetIncludeMailer::params2string(p);
1186 } else if (name == "box") {
1187 // \c data == "Boxed" || "Frameless" etc
1188 InsetBoxParams p(data);
1189 data = InsetBoxMailer::params2string(p);
1190 } else if (name == "branch") {
1191 InsetBranchParams p;
1192 data = InsetBranchMailer::params2string(p);
1193 } else if (name == "citation") {
1194 InsetCommandParams p("cite");
1195 data = InsetCommandMailer::params2string(name, p);
1196 } else if (name == "ert") {
1197 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1198 } else if (name == "external") {
1199 InsetExternalParams p;
1200 Buffer const & buffer = *owner->buffer();
1201 data = InsetExternalMailer::params2string(p, buffer);
1202 } else if (name == "float") {
1204 data = InsetFloatMailer::params2string(p);
1205 } else if (name == "graphics") {
1206 InsetGraphicsParams p;
1207 Buffer const & buffer = *owner->buffer();
1208 data = InsetGraphicsMailer::params2string(p, buffer);
1209 } else if (name == "note") {
1211 data = InsetNoteMailer::params2string(p);
1212 } else if (name == "vspace") {
1214 data = InsetVSpaceMailer::params2string(space);
1215 } else if (name == "wrap") {
1217 data = InsetWrapMailer::params2string(p);
1219 owner->getDialogs().show(name, data, 0);
1223 case LFUN_DIALOG_SHOW_NEXT_INSET:
1226 case LFUN_DIALOG_UPDATE: {
1227 string const & name = argument;
1228 // Can only update a dialog connected to an existing inset
1229 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1231 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1232 inset->dispatch(view()->cursor(), fr);
1233 } else if (name == "paragraph") {
1234 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1235 } else if (name == "prefs") {
1236 owner->getDialogs().update(name, string());
1241 case LFUN_DIALOG_HIDE:
1242 Dialogs::hide(argument, 0);
1245 case LFUN_DIALOG_DISCONNECT_INSET:
1246 owner->getDialogs().disconnect(argument);
1249 case LFUN_CHILDOPEN: {
1250 string const filename =
1251 MakeAbsPath(argument, owner->buffer()->filePath());
1252 setMessage(N_("Opening child document ") +
1253 MakeDisplayPath(filename) + "...");
1254 view()->savePosition(0);
1255 string const parentfilename = owner->buffer()->fileName();
1256 if (bufferlist.exists(filename))
1257 view()->setBuffer(bufferlist.getBuffer(filename));
1259 view()->loadLyXFile(filename);
1260 // Set the parent name of the child document.
1261 // This makes insertion of citations and references in the child work,
1262 // when the target is in the parent or another child document.
1263 owner->buffer()->setParentName(parentfilename);
1267 case LFUN_TOGGLECURSORFOLLOW:
1268 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1272 owner->getIntl().KeyMapOn(false);
1275 case LFUN_KMAP_PRIM:
1276 owner->getIntl().KeyMapPrim();
1280 owner->getIntl().KeyMapSec();
1283 case LFUN_KMAP_TOGGLE:
1284 owner->getIntl().ToggleKeyMap();
1290 string rest = split(argument, countstr, ' ');
1291 istringstream is(countstr);
1294 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1295 for (int i = 0; i < count; ++i)
1296 dispatch(lyxaction.lookupFunc(rest));
1300 case LFUN_SEQUENCE: {
1301 // argument contains ';'-terminated commands
1302 string arg = argument;
1303 while (!arg.empty()) {
1305 arg = split(arg, first, ';');
1306 FuncRequest func(lyxaction.lookupFunc(first));
1307 func.origin = cmd.origin;
1313 case LFUN_SAVEPREFERENCES: {
1314 Path p(package().user_support());
1315 lyxrc.write("preferences", false);
1319 case LFUN_SCREEN_FONT_UPDATE:
1320 // handle the screen font changes.
1321 lyxrc.set_font_norm_type();
1322 lyx_gui::update_fonts();
1323 // All visible buffers will need resize
1327 case LFUN_SET_COLOR: {
1329 string const x11_name = split(argument, lyx_name, ' ');
1330 if (lyx_name.empty() || x11_name.empty()) {
1331 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1336 bool const graphicsbg_changed =
1337 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1338 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1340 if (!lcolor.setColor(lyx_name, x11_name)) {
1342 bformat(_("Set-color \"%1$s\" failed "
1343 "- color is undefined or "
1344 "may not be redefined"), lyx_name));
1348 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1350 if (graphicsbg_changed) {
1351 #ifdef WITH_WARNINGS
1352 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1355 lyx::graphics::GCache::get().changeDisplay(true);
1362 owner->message(argument);
1365 case LFUN_TOOLTIPS_TOGGLE:
1366 owner->getDialogs().toggleTooltips();
1369 case LFUN_EXTERNAL_EDIT: {
1370 FuncRequest fr(action, argument);
1371 InsetExternal().dispatch(view()->cursor(), fr);
1375 case LFUN_GRAPHICS_EDIT: {
1376 FuncRequest fr(action, argument);
1377 InsetGraphics().dispatch(view()->cursor(), fr);
1381 case LFUN_INSET_APPLY: {
1382 string const name = cmd.getArg(0);
1383 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1385 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1386 inset->dispatch(view()->cursor(), fr);
1388 FuncRequest fr(LFUN_INSET_INSERT, argument);
1391 // ideally, the update flag should be set by the insets,
1392 // but this is not possible currently
1397 case LFUN_ALL_INSETS_TOGGLE: {
1399 string const name = split(argument, action, ' ');
1400 InsetBase::Code const inset_code =
1401 InsetBase::translate(name);
1403 LCursor & cur = view()->cursor();
1404 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1406 InsetBase & inset = owner->buffer()->inset();
1407 InsetIterator it = inset_iterator_begin(inset);
1408 InsetIterator const end = inset_iterator_end(inset);
1409 for (; it != end; ++it) {
1410 if (inset_code == InsetBase::NO_CODE
1411 || inset_code == it->lyxCode())
1412 it->dispatch(cur, fr);
1418 case LFUN_LANGUAGE_BUFFER: {
1419 Buffer & buffer = *owner->buffer();
1420 Language const * oldL = buffer.params().language;
1421 Language const * newL = languages.getLanguage(argument);
1422 if (!newL || oldL == newL)
1425 if (oldL->RightToLeft() == newL->RightToLeft()
1426 && !buffer.isMultiLingual())
1427 buffer.changeLanguage(oldL, newL);
1429 buffer.updateDocLang(newL);
1433 case LFUN_SAVE_AS_DEFAULT: {
1434 string const fname =
1435 AddName(AddPath(package().user_support(), "templates/"),
1437 Buffer defaults(fname);
1439 istringstream ss(argument);
1442 int const unknown_tokens = defaults.readHeader(lex);
1444 if (unknown_tokens != 0) {
1445 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1446 << unknown_tokens << " unknown token"
1447 << (unknown_tokens == 1 ? "" : "s")
1451 if (defaults.writeFile(defaults.fileName()))
1452 setMessage(_("Document defaults saved in ")
1453 + MakeDisplayPath(fname));
1455 setErrorMessage(_("Unable to save document defaults"));
1459 case LFUN_BUFFERPARAMS_APPLY: {
1460 biblio::CiteEngine const engine =
1461 owner->buffer()->params().cite_engine;
1463 istringstream ss(argument);
1466 int const unknown_tokens =
1467 owner->buffer()->readHeader(lex);
1469 if (unknown_tokens != 0) {
1470 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1471 << unknown_tokens << " unknown token"
1472 << (unknown_tokens == 1 ? "" : "s")
1475 if (engine == owner->buffer()->params().cite_engine)
1478 LCursor & cur = view()->cursor();
1479 FuncRequest fr(LFUN_INSET_REFRESH);
1481 InsetBase & inset = owner->buffer()->inset();
1482 InsetIterator it = inset_iterator_begin(inset);
1483 InsetIterator const end = inset_iterator_end(inset);
1484 for (; it != end; ++it)
1485 if (it->lyxCode() == InsetBase::CITE_CODE)
1486 it->dispatch(cur, fr);
1490 case LFUN_TEXTCLASS_APPLY: {
1491 Buffer * buffer = owner->buffer();
1493 lyx::textclass_type const old_class =
1494 buffer->params().textclass;
1496 loadTextclass(argument);
1498 std::pair<bool, lyx::textclass_type> const tc_pair =
1499 textclasslist.NumberOfClass(argument);
1504 lyx::textclass_type const new_class = tc_pair.second;
1505 if (old_class == new_class)
1509 owner->message(_("Converting document to new document class..."));
1510 recordUndoFullDocument(view());
1511 buffer->params().textclass = new_class;
1512 StableDocIterator backcur(view()->cursor());
1514 lyx::cap::SwitchBetweenClasses(
1515 old_class, new_class,
1516 buffer->paragraphs(), el);
1518 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1519 bufferErrors(*buffer, el);
1520 view()->showErrorList(_("Class switch"));
1521 updateCounters(*buffer);
1526 case LFUN_TEXTCLASS_LOAD:
1527 loadTextclass(argument);
1530 case LFUN_LYXRC_APPLY: {
1531 LyXRC const lyxrc_orig = lyxrc;
1533 istringstream ss(argument);
1534 bool const success = lyxrc.read(ss) == 0;
1537 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1538 << "Unable to read lyxrc data"
1543 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1548 view()->cursor().dispatch(cmd);
1549 update |= view()->cursor().result().update();
1550 if (!view()->cursor().result().dispatched())
1551 update |= view()->dispatch(cmd);
1556 if (view()->available()) {
1557 // Redraw screen unless explicitly told otherwise.
1558 // This also initializes the position cache for all insets
1559 // in (at least partially) visible top-level paragraphs.
1561 view()->update(Update::FitCursor | Update::Force);
1563 view()->update(Update::FitCursor);
1565 // if we executed a mutating lfun, mark the buffer as dirty
1566 // FIXME: Why not use flag.enabled() but call getStatus again?
1567 if (getStatus(cmd).enabled()
1568 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1569 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1570 view()->buffer()->markDirty();
1573 if (view()->cursor().inTexted()) {
1574 view()->owner()->updateLayoutChoice();
1577 sendDispatchMessage(_(getMessage()), cmd);
1581 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1583 /* When an action did not originate from the UI/kbd, it makes
1584 * sense to avoid updating the GUI. It turns out that this
1585 * fixes bug 1941, for reasons that are described here:
1586 * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1588 if (cmd.origin != FuncRequest::INTERNAL) {
1589 owner->updateMenubar();
1590 owner->updateToolbars();
1593 const bool verbose = (cmd.origin == FuncRequest::UI
1594 || cmd.origin == FuncRequest::COMMANDBUFFER);
1596 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1597 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1599 owner->message(msg);
1603 string dispatch_msg = msg;
1604 if (!dispatch_msg.empty())
1605 dispatch_msg += ' ';
1607 string comname = lyxaction.getActionName(cmd.action);
1609 bool argsadded = false;
1611 if (!cmd.argument.empty()) {
1612 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1613 comname += ' ' + cmd.argument;
1618 string const shortcuts = toplevel_keymap->printbindings(cmd);
1620 if (!shortcuts.empty())
1621 comname += ": " + shortcuts;
1622 else if (!argsadded && !cmd.argument.empty())
1623 comname += ' ' + cmd.argument;
1625 if (!comname.empty()) {
1626 comname = rtrim(comname);
1627 dispatch_msg += '(' + rtrim(comname) + ')';
1630 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1631 if (!dispatch_msg.empty())
1632 owner->message(dispatch_msg);
1636 void LyXFunc::setupLocalKeymap()
1638 keyseq.stdmap = toplevel_keymap.get();
1639 keyseq.curmap = toplevel_keymap.get();
1640 cancel_meta_seq.stdmap = toplevel_keymap.get();
1641 cancel_meta_seq.curmap = toplevel_keymap.get();
1645 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1647 string initpath = lyxrc.document_path;
1648 string filename(name);
1650 if (view()->available()) {
1651 string const trypath = owner->buffer()->filePath();
1652 // If directory is writeable, use this as default.
1653 if (IsDirWriteable(trypath))
1657 static int newfile_number;
1659 if (filename.empty()) {
1660 filename = AddName(lyxrc.document_path,
1661 "newfile" + convert<string>(++newfile_number) + ".lyx");
1662 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1664 filename = AddName(lyxrc.document_path,
1665 "newfile" + convert<string>(newfile_number) +
1670 // The template stuff
1673 FileDialog fileDlg(_("Select template file"),
1674 LFUN_SELECT_FILE_SYNC,
1675 make_pair(string(_("Documents|#o#O")),
1676 string(lyxrc.document_path)),
1677 make_pair(string(_("Templates|#T#t")),
1678 string(lyxrc.template_path)));
1680 FileDialog::Result result =
1681 fileDlg.open(lyxrc.template_path,
1682 FileFilterList(_("LyX Documents (*.lyx)")),
1685 if (result.first == FileDialog::Later)
1687 if (result.second.empty())
1689 templname = result.second;
1692 view()->newFile(filename, templname, !name.empty());
1696 void LyXFunc::open(string const & fname)
1698 string initpath = lyxrc.document_path;
1700 if (view()->available()) {
1701 string const trypath = owner->buffer()->filePath();
1702 // If directory is writeable, use this as default.
1703 if (IsDirWriteable(trypath))
1709 if (fname.empty()) {
1710 FileDialog fileDlg(_("Select document to open"),
1712 make_pair(string(_("Documents|#o#O")),
1713 string(lyxrc.document_path)),
1714 make_pair(string(_("Examples|#E#e")),
1715 string(AddPath(package().system_support(), "examples"))));
1717 FileDialog::Result result =
1718 fileDlg.open(initpath,
1719 FileFilterList(_("LyX Documents (*.lyx)")),
1722 if (result.first == FileDialog::Later)
1725 filename = result.second;
1727 // check selected filename
1728 if (filename.empty()) {
1729 owner->message(_("Canceled."));
1735 // get absolute path of file and add ".lyx" to the filename if
1737 string const fullpath = FileSearch(string(), filename, "lyx");
1738 if (!fullpath.empty()) {
1739 filename = fullpath;
1742 string const disp_fn(MakeDisplayPath(filename));
1744 // if the file doesn't exist, let the user create one
1745 if (!fs::exists(filename)) {
1746 // the user specifically chose this name. Believe them.
1747 view()->newFile(filename, "", true);
1751 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1754 if (view()->loadLyXFile(filename)) {
1755 str2 = bformat(_("Document %1$s opened."), disp_fn);
1757 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1759 owner->message(str2);
1763 void LyXFunc::doImport(string const & argument)
1766 string filename = split(argument, format, ' ');
1768 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1769 << " file: " << filename << endl;
1771 // need user interaction
1772 if (filename.empty()) {
1773 string initpath = lyxrc.document_path;
1775 if (view()->available()) {
1776 string const trypath = owner->buffer()->filePath();
1777 // If directory is writeable, use this as default.
1778 if (IsDirWriteable(trypath))
1782 string const text = bformat(_("Select %1$s file to import"),
1783 formats.prettyName(format));
1785 FileDialog fileDlg(text,
1787 make_pair(string(_("Documents|#o#O")),
1788 string(lyxrc.document_path)),
1789 make_pair(string(_("Examples|#E#e")),
1790 string(AddPath(package().system_support(), "examples"))));
1792 string const filter = formats.prettyName(format)
1793 + " (*." + formats.extension(format) + ')';
1795 FileDialog::Result result =
1796 fileDlg.open(initpath,
1797 FileFilterList(filter),
1800 if (result.first == FileDialog::Later)
1803 filename = result.second;
1805 // check selected filename
1806 if (filename.empty())
1807 owner->message(_("Canceled."));
1810 if (filename.empty())
1813 // get absolute path of file
1814 filename = MakeAbsPath(filename);
1816 string const lyxfile = ChangeExtension(filename, ".lyx");
1818 // Check if the document already is open
1819 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1820 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1821 owner->message(_("Canceled."));
1826 // if the file exists already, and we didn't do
1827 // -i lyx thefile.lyx, warn
1828 if (fs::exists(lyxfile) && filename != lyxfile) {
1829 string const file = MakeDisplayPath(lyxfile, 30);
1831 string text = bformat(_("The document %1$s already exists.\n\n"
1832 "Do you want to over-write that document?"), file);
1833 int const ret = Alert::prompt(_("Over-write document?"),
1834 text, 0, 1, _("&Over-write"), _("&Cancel"));
1837 owner->message(_("Canceled."));
1842 Importer::Import(owner, filename, format);
1846 void LyXFunc::closeBuffer()
1848 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1849 if (bufferlist.empty()) {
1850 // need this otherwise SEGV may occur while
1851 // trying to set variables that don't exist
1852 // since there's no current buffer
1853 owner->getDialogs().hideBufferDependent();
1855 view()->setBuffer(bufferlist.first());
1861 // Each "owner" should have it's own message method. lyxview and
1862 // the minibuffer would use the minibuffer, but lyxserver would
1863 // send an ERROR signal to its client. Alejandro 970603
1864 // This function is bit problematic when it comes to NLS, to make the
1865 // lyx servers client be language indepenent we must not translate
1866 // strings sent to this func.
1867 void LyXFunc::setErrorMessage(string const & m) const
1869 dispatch_buffer = m;
1874 void LyXFunc::setMessage(string const & m) const
1876 dispatch_buffer = m;
1880 string const LyXFunc::viewStatusMessage()
1882 // When meta-fake key is pressed, show the key sequence so far + "M-".
1884 return keyseq.print() + "M-";
1886 // Else, when a non-complete key sequence is pressed,
1887 // show the available options.
1888 if (keyseq.length() > 0 && !keyseq.deleted())
1889 return keyseq.printOptions();
1891 if (!view()->available())
1892 return _("Welcome to LyX!");
1894 return view()->cursor().currentState();
1898 BufferView * LyXFunc::view() const
1900 BOOST_ASSERT(owner);
1901 return owner->view().get();
1905 bool LyXFunc::wasMetaKey() const
1907 return (meta_fake_bit != key_modifier::none);
1913 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1915 // Why the switch you might ask. It is a trick to ensure that all
1916 // the elements in the LyXRCTags enum is handled. As you can see
1917 // there are no breaks at all. So it is just a huge fall-through.
1918 // The nice thing is that we will get a warning from the compiler
1919 // if we forget an element.
1920 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1922 case LyXRC::RC_ACCEPT_COMPOUND:
1923 case LyXRC::RC_ALT_LANG:
1924 case LyXRC::RC_ASCIIROFF_COMMAND:
1925 case LyXRC::RC_ASCII_LINELEN:
1926 case LyXRC::RC_AUTOREGIONDELETE:
1927 case LyXRC::RC_AUTORESET_OPTIONS:
1928 case LyXRC::RC_AUTOSAVE:
1929 case LyXRC::RC_AUTO_NUMBER:
1930 case LyXRC::RC_BACKUPDIR_PATH:
1931 case LyXRC::RC_BIBTEX_COMMAND:
1932 case LyXRC::RC_BINDFILE:
1933 case LyXRC::RC_CHECKLASTFILES:
1934 case LyXRC::RC_CHKTEX_COMMAND:
1935 case LyXRC::RC_CONVERTER:
1936 case LyXRC::RC_COPIER:
1937 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1938 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1939 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1940 case LyXRC::RC_CYGWIN_PATH_FIX:
1941 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1942 namespace os = lyx::support::os;
1943 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1945 case LyXRC::RC_DATE_INSERT_FORMAT:
1946 case LyXRC::RC_DEFAULT_LANGUAGE:
1947 case LyXRC::RC_DEFAULT_PAPERSIZE:
1948 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1949 case LyXRC::RC_DISPLAY_GRAPHICS:
1950 case LyXRC::RC_DOCUMENTPATH:
1951 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1952 if (fs::exists(lyxrc_new.document_path) &&
1953 fs::is_directory(lyxrc_new.document_path)) {
1954 using lyx::support::package;
1955 package().document_dir() = lyxrc.document_path;
1958 case LyXRC::RC_ESC_CHARS:
1959 case LyXRC::RC_FONT_ENCODING:
1960 case LyXRC::RC_FORMAT:
1961 case LyXRC::RC_INDEX_COMMAND:
1962 case LyXRC::RC_INPUT:
1963 case LyXRC::RC_KBMAP:
1964 case LyXRC::RC_KBMAP_PRIMARY:
1965 case LyXRC::RC_KBMAP_SECONDARY:
1966 case LyXRC::RC_LABEL_INIT_LENGTH:
1967 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1968 case LyXRC::RC_LANGUAGE_AUTO_END:
1969 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1970 case LyXRC::RC_LANGUAGE_COMMAND_END:
1971 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1972 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1973 case LyXRC::RC_LANGUAGE_PACKAGE:
1974 case LyXRC::RC_LANGUAGE_USE_BABEL:
1975 case LyXRC::RC_LASTFILES:
1976 case LyXRC::RC_MAKE_BACKUP:
1977 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1978 case LyXRC::RC_NUMLASTFILES:
1979 case LyXRC::RC_PATH_PREFIX:
1980 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1981 using lyx::support::prependEnvPath;
1982 prependEnvPath("PATH", lyxrc.path_prefix);
1984 case LyXRC::RC_PERS_DICT:
1985 case LyXRC::RC_POPUP_BOLD_FONT:
1986 case LyXRC::RC_POPUP_FONT_ENCODING:
1987 case LyXRC::RC_POPUP_NORMAL_FONT:
1988 case LyXRC::RC_PREVIEW:
1989 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1990 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1991 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1992 case LyXRC::RC_PRINTCOPIESFLAG:
1993 case LyXRC::RC_PRINTER:
1994 case LyXRC::RC_PRINTEVENPAGEFLAG:
1995 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1996 case LyXRC::RC_PRINTFILEEXTENSION:
1997 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1998 case LyXRC::RC_PRINTODDPAGEFLAG:
1999 case LyXRC::RC_PRINTPAGERANGEFLAG:
2000 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2001 case LyXRC::RC_PRINTPAPERFLAG:
2002 case LyXRC::RC_PRINTREVERSEFLAG:
2003 case LyXRC::RC_PRINTSPOOL_COMMAND:
2004 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2005 case LyXRC::RC_PRINTTOFILE:
2006 case LyXRC::RC_PRINTTOPRINTER:
2007 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2008 case LyXRC::RC_PRINT_COMMAND:
2009 case LyXRC::RC_RTL_SUPPORT:
2010 case LyXRC::RC_SCREEN_DPI:
2011 case LyXRC::RC_SCREEN_FONT_ENCODING:
2012 case LyXRC::RC_SCREEN_FONT_ROMAN:
2013 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2014 case LyXRC::RC_SCREEN_FONT_SANS:
2015 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2016 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2017 case LyXRC::RC_SCREEN_FONT_SIZES:
2018 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2019 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2020 case LyXRC::RC_SCREEN_ZOOM:
2021 case LyXRC::RC_SERVERPIPE:
2022 case LyXRC::RC_SET_COLOR:
2023 case LyXRC::RC_SHOW_BANNER:
2024 case LyXRC::RC_SPELL_COMMAND:
2025 case LyXRC::RC_TEMPDIRPATH:
2026 case LyXRC::RC_TEMPLATEPATH:
2027 case LyXRC::RC_TEX_ALLOWS_SPACES:
2028 case LyXRC::RC_UIFILE:
2029 case LyXRC::RC_USER_EMAIL:
2030 case LyXRC::RC_USER_NAME:
2031 case LyXRC::RC_USETEMPDIR:
2032 case LyXRC::RC_USE_ALT_LANG:
2033 case LyXRC::RC_USE_ESC_CHARS:
2034 case LyXRC::RC_USE_INP_ENC:
2035 case LyXRC::RC_USE_PERS_DICT:
2036 case LyXRC::RC_USE_SPELL_LIB:
2037 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2038 case LyXRC::RC_VIEWER:
2039 case LyXRC::RC_WHEEL_JUMP:
2040 case LyXRC::RC_LAST: