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);
1414 case LFUN_LANGUAGE_BUFFER: {
1415 Buffer & buffer = *owner->buffer();
1416 Language const * oldL = buffer.params().language;
1417 Language const * newL = languages.getLanguage(argument);
1418 if (!newL || oldL == newL)
1421 if (oldL->RightToLeft() == newL->RightToLeft()
1422 && !buffer.isMultiLingual())
1423 buffer.changeLanguage(oldL, newL);
1425 buffer.updateDocLang(newL);
1429 case LFUN_SAVE_AS_DEFAULT: {
1430 string const fname =
1431 AddName(AddPath(package().user_support(), "templates/"),
1433 Buffer defaults(fname);
1435 istringstream ss(argument);
1438 int const unknown_tokens = defaults.readHeader(lex);
1440 if (unknown_tokens != 0) {
1441 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1442 << unknown_tokens << " unknown token"
1443 << (unknown_tokens == 1 ? "" : "s")
1447 if (defaults.writeFile(defaults.fileName()))
1448 setMessage(_("Document defaults saved in ")
1449 + MakeDisplayPath(fname));
1451 setErrorMessage(_("Unable to save document defaults"));
1455 case LFUN_BUFFERPARAMS_APPLY: {
1456 biblio::CiteEngine const engine =
1457 owner->buffer()->params().cite_engine;
1459 istringstream ss(argument);
1462 int const unknown_tokens =
1463 owner->buffer()->readHeader(lex);
1465 if (unknown_tokens != 0) {
1466 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1467 << unknown_tokens << " unknown token"
1468 << (unknown_tokens == 1 ? "" : "s")
1471 if (engine == owner->buffer()->params().cite_engine)
1474 LCursor & cur = view()->cursor();
1475 FuncRequest fr(LFUN_INSET_REFRESH);
1477 InsetBase & inset = owner->buffer()->inset();
1478 InsetIterator it = inset_iterator_begin(inset);
1479 InsetIterator const end = inset_iterator_end(inset);
1480 for (; it != end; ++it)
1481 if (it->lyxCode() == InsetBase::CITE_CODE)
1482 it->dispatch(cur, fr);
1486 case LFUN_TEXTCLASS_APPLY: {
1487 recordUndoFullDocument(view());
1488 Buffer * buffer = owner->buffer();
1490 lyx::textclass_type const old_class =
1491 buffer->params().textclass;
1493 loadTextclass(argument);
1495 std::pair<bool, lyx::textclass_type> const tc_pair =
1496 textclasslist.NumberOfClass(argument);
1501 lyx::textclass_type const new_class = tc_pair.second;
1502 if (old_class == new_class)
1506 owner->message(_("Converting document to new document class..."));
1507 StableDocIterator backcur(view()->cursor());
1509 lyx::cap::SwitchBetweenClasses(
1510 old_class, new_class,
1511 buffer->paragraphs(), el);
1513 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1514 bufferErrors(*buffer, el);
1515 view()->showErrorList(_("Class switch"));
1516 updateCounters(*buffer);
1521 case LFUN_TEXTCLASS_LOAD:
1522 loadTextclass(argument);
1525 case LFUN_LYXRC_APPLY: {
1526 LyXRC const lyxrc_orig = lyxrc;
1528 istringstream ss(argument);
1529 bool const success = lyxrc.read(ss) == 0;
1532 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1533 << "Unable to read lyxrc data"
1538 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1543 view()->cursor().dispatch(cmd);
1544 update |= view()->cursor().result().update();
1545 if (!view()->cursor().result().dispatched())
1546 update |= view()->dispatch(cmd);
1551 if (view()->available()) {
1552 // Redraw screen unless explicitly told otherwise.
1553 // This also initializes the position cache for all insets
1554 // in (at least partially) visible top-level paragraphs.
1556 view()->update(Update::FitCursor | Update::Force);
1558 view()->update(Update::FitCursor);
1560 // if we executed a mutating lfun, mark the buffer as dirty
1561 // FIXME: Why not use flag.enabled() but call getStatus again?
1562 if (getStatus(cmd).enabled()
1563 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1564 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1565 view()->buffer()->markDirty();
1568 if (view()->cursor().inTexted()) {
1569 view()->owner()->updateLayoutChoice();
1572 sendDispatchMessage(_(getMessage()), cmd);
1576 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1578 owner->updateMenubar();
1579 owner->updateToolbars();
1581 const bool verbose = (cmd.origin == FuncRequest::UI
1582 || cmd.origin == FuncRequest::COMMANDBUFFER);
1584 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1585 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1587 owner->message(msg);
1591 string dispatch_msg = msg;
1592 if (!dispatch_msg.empty())
1593 dispatch_msg += ' ';
1595 string comname = lyxaction.getActionName(cmd.action);
1597 bool argsadded = false;
1599 if (!cmd.argument.empty()) {
1600 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1601 comname += ' ' + cmd.argument;
1606 string const shortcuts = toplevel_keymap->printbindings(cmd);
1608 if (!shortcuts.empty())
1609 comname += ": " + shortcuts;
1610 else if (!argsadded && !cmd.argument.empty())
1611 comname += ' ' + cmd.argument;
1613 if (!comname.empty()) {
1614 comname = rtrim(comname);
1615 dispatch_msg += '(' + rtrim(comname) + ')';
1618 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1619 if (!dispatch_msg.empty())
1620 owner->message(dispatch_msg);
1624 void LyXFunc::setupLocalKeymap()
1626 keyseq.stdmap = toplevel_keymap.get();
1627 keyseq.curmap = toplevel_keymap.get();
1628 cancel_meta_seq.stdmap = toplevel_keymap.get();
1629 cancel_meta_seq.curmap = toplevel_keymap.get();
1633 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1635 string initpath = lyxrc.document_path;
1636 string filename(name);
1638 if (view()->available()) {
1639 string const trypath = owner->buffer()->filePath();
1640 // If directory is writeable, use this as default.
1641 if (IsDirWriteable(trypath))
1645 static int newfile_number;
1647 if (filename.empty()) {
1648 filename = AddName(lyxrc.document_path,
1649 "newfile" + convert<string>(++newfile_number) + ".lyx");
1650 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1652 filename = AddName(lyxrc.document_path,
1653 "newfile" + convert<string>(newfile_number) +
1658 // The template stuff
1661 FileDialog fileDlg(_("Select template file"),
1662 LFUN_SELECT_FILE_SYNC,
1663 make_pair(string(_("Documents|#o#O")),
1664 string(lyxrc.document_path)),
1665 make_pair(string(_("Templates|#T#t")),
1666 string(lyxrc.template_path)));
1668 FileDialog::Result result =
1669 fileDlg.open(lyxrc.template_path,
1670 FileFilterList(_("LyX Documents (*.lyx)")),
1673 if (result.first == FileDialog::Later)
1675 if (result.second.empty())
1677 templname = result.second;
1680 view()->newFile(filename, templname, !name.empty());
1684 void LyXFunc::open(string const & fname)
1686 string initpath = lyxrc.document_path;
1688 if (view()->available()) {
1689 string const trypath = owner->buffer()->filePath();
1690 // If directory is writeable, use this as default.
1691 if (IsDirWriteable(trypath))
1697 if (fname.empty()) {
1698 FileDialog fileDlg(_("Select document to open"),
1700 make_pair(string(_("Documents|#o#O")),
1701 string(lyxrc.document_path)),
1702 make_pair(string(_("Examples|#E#e")),
1703 string(AddPath(package().system_support(), "examples"))));
1705 FileDialog::Result result =
1706 fileDlg.open(initpath,
1707 FileFilterList(_("LyX Documents (*.lyx)")),
1710 if (result.first == FileDialog::Later)
1713 filename = result.second;
1715 // check selected filename
1716 if (filename.empty()) {
1717 owner->message(_("Canceled."));
1723 // get absolute path of file and add ".lyx" to the filename if
1725 string const fullpath = FileSearch(string(), filename, "lyx");
1726 if (!fullpath.empty()) {
1727 filename = fullpath;
1730 string const disp_fn(MakeDisplayPath(filename));
1732 // if the file doesn't exist, let the user create one
1733 if (!fs::exists(filename)) {
1734 // the user specifically chose this name. Believe them.
1735 view()->newFile(filename, "", true);
1739 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1742 if (view()->loadLyXFile(filename)) {
1743 str2 = bformat(_("Document %1$s opened."), disp_fn);
1745 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1747 owner->message(str2);
1751 void LyXFunc::doImport(string const & argument)
1754 string filename = split(argument, format, ' ');
1756 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1757 << " file: " << filename << endl;
1759 // need user interaction
1760 if (filename.empty()) {
1761 string initpath = lyxrc.document_path;
1763 if (view()->available()) {
1764 string const trypath = owner->buffer()->filePath();
1765 // If directory is writeable, use this as default.
1766 if (IsDirWriteable(trypath))
1770 string const text = bformat(_("Select %1$s file to import"),
1771 formats.prettyName(format));
1773 FileDialog fileDlg(text,
1775 make_pair(string(_("Documents|#o#O")),
1776 string(lyxrc.document_path)),
1777 make_pair(string(_("Examples|#E#e")),
1778 string(AddPath(package().system_support(), "examples"))));
1780 string const filter = formats.prettyName(format)
1781 + " (*." + formats.extension(format) + ')';
1783 FileDialog::Result result =
1784 fileDlg.open(initpath,
1785 FileFilterList(filter),
1788 if (result.first == FileDialog::Later)
1791 filename = result.second;
1793 // check selected filename
1794 if (filename.empty())
1795 owner->message(_("Canceled."));
1798 if (filename.empty())
1801 // get absolute path of file
1802 filename = MakeAbsPath(filename);
1804 string const lyxfile = ChangeExtension(filename, ".lyx");
1806 // Check if the document already is open
1807 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1808 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1809 owner->message(_("Canceled."));
1814 // if the file exists already, and we didn't do
1815 // -i lyx thefile.lyx, warn
1816 if (fs::exists(lyxfile) && filename != lyxfile) {
1817 string const file = MakeDisplayPath(lyxfile, 30);
1819 string text = bformat(_("The document %1$s already exists.\n\n"
1820 "Do you want to over-write that document?"), file);
1821 int const ret = Alert::prompt(_("Over-write document?"),
1822 text, 0, 1, _("&Over-write"), _("&Cancel"));
1825 owner->message(_("Canceled."));
1830 Importer::Import(owner, filename, format);
1834 void LyXFunc::closeBuffer()
1836 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1837 if (bufferlist.empty()) {
1838 // need this otherwise SEGV may occur while
1839 // trying to set variables that don't exist
1840 // since there's no current buffer
1841 owner->getDialogs().hideBufferDependent();
1843 view()->setBuffer(bufferlist.first());
1849 // Each "owner" should have it's own message method. lyxview and
1850 // the minibuffer would use the minibuffer, but lyxserver would
1851 // send an ERROR signal to its client. Alejandro 970603
1852 // This function is bit problematic when it comes to NLS, to make the
1853 // lyx servers client be language indepenent we must not translate
1854 // strings sent to this func.
1855 void LyXFunc::setErrorMessage(string const & m) const
1857 dispatch_buffer = m;
1862 void LyXFunc::setMessage(string const & m) const
1864 dispatch_buffer = m;
1868 string const LyXFunc::viewStatusMessage()
1870 // When meta-fake key is pressed, show the key sequence so far + "M-".
1872 return keyseq.print() + "M-";
1874 // Else, when a non-complete key sequence is pressed,
1875 // show the available options.
1876 if (keyseq.length() > 0 && !keyseq.deleted())
1877 return keyseq.printOptions();
1879 if (!view()->available())
1880 return _("Welcome to LyX!");
1882 return view()->cursor().currentState();
1886 BufferView * LyXFunc::view() const
1888 BOOST_ASSERT(owner);
1889 return owner->view().get();
1893 bool LyXFunc::wasMetaKey() const
1895 return (meta_fake_bit != key_modifier::none);
1901 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1903 // Why the switch you might ask. It is a trick to ensure that all
1904 // the elements in the LyXRCTags enum is handled. As you can see
1905 // there are no breaks at all. So it is just a huge fall-through.
1906 // The nice thing is that we will get a warning from the compiler
1907 // if we forget an element.
1908 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1910 case LyXRC::RC_ACCEPT_COMPOUND:
1911 case LyXRC::RC_ALT_LANG:
1912 case LyXRC::RC_ASCIIROFF_COMMAND:
1913 case LyXRC::RC_ASCII_LINELEN:
1914 case LyXRC::RC_AUTOREGIONDELETE:
1915 case LyXRC::RC_AUTORESET_OPTIONS:
1916 case LyXRC::RC_AUTOSAVE:
1917 case LyXRC::RC_AUTO_NUMBER:
1918 case LyXRC::RC_BACKUPDIR_PATH:
1919 case LyXRC::RC_BIBTEX_COMMAND:
1920 case LyXRC::RC_BINDFILE:
1921 case LyXRC::RC_CHECKLASTFILES:
1922 case LyXRC::RC_CHKTEX_COMMAND:
1923 case LyXRC::RC_CONVERTER:
1924 case LyXRC::RC_COPIER:
1925 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1926 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1927 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1928 case LyXRC::RC_CYGWIN_PATH_FIX:
1929 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1930 namespace os = lyx::support::os;
1931 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1933 case LyXRC::RC_DATE_INSERT_FORMAT:
1934 case LyXRC::RC_DEFAULT_LANGUAGE:
1935 case LyXRC::RC_DEFAULT_PAPERSIZE:
1936 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1937 case LyXRC::RC_DISPLAY_GRAPHICS:
1938 case LyXRC::RC_DOCUMENTPATH:
1939 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1940 if (fs::exists(lyxrc_new.document_path) &&
1941 fs::is_directory(lyxrc_new.document_path)) {
1942 using lyx::support::package;
1943 package().document_dir() = lyxrc.document_path;
1946 case LyXRC::RC_ESC_CHARS:
1947 case LyXRC::RC_FONT_ENCODING:
1948 case LyXRC::RC_FORMAT:
1949 case LyXRC::RC_INDEX_COMMAND:
1950 case LyXRC::RC_INPUT:
1951 case LyXRC::RC_KBMAP:
1952 case LyXRC::RC_KBMAP_PRIMARY:
1953 case LyXRC::RC_KBMAP_SECONDARY:
1954 case LyXRC::RC_LABEL_INIT_LENGTH:
1955 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1956 case LyXRC::RC_LANGUAGE_AUTO_END:
1957 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1958 case LyXRC::RC_LANGUAGE_COMMAND_END:
1959 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1960 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1961 case LyXRC::RC_LANGUAGE_PACKAGE:
1962 case LyXRC::RC_LANGUAGE_USE_BABEL:
1963 case LyXRC::RC_LASTFILES:
1964 case LyXRC::RC_MAKE_BACKUP:
1965 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1966 case LyXRC::RC_NUMLASTFILES:
1967 case LyXRC::RC_PATH_PREFIX:
1968 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1969 using lyx::support::prependEnvPath;
1970 prependEnvPath("PATH", lyxrc.path_prefix);
1972 case LyXRC::RC_PERS_DICT:
1973 case LyXRC::RC_POPUP_BOLD_FONT:
1974 case LyXRC::RC_POPUP_FONT_ENCODING:
1975 case LyXRC::RC_POPUP_NORMAL_FONT:
1976 case LyXRC::RC_PREVIEW:
1977 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1978 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1979 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1980 case LyXRC::RC_PRINTCOPIESFLAG:
1981 case LyXRC::RC_PRINTER:
1982 case LyXRC::RC_PRINTEVENPAGEFLAG:
1983 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1984 case LyXRC::RC_PRINTFILEEXTENSION:
1985 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1986 case LyXRC::RC_PRINTODDPAGEFLAG:
1987 case LyXRC::RC_PRINTPAGERANGEFLAG:
1988 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1989 case LyXRC::RC_PRINTPAPERFLAG:
1990 case LyXRC::RC_PRINTREVERSEFLAG:
1991 case LyXRC::RC_PRINTSPOOL_COMMAND:
1992 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1993 case LyXRC::RC_PRINTTOFILE:
1994 case LyXRC::RC_PRINTTOPRINTER:
1995 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1996 case LyXRC::RC_PRINT_COMMAND:
1997 case LyXRC::RC_RTL_SUPPORT:
1998 case LyXRC::RC_SCREEN_DPI:
1999 case LyXRC::RC_SCREEN_FONT_ENCODING:
2000 case LyXRC::RC_SCREEN_FONT_ROMAN:
2001 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2002 case LyXRC::RC_SCREEN_FONT_SANS:
2003 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2004 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2005 case LyXRC::RC_SCREEN_FONT_SIZES:
2006 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2007 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2008 case LyXRC::RC_SCREEN_ZOOM:
2009 case LyXRC::RC_SERVERPIPE:
2010 case LyXRC::RC_SET_COLOR:
2011 case LyXRC::RC_SHOW_BANNER:
2012 case LyXRC::RC_SPELL_COMMAND:
2013 case LyXRC::RC_TEMPDIRPATH:
2014 case LyXRC::RC_TEMPLATEPATH:
2015 case LyXRC::RC_TEX_ALLOWS_SPACES:
2016 case LyXRC::RC_UIFILE:
2017 case LyXRC::RC_USER_EMAIL:
2018 case LyXRC::RC_USER_NAME:
2019 case LyXRC::RC_USETEMPDIR:
2020 case LyXRC::RC_USE_ALT_LANG:
2021 case LyXRC::RC_USE_ESC_CHARS:
2022 case LyXRC::RC_USE_INP_ENC:
2023 case LyXRC::RC_USE_PERS_DICT:
2024 case LyXRC::RC_USE_SPELL_LIB:
2025 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2026 case LyXRC::RC_VIEWER:
2027 case LyXRC::RC_WHEEL_JUMP:
2028 case LyXRC::RC_LAST: