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.
343 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
346 buf = owner->buffer();
348 if (cmd.action == LFUN_NOACTION) {
349 flag.message(N_("Nothing to do"));
354 switch (cmd.action) {
355 case LFUN_UNKNOWN_ACTION:
356 #ifndef HAVE_LIBAIKSAURUS
357 case LFUN_THESAURUS_ENTRY:
363 flag |= lyx_gui::getStatus(cmd);
366 if (flag.unknown()) {
367 flag.message(N_("Unknown action"));
371 if (!flag.enabled()) {
372 if (flag.message().empty())
373 flag.message(N_("Command disabled"));
377 // Check whether we need a buffer
378 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
380 flag.message(N_("Command not allowed with"
381 "out any document open"));
386 // I would really like to avoid having this switch and rather try to
387 // encode this in the function itself.
388 // -- And I'd rather let an inset decide which LFUNs it is willing
389 // to handle (Andre')
391 switch (cmd.action) {
392 case LFUN_TOOLTIPS_TOGGLE:
393 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
396 case LFUN_READ_ONLY_TOGGLE:
397 flag.setOnOff(buf->isReadonly());
400 case LFUN_SWITCHBUFFER:
401 // toggle on the current buffer, but do not toggle off
402 // the other ones (is that a good idea?)
403 if (cmd.argument == buf->fileName())
408 enable = cmd.argument == "custom"
409 || Exporter::IsExportable(*buf, cmd.argument);
413 enable = cur.selection();
417 enable = buf->isLatex() && lyxrc.chktex_command != "none";
421 enable = Exporter::IsExportable(*buf, "program");
424 case LFUN_LAYOUT_TABULAR:
425 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
429 case LFUN_LAYOUT_PARAGRAPH:
430 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
433 case LFUN_VC_REGISTER:
434 enable = !buf->lyxvc().inUse();
436 case LFUN_VC_CHECKIN:
437 enable = buf->lyxvc().inUse() && !buf->isReadonly();
439 case LFUN_VC_CHECKOUT:
440 enable = buf->lyxvc().inUse() && buf->isReadonly();
444 enable = buf->lyxvc().inUse();
446 case LFUN_MENURELOAD:
447 enable = !buf->isUnnamed() && !buf->isClean();
450 case LFUN_INSET_SETTINGS: {
454 InsetBase::Code code = cur.inset().lyxCode();
456 case InsetBase::TABULAR_CODE:
457 enable = cmd.argument == "tabular";
459 case InsetBase::ERT_CODE:
460 enable = cmd.argument == "ert";
462 case InsetBase::FLOAT_CODE:
463 enable = cmd.argument == "float";
465 case InsetBase::WRAP_CODE:
466 enable = cmd.argument == "wrap";
468 case InsetBase::NOTE_CODE:
469 enable = cmd.argument == "note";
471 case InsetBase::BRANCH_CODE:
472 enable = cmd.argument == "branch";
474 case InsetBase::BOX_CODE:
475 enable = cmd.argument == "box";
483 case LFUN_INSET_APPLY: {
484 string const name = cmd.getArg(0);
485 InsetBase * inset = owner->getDialogs().getOpenInset(name);
487 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
489 bool const success = inset->getStatus(cur, fr, fs);
490 // Every inset is supposed to handle this
491 BOOST_ASSERT(success);
494 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
495 flag |= getStatus(fr);
497 enable = flag.enabled();
501 case LFUN_DIALOG_SHOW: {
502 string const name = cmd.getArg(0);
504 enable = name == "aboutlyx"
508 || name == "texinfo";
509 else if (name == "print")
510 enable = Exporter::IsExportable(*buf, "dvi")
511 && lyxrc.print_command != "none";
512 else if (name == "character" || name == "mathpanel")
513 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
514 else if (name == "latexlog")
515 enable = IsFileReadable(buf->getLogName().second);
516 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
517 else if (name == "spellchecker")
520 else if (name == "vclog")
521 enable = buf->lyxvc().inUse();
525 case LFUN_DIALOG_SHOW_NEW_INSET:
526 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
529 case LFUN_DIALOG_UPDATE: {
530 string const name = cmd.getArg(0);
532 enable = name == "prefs";
536 // this one is difficult to get right. As a half-baked
537 // solution, we consider only the first action of the sequence
538 case LFUN_SEQUENCE: {
539 // argument contains ';'-terminated commands
540 string const firstcmd = token(cmd.argument, ';', 0);
541 FuncRequest func(lyxaction.lookupFunc(firstcmd));
542 func.origin = cmd.origin;
543 flag = getStatus(func);
547 case LFUN_MENUNEWTMPLT:
548 case LFUN_WORDFINDFORWARD:
549 case LFUN_WORDFINDBACKWARD:
551 case LFUN_EXEC_COMMAND:
554 case LFUN_CLOSEBUFFER:
563 case LFUN_RECONFIGURE:
567 case LFUN_DROP_LAYOUTS_CHOICE:
568 case LFUN_MENU_OPEN_BY_NAME:
571 case LFUN_GOTOFILEROW:
572 case LFUN_DIALOG_SHOW_NEXT_INSET:
573 case LFUN_DIALOG_HIDE:
574 case LFUN_DIALOG_DISCONNECT_INSET:
576 case LFUN_TOGGLECURSORFOLLOW:
580 case LFUN_KMAP_TOGGLE:
582 case LFUN_EXPORT_CUSTOM:
584 case LFUN_SAVEPREFERENCES:
585 case LFUN_SCREEN_FONT_UPDATE:
588 case LFUN_EXTERNAL_EDIT:
589 case LFUN_GRAPHICS_EDIT:
590 case LFUN_ALL_INSETS_TOGGLE:
591 case LFUN_LANGUAGE_BUFFER:
592 case LFUN_TEXTCLASS_APPLY:
593 case LFUN_TEXTCLASS_LOAD:
594 case LFUN_SAVE_AS_DEFAULT:
595 case LFUN_BUFFERPARAMS_APPLY:
596 case LFUN_LYXRC_APPLY:
597 case LFUN_NEXTBUFFER:
598 case LFUN_PREVIOUSBUFFER:
599 // these are handled in our dispatch()
604 if (!::getStatus(cur, cmd, flag))
605 flag = view()->getStatus(cmd);
611 // Can we use a readonly buffer?
612 if (buf && buf->isReadonly()
613 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
614 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
615 flag.message(N_("Document is read-only"));
619 // Are we in a DELETED change-tracking region?
620 if (buf && buf->params().tracking_changes
621 && lookupChange(cur, true) == Change::DELETED
622 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
623 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
624 flag.message(N_("This portion of the document is deleted."));
628 // the default error message if we disable the command
629 if (!flag.enabled() && flag.message().empty())
630 flag.message(N_("Command disabled"));
638 bool ensureBufferClean(BufferView * bv)
640 Buffer & buf = *bv->buffer();
644 string const file = MakeDisplayPath(buf.fileName(), 30);
645 string text = bformat(_("The document %1$s has unsaved "
646 "changes.\n\nDo you want to save "
647 "the document?"), file);
648 int const ret = Alert::prompt(_("Save changed document?"),
649 text, 0, 1, _("&Save"),
653 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
655 return buf.isClean();
659 void showPrintError(string const & name)
661 string str = bformat(_("Could not print the document %1$s.\n"
662 "Check that your printer is set up correctly."),
663 MakeDisplayPath(name, 50));
664 Alert::error(_("Print document failed"), str);
668 void loadTextclass(string const & name)
670 std::pair<bool, lyx::textclass_type> const tc_pair =
671 textclasslist.NumberOfClass(name);
673 if (!tc_pair.first) {
674 lyxerr << "Document class \"" << name
675 << "\" does not exist."
680 lyx::textclass_type const tc = tc_pair.second;
682 if (!textclasslist[tc].load()) {
683 string s = bformat(_("The document could not be converted\n"
684 "into the document class %1$s."),
685 textclasslist[tc].name());
686 Alert::error(_("Could not change class"), s);
691 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
696 void LyXFunc::dispatch(FuncRequest const & cmd)
698 BOOST_ASSERT(view());
699 string const argument = cmd.argument;
700 kb_action const action = cmd.action;
702 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
703 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
705 // we have not done anything wrong yet.
707 dispatch_buffer.erase();
711 FuncStatus const flag = getStatus(cmd);
712 if (!flag.enabled()) {
713 // We cannot use this function here
714 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
715 << lyxaction.getActionName(action)
716 << " [" << action << "] is disabled at this location"
718 setErrorMessage(flag.message());
721 if (view()->available())
722 view()->hideCursor();
726 case LFUN_WORDFINDFORWARD:
727 case LFUN_WORDFINDBACKWARD: {
728 static string last_search;
729 string searched_string;
731 if (!argument.empty()) {
732 last_search = argument;
733 searched_string = argument;
735 searched_string = last_search;
738 if (searched_string.empty())
741 bool const fw = action == LFUN_WORDFINDFORWARD;
743 lyx::find::find2string(searched_string, true, false, fw);
744 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
749 owner->message(keyseq.printOptions());
752 case LFUN_EXEC_COMMAND:
753 owner->getToolbars().display("minibuffer", true);
754 owner->focus_command_buffer();
759 meta_fake_bit = key_modifier::none;
760 if (view()->available())
761 // cancel any selection
762 dispatch(FuncRequest(LFUN_MARK_OFF));
763 setMessage(N_("Cancel"));
767 meta_fake_bit = key_modifier::alt;
768 setMessage(keyseq.print());
771 case LFUN_READ_ONLY_TOGGLE:
772 if (owner->buffer()->lyxvc().inUse())
773 owner->buffer()->lyxvc().toggleReadOnly();
775 owner->buffer()->setReadonly(
776 !owner->buffer()->isReadonly());
779 // --- Menus -----------------------------------------------
781 menuNew(argument, false);
784 case LFUN_MENUNEWTMPLT:
785 menuNew(argument, true);
788 case LFUN_CLOSEBUFFER:
793 if (!owner->buffer()->isUnnamed()) {
794 string const str = bformat(_("Saving document %1$s..."),
795 MakeDisplayPath(owner->buffer()->fileName()));
797 MenuWrite(owner->buffer());
798 owner->message(str + _(" done."));
800 WriteAs(owner->buffer());
804 WriteAs(owner->buffer(), argument);
807 case LFUN_MENURELOAD: {
808 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
809 string text = bformat(_("Any changes will be lost. Are you sure "
810 "you want to revert to the saved version of the document %1$s?"), file);
811 int const ret = Alert::prompt(_("Revert to saved document?"),
812 text, 0, 1, _("&Revert"), _("&Cancel"));
820 Exporter::Export(owner->buffer(), argument, true);
821 view()->showErrorList(BufferFormat(*owner->buffer()));
825 Exporter::Preview(owner->buffer(), argument);
826 view()->showErrorList(BufferFormat(*owner->buffer()));
830 Exporter::Export(owner->buffer(), "program", true);
831 view()->showErrorList(_("Build"));
835 owner->buffer()->runChktex();
836 view()->showErrorList(_("ChkTeX"));
840 if (argument == "custom")
841 owner->getDialogs().show("sendto");
843 Exporter::Export(owner->buffer(), argument, false);
844 view()->showErrorList(BufferFormat(*owner->buffer()));
848 case LFUN_EXPORT_CUSTOM: {
850 string command = split(argument, format_name, ' ');
851 Format const * format = formats.getFormat(format_name);
853 lyxerr << "Format \"" << format_name
854 << "\" not recognized!"
859 Buffer * buffer = owner->buffer();
861 // The name of the file created by the conversion process
864 // Output to filename
865 if (format->name() == "lyx") {
866 string const latexname =
867 buffer->getLatexName(false);
868 filename = ChangeExtension(latexname,
869 format->extension());
870 filename = AddName(buffer->temppath(), filename);
872 if (!buffer->writeFile(filename))
876 Exporter::Export(buffer, format_name, true,
880 // Substitute $$FName for filename
881 if (!contains(command, "$$FName"))
882 command = "( " + command + " ) < $$FName";
883 command = subst(command, "$$FName", filename);
885 // Execute the command in the background
887 call.startscript(Systemcall::DontWait, command);
894 string command = split(split(argument, target, ' '),
898 || target_name.empty()
899 || command.empty()) {
900 lyxerr << "Unable to parse \""
901 << argument << '"' << std::endl;
904 if (target != "printer" && target != "file") {
905 lyxerr << "Unrecognized target \""
906 << target << '"' << std::endl;
910 Buffer * buffer = owner->buffer();
912 if (!Exporter::Export(buffer, "dvi", true)) {
913 showPrintError(buffer->fileName());
917 // Push directory path.
918 string const path = buffer->temppath();
921 // there are three cases here:
922 // 1. we print to a file
923 // 2. we print directly to a printer
924 // 3. we print using a spool command (print to file first)
927 string const dviname =
928 ChangeExtension(buffer->getLatexName(true),
931 if (target == "printer") {
932 if (!lyxrc.print_spool_command.empty()) {
933 // case 3: print using a spool
934 string const psname =
935 ChangeExtension(dviname,".ps");
936 command += lyxrc.print_to_file
939 + QuoteName(dviname);
942 lyxrc.print_spool_command +' ';
943 if (target_name != "default") {
944 command2 += lyxrc.print_spool_printerprefix
948 command2 += QuoteName(psname);
950 // If successful, then spool command
951 res = one.startscript(
956 res = one.startscript(
957 Systemcall::DontWait,
960 // case 2: print directly to a printer
961 res = one.startscript(
962 Systemcall::DontWait,
963 command + QuoteName(dviname));
967 // case 1: print to a file
968 command += lyxrc.print_to_file
969 + QuoteName(MakeAbsPath(target_name,
972 + QuoteName(dviname);
973 res = one.startscript(Systemcall::DontWait,
978 showPrintError(buffer->fileName());
987 QuitLyX(argument == "force");
991 InsetCommandParams p("tableofcontents");
992 string const data = InsetCommandMailer::params2string("toc", p);
993 owner->getDialogs().show("toc", data, 0);
1001 case LFUN_RECONFIGURE:
1002 Reconfigure(view());
1005 case LFUN_HELP_OPEN: {
1006 string const arg = argument;
1008 setErrorMessage(N_("Missing argument"));
1011 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1012 if (fname.empty()) {
1013 lyxerr << "LyX: unable to find documentation file `"
1014 << arg << "'. Bad installation?" << endl;
1017 owner->message(bformat(_("Opening help file %1$s..."),
1018 MakeDisplayPath(fname)));
1019 view()->loadLyXFile(fname, false);
1023 // --- version control -------------------------------
1024 case LFUN_VC_REGISTER:
1025 if (!ensureBufferClean(view()))
1027 if (!owner->buffer()->lyxvc().inUse()) {
1028 owner->buffer()->lyxvc().registrer();
1033 case LFUN_VC_CHECKIN:
1034 if (!ensureBufferClean(view()))
1036 if (owner->buffer()->lyxvc().inUse()
1037 && !owner->buffer()->isReadonly()) {
1038 owner->buffer()->lyxvc().checkIn();
1043 case LFUN_VC_CHECKOUT:
1044 if (!ensureBufferClean(view()))
1046 if (owner->buffer()->lyxvc().inUse()
1047 && owner->buffer()->isReadonly()) {
1048 owner->buffer()->lyxvc().checkOut();
1053 case LFUN_VC_REVERT:
1054 owner->buffer()->lyxvc().revert();
1059 owner->buffer()->lyxvc().undoLast();
1063 // --- buffers ----------------------------------------
1064 case LFUN_SWITCHBUFFER:
1065 view()->setBuffer(bufferlist.getBuffer(argument));
1068 case LFUN_NEXTBUFFER:
1069 view()->setBuffer(bufferlist.next(view()->buffer()));
1072 case LFUN_PREVIOUSBUFFER:
1073 view()->setBuffer(bufferlist.previous(view()->buffer()));
1077 NewFile(view(), argument);
1080 case LFUN_FILE_OPEN:
1084 case LFUN_DROP_LAYOUTS_CHOICE:
1085 owner->getToolbars().openLayoutList();
1088 case LFUN_MENU_OPEN_BY_NAME:
1089 owner->getMenubar().openByName(argument);
1092 // --- lyxserver commands ----------------------------
1094 setMessage(owner->buffer()->fileName());
1095 lyxerr[Debug::INFO] << "FNAME["
1096 << owner->buffer()->fileName()
1101 dispatch_buffer = keyseq.print();
1102 lyxserver->notifyClient(dispatch_buffer);
1105 case LFUN_GOTOFILEROW: {
1108 istringstream is(argument);
1109 is >> file_name >> row;
1110 if (prefixIs(file_name, package().temp_dir())) {
1111 // Needed by inverse dvi search. If it is a file
1112 // in tmpdir, call the apropriated function
1113 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1115 // Must replace extension of the file to be .lyx
1116 // and get full path
1117 string const s = ChangeExtension(file_name, ".lyx");
1118 // Either change buffer or load the file
1119 if (bufferlist.exists(s)) {
1120 view()->setBuffer(bufferlist.getBuffer(s));
1122 view()->loadLyXFile(s);
1126 view()->setCursorFromRow(row);
1129 // see BufferView_pimpl::center()
1130 view()->updateScrollbar();
1134 case LFUN_DIALOG_SHOW: {
1135 string const name = cmd.getArg(0);
1136 string data = trim(cmd.argument.substr(name.size()));
1138 if (name == "character") {
1139 data = freefont2string();
1141 owner->getDialogs().show("character", data);
1144 else if (name == "latexlog") {
1145 pair<Buffer::LogType, string> const logfile =
1146 owner->buffer()->getLogName();
1147 switch (logfile.first) {
1148 case Buffer::latexlog:
1151 case Buffer::buildlog:
1155 data += logfile.second;
1156 owner->getDialogs().show("log", data);
1158 else if (name == "vclog") {
1159 string const data = "vc " +
1160 owner->buffer()->lyxvc().getLogFile();
1161 owner->getDialogs().show("log", data);
1164 owner->getDialogs().show(name, data);
1168 case LFUN_DIALOG_SHOW_NEW_INSET: {
1169 string const name = cmd.getArg(0);
1170 string data = trim(cmd.argument.substr(name.size()));
1171 if (name == "bibitem" ||
1178 InsetCommandParams p(name);
1179 data = InsetCommandMailer::params2string(name, p);
1180 } else if (name == "include") {
1181 InsetCommandParams p(data);
1182 data = InsetIncludeMailer::params2string(p);
1183 } else if (name == "box") {
1184 // \c data == "Boxed" || "Frameless" etc
1185 InsetBoxParams p(data);
1186 data = InsetBoxMailer::params2string(p);
1187 } else if (name == "branch") {
1188 InsetBranchParams p;
1189 data = InsetBranchMailer::params2string(p);
1190 } else if (name == "citation") {
1191 InsetCommandParams p("cite");
1192 data = InsetCommandMailer::params2string(name, p);
1193 } else if (name == "ert") {
1194 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1195 } else if (name == "external") {
1196 InsetExternalParams p;
1197 Buffer const & buffer = *owner->buffer();
1198 data = InsetExternalMailer::params2string(p, buffer);
1199 } else if (name == "float") {
1201 data = InsetFloatMailer::params2string(p);
1202 } else if (name == "graphics") {
1203 InsetGraphicsParams p;
1204 Buffer const & buffer = *owner->buffer();
1205 data = InsetGraphicsMailer::params2string(p, buffer);
1206 } else if (name == "note") {
1208 data = InsetNoteMailer::params2string(p);
1209 } else if (name == "vspace") {
1211 data = InsetVSpaceMailer::params2string(space);
1212 } else if (name == "wrap") {
1214 data = InsetWrapMailer::params2string(p);
1216 owner->getDialogs().show(name, data, 0);
1220 case LFUN_DIALOG_SHOW_NEXT_INSET:
1223 case LFUN_DIALOG_UPDATE: {
1224 string const & name = argument;
1225 // Can only update a dialog connected to an existing inset
1226 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1228 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1229 inset->dispatch(view()->cursor(), fr);
1230 } else if (name == "paragraph") {
1231 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1232 } else if (name == "prefs") {
1233 owner->getDialogs().update(name, string());
1238 case LFUN_DIALOG_HIDE:
1239 Dialogs::hide(argument, 0);
1242 case LFUN_DIALOG_DISCONNECT_INSET:
1243 owner->getDialogs().disconnect(argument);
1246 case LFUN_CHILDOPEN: {
1247 string const filename =
1248 MakeAbsPath(argument, owner->buffer()->filePath());
1249 setMessage(N_("Opening child document ") +
1250 MakeDisplayPath(filename) + "...");
1251 view()->savePosition(0);
1252 string const parentfilename = owner->buffer()->fileName();
1253 if (bufferlist.exists(filename))
1254 view()->setBuffer(bufferlist.getBuffer(filename));
1256 view()->loadLyXFile(filename);
1257 // Set the parent name of the child document.
1258 // This makes insertion of citations and references in the child work,
1259 // when the target is in the parent or another child document.
1260 owner->buffer()->setParentName(parentfilename);
1264 case LFUN_TOGGLECURSORFOLLOW:
1265 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1269 owner->getIntl().KeyMapOn(false);
1272 case LFUN_KMAP_PRIM:
1273 owner->getIntl().KeyMapPrim();
1277 owner->getIntl().KeyMapSec();
1280 case LFUN_KMAP_TOGGLE:
1281 owner->getIntl().ToggleKeyMap();
1287 string rest = split(argument, countstr, ' ');
1288 istringstream is(countstr);
1291 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1292 for (int i = 0; i < count; ++i)
1293 dispatch(lyxaction.lookupFunc(rest));
1297 case LFUN_SEQUENCE: {
1298 // argument contains ';'-terminated commands
1299 string arg = argument;
1300 while (!arg.empty()) {
1302 arg = split(arg, first, ';');
1303 FuncRequest func(lyxaction.lookupFunc(first));
1304 func.origin = cmd.origin;
1310 case LFUN_SAVEPREFERENCES: {
1311 Path p(package().user_support());
1312 lyxrc.write("preferences", false);
1316 case LFUN_SCREEN_FONT_UPDATE:
1317 // handle the screen font changes.
1318 lyxrc.set_font_norm_type();
1319 lyx_gui::update_fonts();
1320 // All visible buffers will need resize
1324 case LFUN_SET_COLOR: {
1326 string const x11_name = split(argument, lyx_name, ' ');
1327 if (lyx_name.empty() || x11_name.empty()) {
1328 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1333 bool const graphicsbg_changed =
1334 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1335 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1337 if (!lcolor.setColor(lyx_name, x11_name)) {
1339 bformat(_("Set-color \"%1$s\" failed "
1340 "- color is undefined or "
1341 "may not be redefined"), lyx_name));
1345 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1347 if (graphicsbg_changed) {
1348 #ifdef WITH_WARNINGS
1349 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1352 lyx::graphics::GCache::get().changeDisplay(true);
1359 owner->message(argument);
1362 case LFUN_TOOLTIPS_TOGGLE:
1363 owner->getDialogs().toggleTooltips();
1366 case LFUN_EXTERNAL_EDIT: {
1367 FuncRequest fr(action, argument);
1368 InsetExternal().dispatch(view()->cursor(), fr);
1372 case LFUN_GRAPHICS_EDIT: {
1373 FuncRequest fr(action, argument);
1374 InsetGraphics().dispatch(view()->cursor(), fr);
1378 case LFUN_INSET_APPLY: {
1379 string const name = cmd.getArg(0);
1380 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1382 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1383 inset->dispatch(view()->cursor(), fr);
1385 FuncRequest fr(LFUN_INSET_INSERT, argument);
1388 // ideally, the update flag should be set by the insets,
1389 // but this is not possible currently
1394 case LFUN_ALL_INSETS_TOGGLE: {
1396 string const name = split(argument, action, ' ');
1397 InsetBase::Code const inset_code =
1398 InsetBase::translate(name);
1400 LCursor & cur = view()->cursor();
1401 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1403 InsetBase & inset = owner->buffer()->inset();
1404 InsetIterator it = inset_iterator_begin(inset);
1405 InsetIterator const end = inset_iterator_end(inset);
1406 for (; it != end; ++it) {
1407 if (inset_code == InsetBase::NO_CODE
1408 || inset_code == it->lyxCode())
1409 it->dispatch(cur, fr);
1415 case LFUN_LANGUAGE_BUFFER: {
1416 Buffer & buffer = *owner->buffer();
1417 Language const * oldL = buffer.params().language;
1418 Language const * newL = languages.getLanguage(argument);
1419 if (!newL || oldL == newL)
1422 if (oldL->RightToLeft() == newL->RightToLeft()
1423 && !buffer.isMultiLingual())
1424 buffer.changeLanguage(oldL, newL);
1426 buffer.updateDocLang(newL);
1430 case LFUN_SAVE_AS_DEFAULT: {
1431 string const fname =
1432 AddName(AddPath(package().user_support(), "templates/"),
1434 Buffer defaults(fname);
1436 istringstream ss(argument);
1439 int const unknown_tokens = defaults.readHeader(lex);
1441 if (unknown_tokens != 0) {
1442 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1443 << unknown_tokens << " unknown token"
1444 << (unknown_tokens == 1 ? "" : "s")
1448 if (defaults.writeFile(defaults.fileName()))
1449 setMessage(_("Document defaults saved in ")
1450 + MakeDisplayPath(fname));
1452 setErrorMessage(_("Unable to save document defaults"));
1456 case LFUN_BUFFERPARAMS_APPLY: {
1457 biblio::CiteEngine const engine =
1458 owner->buffer()->params().cite_engine;
1460 istringstream ss(argument);
1463 int const unknown_tokens =
1464 owner->buffer()->readHeader(lex);
1466 if (unknown_tokens != 0) {
1467 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1468 << unknown_tokens << " unknown token"
1469 << (unknown_tokens == 1 ? "" : "s")
1472 if (engine == owner->buffer()->params().cite_engine)
1475 LCursor & cur = view()->cursor();
1476 FuncRequest fr(LFUN_INSET_REFRESH);
1478 InsetBase & inset = owner->buffer()->inset();
1479 InsetIterator it = inset_iterator_begin(inset);
1480 InsetIterator const end = inset_iterator_end(inset);
1481 for (; it != end; ++it)
1482 if (it->lyxCode() == InsetBase::CITE_CODE)
1483 it->dispatch(cur, fr);
1487 case LFUN_TEXTCLASS_APPLY: {
1488 recordUndoFullDocument(view());
1489 Buffer * buffer = owner->buffer();
1491 lyx::textclass_type const old_class =
1492 buffer->params().textclass;
1494 loadTextclass(argument);
1496 std::pair<bool, lyx::textclass_type> const tc_pair =
1497 textclasslist.NumberOfClass(argument);
1502 lyx::textclass_type const new_class = tc_pair.second;
1503 if (old_class == new_class)
1507 owner->message(_("Converting document to new document class..."));
1508 StableDocIterator backcur(view()->cursor());
1510 lyx::cap::SwitchBetweenClasses(
1511 old_class, new_class,
1512 buffer->paragraphs(), el);
1514 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1515 bufferErrors(*buffer, el);
1516 view()->showErrorList(_("Class switch"));
1517 updateCounters(*buffer);
1522 case LFUN_TEXTCLASS_LOAD:
1523 loadTextclass(argument);
1526 case LFUN_LYXRC_APPLY: {
1527 LyXRC const lyxrc_orig = lyxrc;
1529 istringstream ss(argument);
1530 bool const success = lyxrc.read(ss) == 0;
1533 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1534 << "Unable to read lyxrc data"
1539 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1544 view()->cursor().dispatch(cmd);
1545 update |= view()->cursor().result().update();
1546 if (!view()->cursor().result().dispatched())
1547 update |= view()->dispatch(cmd);
1552 if (view()->available()) {
1553 // Redraw screen unless explicitly told otherwise.
1554 // This also initializes the position cache for all insets
1555 // in (at least partially) visible top-level paragraphs.
1557 view()->update(Update::FitCursor | Update::Force);
1559 view()->update(Update::FitCursor);
1561 // if we executed a mutating lfun, mark the buffer as dirty
1562 // FIXME: Why not use flag.enabled() but call getStatus again?
1563 if (getStatus(cmd).enabled()
1564 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1565 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1566 view()->buffer()->markDirty();
1569 if (view()->cursor().inTexted()) {
1570 view()->owner()->updateLayoutChoice();
1573 sendDispatchMessage(_(getMessage()), cmd);
1577 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1579 owner->updateMenubar();
1580 owner->updateToolbars();
1582 const bool verbose = (cmd.origin == FuncRequest::UI
1583 || cmd.origin == FuncRequest::COMMANDBUFFER);
1585 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1586 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1588 owner->message(msg);
1592 string dispatch_msg = msg;
1593 if (!dispatch_msg.empty())
1594 dispatch_msg += ' ';
1596 string comname = lyxaction.getActionName(cmd.action);
1598 bool argsadded = false;
1600 if (!cmd.argument.empty()) {
1601 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1602 comname += ' ' + cmd.argument;
1607 string const shortcuts = toplevel_keymap->printbindings(cmd);
1609 if (!shortcuts.empty())
1610 comname += ": " + shortcuts;
1611 else if (!argsadded && !cmd.argument.empty())
1612 comname += ' ' + cmd.argument;
1614 if (!comname.empty()) {
1615 comname = rtrim(comname);
1616 dispatch_msg += '(' + rtrim(comname) + ')';
1619 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1620 if (!dispatch_msg.empty())
1621 owner->message(dispatch_msg);
1625 void LyXFunc::setupLocalKeymap()
1627 keyseq.stdmap = toplevel_keymap.get();
1628 keyseq.curmap = toplevel_keymap.get();
1629 cancel_meta_seq.stdmap = toplevel_keymap.get();
1630 cancel_meta_seq.curmap = toplevel_keymap.get();
1634 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1636 string initpath = lyxrc.document_path;
1637 string filename(name);
1639 if (view()->available()) {
1640 string const trypath = owner->buffer()->filePath();
1641 // If directory is writeable, use this as default.
1642 if (IsDirWriteable(trypath))
1646 static int newfile_number;
1648 if (filename.empty()) {
1649 filename = AddName(lyxrc.document_path,
1650 "newfile" + convert<string>(++newfile_number) + ".lyx");
1651 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1653 filename = AddName(lyxrc.document_path,
1654 "newfile" + convert<string>(newfile_number) +
1659 // The template stuff
1662 FileDialog fileDlg(_("Select template file"),
1663 LFUN_SELECT_FILE_SYNC,
1664 make_pair(string(_("Documents|#o#O")),
1665 string(lyxrc.document_path)),
1666 make_pair(string(_("Templates|#T#t")),
1667 string(lyxrc.template_path)));
1669 FileDialog::Result result =
1670 fileDlg.open(lyxrc.template_path,
1671 FileFilterList(_("LyX Documents (*.lyx)")),
1674 if (result.first == FileDialog::Later)
1676 if (result.second.empty())
1678 templname = result.second;
1681 view()->newFile(filename, templname, !name.empty());
1685 void LyXFunc::open(string const & fname)
1687 string initpath = lyxrc.document_path;
1689 if (view()->available()) {
1690 string const trypath = owner->buffer()->filePath();
1691 // If directory is writeable, use this as default.
1692 if (IsDirWriteable(trypath))
1698 if (fname.empty()) {
1699 FileDialog fileDlg(_("Select document to open"),
1701 make_pair(string(_("Documents|#o#O")),
1702 string(lyxrc.document_path)),
1703 make_pair(string(_("Examples|#E#e")),
1704 string(AddPath(package().system_support(), "examples"))));
1706 FileDialog::Result result =
1707 fileDlg.open(initpath,
1708 FileFilterList(_("LyX Documents (*.lyx)")),
1711 if (result.first == FileDialog::Later)
1714 filename = result.second;
1716 // check selected filename
1717 if (filename.empty()) {
1718 owner->message(_("Canceled."));
1724 // get absolute path of file and add ".lyx" to the filename if
1726 string const fullpath = FileSearch(string(), filename, "lyx");
1727 if (!fullpath.empty()) {
1728 filename = fullpath;
1731 string const disp_fn(MakeDisplayPath(filename));
1733 // if the file doesn't exist, let the user create one
1734 if (!fs::exists(filename)) {
1735 // the user specifically chose this name. Believe them.
1736 view()->newFile(filename, "", true);
1740 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1743 if (view()->loadLyXFile(filename)) {
1744 str2 = bformat(_("Document %1$s opened."), disp_fn);
1746 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1748 owner->message(str2);
1752 void LyXFunc::doImport(string const & argument)
1755 string filename = split(argument, format, ' ');
1757 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1758 << " file: " << filename << endl;
1760 // need user interaction
1761 if (filename.empty()) {
1762 string initpath = lyxrc.document_path;
1764 if (view()->available()) {
1765 string const trypath = owner->buffer()->filePath();
1766 // If directory is writeable, use this as default.
1767 if (IsDirWriteable(trypath))
1771 string const text = bformat(_("Select %1$s file to import"),
1772 formats.prettyName(format));
1774 FileDialog fileDlg(text,
1776 make_pair(string(_("Documents|#o#O")),
1777 string(lyxrc.document_path)),
1778 make_pair(string(_("Examples|#E#e")),
1779 string(AddPath(package().system_support(), "examples"))));
1781 string const filter = formats.prettyName(format)
1782 + " (*." + formats.extension(format) + ')';
1784 FileDialog::Result result =
1785 fileDlg.open(initpath,
1786 FileFilterList(filter),
1789 if (result.first == FileDialog::Later)
1792 filename = result.second;
1794 // check selected filename
1795 if (filename.empty())
1796 owner->message(_("Canceled."));
1799 if (filename.empty())
1802 // get absolute path of file
1803 filename = MakeAbsPath(filename);
1805 string const lyxfile = ChangeExtension(filename, ".lyx");
1807 // Check if the document already is open
1808 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1809 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1810 owner->message(_("Canceled."));
1815 // if the file exists already, and we didn't do
1816 // -i lyx thefile.lyx, warn
1817 if (fs::exists(lyxfile) && filename != lyxfile) {
1818 string const file = MakeDisplayPath(lyxfile, 30);
1820 string text = bformat(_("The document %1$s already exists.\n\n"
1821 "Do you want to over-write that document?"), file);
1822 int const ret = Alert::prompt(_("Over-write document?"),
1823 text, 0, 1, _("&Over-write"), _("&Cancel"));
1826 owner->message(_("Canceled."));
1831 Importer::Import(owner, filename, format);
1835 void LyXFunc::closeBuffer()
1837 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1838 if (bufferlist.empty()) {
1839 // need this otherwise SEGV may occur while
1840 // trying to set variables that don't exist
1841 // since there's no current buffer
1842 owner->getDialogs().hideBufferDependent();
1844 view()->setBuffer(bufferlist.first());
1850 // Each "owner" should have it's own message method. lyxview and
1851 // the minibuffer would use the minibuffer, but lyxserver would
1852 // send an ERROR signal to its client. Alejandro 970603
1853 // This function is bit problematic when it comes to NLS, to make the
1854 // lyx servers client be language indepenent we must not translate
1855 // strings sent to this func.
1856 void LyXFunc::setErrorMessage(string const & m) const
1858 dispatch_buffer = m;
1863 void LyXFunc::setMessage(string const & m) const
1865 dispatch_buffer = m;
1869 string const LyXFunc::viewStatusMessage()
1871 // When meta-fake key is pressed, show the key sequence so far + "M-".
1873 return keyseq.print() + "M-";
1875 // Else, when a non-complete key sequence is pressed,
1876 // show the available options.
1877 if (keyseq.length() > 0 && !keyseq.deleted())
1878 return keyseq.printOptions();
1880 if (!view()->available())
1881 return _("Welcome to LyX!");
1883 return view()->cursor().currentState();
1887 BufferView * LyXFunc::view() const
1889 BOOST_ASSERT(owner);
1890 return owner->view().get();
1894 bool LyXFunc::wasMetaKey() const
1896 return (meta_fake_bit != key_modifier::none);
1902 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1904 // Why the switch you might ask. It is a trick to ensure that all
1905 // the elements in the LyXRCTags enum is handled. As you can see
1906 // there are no breaks at all. So it is just a huge fall-through.
1907 // The nice thing is that we will get a warning from the compiler
1908 // if we forget an element.
1909 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1911 case LyXRC::RC_ACCEPT_COMPOUND:
1912 case LyXRC::RC_ALT_LANG:
1913 case LyXRC::RC_ASCIIROFF_COMMAND:
1914 case LyXRC::RC_ASCII_LINELEN:
1915 case LyXRC::RC_AUTOREGIONDELETE:
1916 case LyXRC::RC_AUTORESET_OPTIONS:
1917 case LyXRC::RC_AUTOSAVE:
1918 case LyXRC::RC_AUTO_NUMBER:
1919 case LyXRC::RC_BACKUPDIR_PATH:
1920 case LyXRC::RC_BIBTEX_COMMAND:
1921 case LyXRC::RC_BINDFILE:
1922 case LyXRC::RC_CHECKLASTFILES:
1923 case LyXRC::RC_CHKTEX_COMMAND:
1924 case LyXRC::RC_CONVERTER:
1925 case LyXRC::RC_COPIER:
1926 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1927 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1928 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1929 case LyXRC::RC_CYGWIN_PATH_FIX:
1930 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1931 namespace os = lyx::support::os;
1932 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1934 case LyXRC::RC_DATE_INSERT_FORMAT:
1935 case LyXRC::RC_DEFAULT_LANGUAGE:
1936 case LyXRC::RC_DEFAULT_PAPERSIZE:
1937 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1938 case LyXRC::RC_DISPLAY_GRAPHICS:
1939 case LyXRC::RC_DOCUMENTPATH:
1940 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1941 if (fs::exists(lyxrc_new.document_path) &&
1942 fs::is_directory(lyxrc_new.document_path)) {
1943 using lyx::support::package;
1944 package().document_dir() = lyxrc.document_path;
1947 case LyXRC::RC_ESC_CHARS:
1948 case LyXRC::RC_FONT_ENCODING:
1949 case LyXRC::RC_FORMAT:
1950 case LyXRC::RC_INDEX_COMMAND:
1951 case LyXRC::RC_INPUT:
1952 case LyXRC::RC_KBMAP:
1953 case LyXRC::RC_KBMAP_PRIMARY:
1954 case LyXRC::RC_KBMAP_SECONDARY:
1955 case LyXRC::RC_LABEL_INIT_LENGTH:
1956 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1957 case LyXRC::RC_LANGUAGE_AUTO_END:
1958 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1959 case LyXRC::RC_LANGUAGE_COMMAND_END:
1960 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1961 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1962 case LyXRC::RC_LANGUAGE_PACKAGE:
1963 case LyXRC::RC_LANGUAGE_USE_BABEL:
1964 case LyXRC::RC_LASTFILES:
1965 case LyXRC::RC_MAKE_BACKUP:
1966 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1967 case LyXRC::RC_NUMLASTFILES:
1968 case LyXRC::RC_PATH_PREFIX:
1969 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1970 using lyx::support::prependEnvPath;
1971 prependEnvPath("PATH", lyxrc.path_prefix);
1973 case LyXRC::RC_PERS_DICT:
1974 case LyXRC::RC_POPUP_BOLD_FONT:
1975 case LyXRC::RC_POPUP_FONT_ENCODING:
1976 case LyXRC::RC_POPUP_NORMAL_FONT:
1977 case LyXRC::RC_PREVIEW:
1978 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1979 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1980 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1981 case LyXRC::RC_PRINTCOPIESFLAG:
1982 case LyXRC::RC_PRINTER:
1983 case LyXRC::RC_PRINTEVENPAGEFLAG:
1984 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1985 case LyXRC::RC_PRINTFILEEXTENSION:
1986 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1987 case LyXRC::RC_PRINTODDPAGEFLAG:
1988 case LyXRC::RC_PRINTPAGERANGEFLAG:
1989 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1990 case LyXRC::RC_PRINTPAPERFLAG:
1991 case LyXRC::RC_PRINTREVERSEFLAG:
1992 case LyXRC::RC_PRINTSPOOL_COMMAND:
1993 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1994 case LyXRC::RC_PRINTTOFILE:
1995 case LyXRC::RC_PRINTTOPRINTER:
1996 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1997 case LyXRC::RC_PRINT_COMMAND:
1998 case LyXRC::RC_RTL_SUPPORT:
1999 case LyXRC::RC_SCREEN_DPI:
2000 case LyXRC::RC_SCREEN_FONT_ENCODING:
2001 case LyXRC::RC_SCREEN_FONT_ROMAN:
2002 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2003 case LyXRC::RC_SCREEN_FONT_SANS:
2004 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2005 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2006 case LyXRC::RC_SCREEN_FONT_SIZES:
2007 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2008 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2009 case LyXRC::RC_SCREEN_ZOOM:
2010 case LyXRC::RC_SERVERPIPE:
2011 case LyXRC::RC_SET_COLOR:
2012 case LyXRC::RC_SHOW_BANNER:
2013 case LyXRC::RC_SPELL_COMMAND:
2014 case LyXRC::RC_TEMPDIRPATH:
2015 case LyXRC::RC_TEMPLATEPATH:
2016 case LyXRC::RC_TEX_ALLOWS_SPACES:
2017 case LyXRC::RC_UIFILE:
2018 case LyXRC::RC_USER_EMAIL:
2019 case LyXRC::RC_USER_NAME:
2020 case LyXRC::RC_USETEMPDIR:
2021 case LyXRC::RC_USE_ALT_LANG:
2022 case LyXRC::RC_USE_ESC_CHARS:
2023 case LyXRC::RC_USE_INP_ENC:
2024 case LyXRC::RC_USE_PERS_DICT:
2025 case LyXRC::RC_USE_SPELL_LIB:
2026 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2027 case LyXRC::RC_VIEWER:
2028 case LyXRC::RC_WHEEL_JUMP:
2029 case LyXRC::RC_LAST: