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,
311 FuncRequest::KEYBOARD);
313 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
314 owner->message(_("Unknown function."));
319 if (func.action == LFUN_SELFINSERT) {
320 if (encoded_last_key != 0) {
321 string const arg(1, encoded_last_key);
322 dispatch(FuncRequest(LFUN_SELFINSERT, arg,
323 FuncRequest::KEYBOARD));
325 << "SelfInsert arg[`" << arg << "']" << endl;
333 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
335 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
337 LCursor & cur = view()->cursor();
339 /* In LyX/Mac, when a dialog is open, the menus of the
340 application can still be accessed without giving focus to
341 the main window. In this case, we want to disable the menu
342 entries that are buffer-related.
344 Note that this code is not perfect, as bug 1941 attests:
345 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
348 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
351 buf = owner->buffer();
353 if (cmd.action == LFUN_NOACTION) {
354 flag.message(N_("Nothing to do"));
359 switch (cmd.action) {
360 case LFUN_UNKNOWN_ACTION:
361 #ifndef HAVE_LIBAIKSAURUS
362 case LFUN_THESAURUS_ENTRY:
368 flag |= lyx_gui::getStatus(cmd);
371 if (flag.unknown()) {
372 flag.message(N_("Unknown action"));
376 if (!flag.enabled()) {
377 if (flag.message().empty())
378 flag.message(N_("Command disabled"));
382 // Check whether we need a buffer
383 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
385 flag.message(N_("Command not allowed with"
386 "out any document open"));
391 // I would really like to avoid having this switch and rather try to
392 // encode this in the function itself.
393 // -- And I'd rather let an inset decide which LFUNs it is willing
394 // to handle (Andre')
396 switch (cmd.action) {
397 case LFUN_TOOLTIPS_TOGGLE:
398 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
401 case LFUN_READ_ONLY_TOGGLE:
402 flag.setOnOff(buf->isReadonly());
405 case LFUN_SWITCHBUFFER:
406 // toggle on the current buffer, but do not toggle off
407 // the other ones (is that a good idea?)
408 if (cmd.argument == buf->fileName())
413 enable = cmd.argument == "custom"
414 || Exporter::IsExportable(*buf, cmd.argument);
418 enable = buf->isLatex() && lyxrc.chktex_command != "none";
422 enable = Exporter::IsExportable(*buf, "program");
425 case LFUN_LAYOUT_TABULAR:
426 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
430 case LFUN_LAYOUT_PARAGRAPH:
431 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
434 case LFUN_VC_REGISTER:
435 enable = !buf->lyxvc().inUse();
437 case LFUN_VC_CHECKIN:
438 enable = buf->lyxvc().inUse() && !buf->isReadonly();
440 case LFUN_VC_CHECKOUT:
441 enable = buf->lyxvc().inUse() && buf->isReadonly();
445 enable = buf->lyxvc().inUse();
447 case LFUN_MENURELOAD:
448 enable = !buf->isUnnamed() && !buf->isClean();
451 case LFUN_INSET_SETTINGS: {
455 InsetBase::Code code = cur.inset().lyxCode();
457 case InsetBase::TABULAR_CODE:
458 enable = cmd.argument == "tabular";
460 case InsetBase::ERT_CODE:
461 enable = cmd.argument == "ert";
463 case InsetBase::FLOAT_CODE:
464 enable = cmd.argument == "float";
466 case InsetBase::WRAP_CODE:
467 enable = cmd.argument == "wrap";
469 case InsetBase::NOTE_CODE:
470 enable = cmd.argument == "note";
472 case InsetBase::BRANCH_CODE:
473 enable = cmd.argument == "branch";
475 case InsetBase::BOX_CODE:
476 enable = cmd.argument == "box";
484 case LFUN_INSET_APPLY: {
485 string const name = cmd.getArg(0);
486 InsetBase * inset = owner->getDialogs().getOpenInset(name);
488 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
490 bool const success = inset->getStatus(cur, fr, fs);
491 // Every inset is supposed to handle this
492 BOOST_ASSERT(success);
495 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
496 flag |= getStatus(fr);
498 enable = flag.enabled();
502 case LFUN_DIALOG_SHOW: {
503 string const name = cmd.getArg(0);
505 enable = name == "aboutlyx"
509 || name == "texinfo";
510 else if (name == "print")
511 enable = Exporter::IsExportable(*buf, "dvi")
512 && lyxrc.print_command != "none";
513 else if (name == "character" || name == "mathpanel")
514 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
515 else if (name == "latexlog")
516 enable = IsFileReadable(buf->getLogName().second);
517 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
518 else if (name == "spellchecker")
521 else if (name == "vclog")
522 enable = buf->lyxvc().inUse();
526 case LFUN_DIALOG_SHOW_NEW_INSET:
527 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
530 case LFUN_DIALOG_UPDATE: {
531 string const name = cmd.getArg(0);
533 enable = name == "prefs";
537 case LFUN_INSERT_CITATION: {
538 FuncRequest fr(LFUN_INSET_INSERT, "citation");
539 enable = getStatus(fr).enabled();
543 case LFUN_MENUWRITE: {
544 enable = !view()->buffer()->isClean();
548 // this one is difficult to get right. As a half-baked
549 // solution, we consider only the first action of the sequence
550 case LFUN_SEQUENCE: {
551 // argument contains ';'-terminated commands
552 string const firstcmd = token(cmd.argument, ';', 0);
553 FuncRequest func(lyxaction.lookupFunc(firstcmd));
554 func.origin = cmd.origin;
555 flag = getStatus(func);
559 case LFUN_MENUNEWTMPLT:
560 case LFUN_WORDFINDFORWARD:
561 case LFUN_WORDFINDBACKWARD:
563 case LFUN_EXEC_COMMAND:
566 case LFUN_CLOSEBUFFER:
574 case LFUN_RECONFIGURE:
578 case LFUN_DROP_LAYOUTS_CHOICE:
579 case LFUN_MENU_OPEN_BY_NAME:
582 case LFUN_GOTOFILEROW:
583 case LFUN_DIALOG_SHOW_NEXT_INSET:
584 case LFUN_DIALOG_HIDE:
585 case LFUN_DIALOG_DISCONNECT_INSET:
587 case LFUN_TOGGLECURSORFOLLOW:
591 case LFUN_KMAP_TOGGLE:
593 case LFUN_EXPORT_CUSTOM:
595 case LFUN_SAVEPREFERENCES:
596 case LFUN_SCREEN_FONT_UPDATE:
599 case LFUN_EXTERNAL_EDIT:
600 case LFUN_GRAPHICS_EDIT:
601 case LFUN_ALL_INSETS_TOGGLE:
602 case LFUN_LANGUAGE_BUFFER:
603 case LFUN_TEXTCLASS_APPLY:
604 case LFUN_TEXTCLASS_LOAD:
605 case LFUN_SAVE_AS_DEFAULT:
606 case LFUN_BUFFERPARAMS_APPLY:
607 case LFUN_LYXRC_APPLY:
608 case LFUN_NEXTBUFFER:
609 case LFUN_PREVIOUSBUFFER:
610 // these are handled in our dispatch()
615 if (!::getStatus(cur, cmd, flag))
616 flag = view()->getStatus(cmd);
622 // Can we use a readonly buffer?
623 if (buf && buf->isReadonly()
624 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
625 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
626 flag.message(N_("Document is read-only"));
630 // Are we in a DELETED change-tracking region?
631 if (buf && buf->params().tracking_changes
632 && lookupChange(cur, true) == Change::DELETED
633 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
634 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
635 flag.message(N_("This portion of the document is deleted."));
639 // the default error message if we disable the command
640 if (!flag.enabled() && flag.message().empty())
641 flag.message(N_("Command disabled"));
649 bool ensureBufferClean(BufferView * bv)
651 Buffer & buf = *bv->buffer();
655 string const file = MakeDisplayPath(buf.fileName(), 30);
656 string text = bformat(_("The document %1$s has unsaved "
657 "changes.\n\nDo you want to save "
658 "the document?"), file);
659 int const ret = Alert::prompt(_("Save changed document?"),
660 text, 0, 1, _("&Save"),
664 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
666 return buf.isClean();
670 void showPrintError(string const & name)
672 string str = bformat(_("Could not print the document %1$s.\n"
673 "Check that your printer is set up correctly."),
674 MakeDisplayPath(name, 50));
675 Alert::error(_("Print document failed"), str);
679 void loadTextclass(string const & name)
681 std::pair<bool, lyx::textclass_type> const tc_pair =
682 textclasslist.NumberOfClass(name);
684 if (!tc_pair.first) {
685 lyxerr << "Document class \"" << name
686 << "\" does not exist."
691 lyx::textclass_type const tc = tc_pair.second;
693 if (!textclasslist[tc].load()) {
694 string s = bformat(_("The document could not be converted\n"
695 "into the document class %1$s."),
696 textclasslist[tc].name());
697 Alert::error(_("Could not change class"), s);
702 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
707 void LyXFunc::dispatch(FuncRequest const & cmd)
709 BOOST_ASSERT(view());
710 string const argument = cmd.argument;
711 kb_action const action = cmd.action;
713 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
714 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
716 // we have not done anything wrong yet.
718 dispatch_buffer.erase();
722 FuncStatus const flag = getStatus(cmd);
723 if (!flag.enabled()) {
724 // We cannot use this function here
725 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
726 << lyxaction.getActionName(action)
727 << " [" << action << "] is disabled at this location"
729 setErrorMessage(flag.message());
732 if (view()->available())
733 view()->hideCursor();
737 case LFUN_WORDFINDFORWARD:
738 case LFUN_WORDFINDBACKWARD: {
739 static string last_search;
740 string searched_string;
742 if (!argument.empty()) {
743 last_search = argument;
744 searched_string = argument;
746 searched_string = last_search;
749 if (searched_string.empty())
752 bool const fw = action == LFUN_WORDFINDFORWARD;
754 lyx::find::find2string(searched_string, true, false, fw);
755 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
760 owner->message(keyseq.printOptions());
763 case LFUN_EXEC_COMMAND:
764 owner->getToolbars().display("minibuffer", true);
765 owner->focus_command_buffer();
770 meta_fake_bit = key_modifier::none;
771 if (view()->available())
772 // cancel any selection
773 dispatch(FuncRequest(LFUN_MARK_OFF));
774 setMessage(N_("Cancel"));
778 meta_fake_bit = key_modifier::alt;
779 setMessage(keyseq.print());
782 case LFUN_READ_ONLY_TOGGLE:
783 if (owner->buffer()->lyxvc().inUse())
784 owner->buffer()->lyxvc().toggleReadOnly();
786 owner->buffer()->setReadonly(
787 !owner->buffer()->isReadonly());
790 // --- Menus -----------------------------------------------
792 menuNew(argument, false);
795 case LFUN_MENUNEWTMPLT:
796 menuNew(argument, true);
799 case LFUN_CLOSEBUFFER:
804 if (!owner->buffer()->isUnnamed()) {
805 string const str = bformat(_("Saving document %1$s..."),
806 MakeDisplayPath(owner->buffer()->fileName()));
808 MenuWrite(owner->buffer());
809 owner->message(str + _(" done."));
811 WriteAs(owner->buffer());
815 WriteAs(owner->buffer(), argument);
818 case LFUN_MENURELOAD: {
819 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
820 string text = bformat(_("Any changes will be lost. Are you sure "
821 "you want to revert to the saved version of the document %1$s?"), file);
822 int const ret = Alert::prompt(_("Revert to saved document?"),
823 text, 0, 1, _("&Revert"), _("&Cancel"));
831 Exporter::Export(owner->buffer(), argument, true);
832 view()->showErrorList(BufferFormat(*owner->buffer()));
836 Exporter::Preview(owner->buffer(), argument);
837 view()->showErrorList(BufferFormat(*owner->buffer()));
841 Exporter::Export(owner->buffer(), "program", true);
842 view()->showErrorList(_("Build"));
846 owner->buffer()->runChktex();
847 view()->showErrorList(_("ChkTeX"));
851 if (argument == "custom")
852 owner->getDialogs().show("sendto");
854 Exporter::Export(owner->buffer(), argument, false);
855 view()->showErrorList(BufferFormat(*owner->buffer()));
859 case LFUN_EXPORT_CUSTOM: {
861 string command = split(argument, format_name, ' ');
862 Format const * format = formats.getFormat(format_name);
864 lyxerr << "Format \"" << format_name
865 << "\" not recognized!"
870 Buffer * buffer = owner->buffer();
872 // The name of the file created by the conversion process
875 // Output to filename
876 if (format->name() == "lyx") {
877 string const latexname =
878 buffer->getLatexName(false);
879 filename = ChangeExtension(latexname,
880 format->extension());
881 filename = AddName(buffer->temppath(), filename);
883 if (!buffer->writeFile(filename))
887 Exporter::Export(buffer, format_name, true,
891 // Substitute $$FName for filename
892 if (!contains(command, "$$FName"))
893 command = "( " + command + " ) < $$FName";
894 command = subst(command, "$$FName", filename);
896 // Execute the command in the background
898 call.startscript(Systemcall::DontWait, command);
905 string command = split(split(argument, target, ' '),
909 || target_name.empty()
910 || command.empty()) {
911 lyxerr << "Unable to parse \""
912 << argument << '"' << std::endl;
915 if (target != "printer" && target != "file") {
916 lyxerr << "Unrecognized target \""
917 << target << '"' << std::endl;
921 Buffer * buffer = owner->buffer();
923 if (!Exporter::Export(buffer, "dvi", true)) {
924 showPrintError(buffer->fileName());
928 // Push directory path.
929 string const path = buffer->temppath();
932 // there are three cases here:
933 // 1. we print to a file
934 // 2. we print directly to a printer
935 // 3. we print using a spool command (print to file first)
938 string const dviname =
939 ChangeExtension(buffer->getLatexName(true),
942 if (target == "printer") {
943 if (!lyxrc.print_spool_command.empty()) {
944 // case 3: print using a spool
945 string const psname =
946 ChangeExtension(dviname,".ps");
947 command += lyxrc.print_to_file
950 + QuoteName(dviname);
953 lyxrc.print_spool_command +' ';
954 if (target_name != "default") {
955 command2 += lyxrc.print_spool_printerprefix
959 command2 += QuoteName(psname);
961 // If successful, then spool command
962 res = one.startscript(
967 res = one.startscript(
968 Systemcall::DontWait,
971 // case 2: print directly to a printer
972 res = one.startscript(
973 Systemcall::DontWait,
974 command + QuoteName(dviname));
978 // case 1: print to a file
979 command += lyxrc.print_to_file
980 + QuoteName(MakeAbsPath(target_name,
983 + QuoteName(dviname);
984 res = one.startscript(Systemcall::DontWait,
989 showPrintError(buffer->fileName());
998 QuitLyX(argument == "force");
1001 case LFUN_TOCVIEW: {
1002 InsetCommandParams p("tableofcontents");
1003 string const data = InsetCommandMailer::params2string("toc", p);
1004 owner->getDialogs().show("toc", data, 0);
1012 case LFUN_RECONFIGURE:
1013 Reconfigure(view());
1016 case LFUN_HELP_OPEN: {
1017 string const arg = argument;
1019 setErrorMessage(N_("Missing argument"));
1022 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1023 if (fname.empty()) {
1024 lyxerr << "LyX: unable to find documentation file `"
1025 << arg << "'. Bad installation?" << endl;
1028 owner->message(bformat(_("Opening help file %1$s..."),
1029 MakeDisplayPath(fname)));
1030 view()->loadLyXFile(fname, false);
1034 // --- version control -------------------------------
1035 case LFUN_VC_REGISTER:
1036 if (!ensureBufferClean(view()))
1038 if (!owner->buffer()->lyxvc().inUse()) {
1039 owner->buffer()->lyxvc().registrer();
1044 case LFUN_VC_CHECKIN:
1045 if (!ensureBufferClean(view()))
1047 if (owner->buffer()->lyxvc().inUse()
1048 && !owner->buffer()->isReadonly()) {
1049 owner->buffer()->lyxvc().checkIn();
1054 case LFUN_VC_CHECKOUT:
1055 if (!ensureBufferClean(view()))
1057 if (owner->buffer()->lyxvc().inUse()
1058 && owner->buffer()->isReadonly()) {
1059 owner->buffer()->lyxvc().checkOut();
1064 case LFUN_VC_REVERT:
1065 owner->buffer()->lyxvc().revert();
1070 owner->buffer()->lyxvc().undoLast();
1074 // --- buffers ----------------------------------------
1075 case LFUN_SWITCHBUFFER:
1076 view()->setBuffer(bufferlist.getBuffer(argument));
1079 case LFUN_NEXTBUFFER:
1080 view()->setBuffer(bufferlist.next(view()->buffer()));
1083 case LFUN_PREVIOUSBUFFER:
1084 view()->setBuffer(bufferlist.previous(view()->buffer()));
1088 NewFile(view(), argument);
1091 case LFUN_FILE_OPEN:
1095 case LFUN_DROP_LAYOUTS_CHOICE:
1096 owner->getToolbars().openLayoutList();
1099 case LFUN_MENU_OPEN_BY_NAME:
1100 owner->getMenubar().openByName(argument);
1103 // --- lyxserver commands ----------------------------
1105 setMessage(owner->buffer()->fileName());
1106 lyxerr[Debug::INFO] << "FNAME["
1107 << owner->buffer()->fileName()
1112 dispatch_buffer = keyseq.print();
1113 lyxserver->notifyClient(dispatch_buffer);
1116 case LFUN_GOTOFILEROW: {
1119 istringstream is(argument);
1120 is >> file_name >> row;
1121 if (prefixIs(file_name, package().temp_dir())) {
1122 // Needed by inverse dvi search. If it is a file
1123 // in tmpdir, call the apropriated function
1124 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1126 // Must replace extension of the file to be .lyx
1127 // and get full path
1128 string const s = ChangeExtension(file_name, ".lyx");
1129 // Either change buffer or load the file
1130 if (bufferlist.exists(s)) {
1131 view()->setBuffer(bufferlist.getBuffer(s));
1133 view()->loadLyXFile(s);
1137 view()->setCursorFromRow(row);
1140 // see BufferView_pimpl::center()
1141 view()->updateScrollbar();
1145 case LFUN_DIALOG_SHOW: {
1146 string const name = cmd.getArg(0);
1147 string data = trim(cmd.argument.substr(name.size()));
1149 if (name == "character") {
1150 data = freefont2string();
1152 owner->getDialogs().show("character", data);
1155 else if (name == "latexlog") {
1156 pair<Buffer::LogType, string> const logfile =
1157 owner->buffer()->getLogName();
1158 switch (logfile.first) {
1159 case Buffer::latexlog:
1162 case Buffer::buildlog:
1166 data += logfile.second;
1167 owner->getDialogs().show("log", data);
1169 else if (name == "vclog") {
1170 string const data = "vc " +
1171 owner->buffer()->lyxvc().getLogFile();
1172 owner->getDialogs().show("log", data);
1175 owner->getDialogs().show(name, data);
1179 case LFUN_DIALOG_SHOW_NEW_INSET: {
1180 string const name = cmd.getArg(0);
1181 string data = trim(cmd.argument.substr(name.size()));
1182 if (name == "bibitem" ||
1189 InsetCommandParams p(name);
1190 data = InsetCommandMailer::params2string(name, p);
1191 } else if (name == "include") {
1192 InsetCommandParams p(data);
1193 data = InsetIncludeMailer::params2string(p);
1194 } else if (name == "box") {
1195 // \c data == "Boxed" || "Frameless" etc
1196 InsetBoxParams p(data);
1197 data = InsetBoxMailer::params2string(p);
1198 } else if (name == "branch") {
1199 InsetBranchParams p;
1200 data = InsetBranchMailer::params2string(p);
1201 } else if (name == "citation") {
1202 InsetCommandParams p("cite");
1203 data = InsetCommandMailer::params2string(name, p);
1204 } else if (name == "ert") {
1205 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1206 } else if (name == "external") {
1207 InsetExternalParams p;
1208 Buffer const & buffer = *owner->buffer();
1209 data = InsetExternalMailer::params2string(p, buffer);
1210 } else if (name == "float") {
1212 data = InsetFloatMailer::params2string(p);
1213 } else if (name == "graphics") {
1214 InsetGraphicsParams p;
1215 Buffer const & buffer = *owner->buffer();
1216 data = InsetGraphicsMailer::params2string(p, buffer);
1217 } else if (name == "note") {
1219 data = InsetNoteMailer::params2string(p);
1220 } else if (name == "vspace") {
1222 data = InsetVSpaceMailer::params2string(space);
1223 } else if (name == "wrap") {
1225 data = InsetWrapMailer::params2string(p);
1227 owner->getDialogs().show(name, data, 0);
1231 case LFUN_DIALOG_SHOW_NEXT_INSET:
1234 case LFUN_DIALOG_UPDATE: {
1235 string const & name = argument;
1236 // Can only update a dialog connected to an existing inset
1237 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1239 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1240 inset->dispatch(view()->cursor(), fr);
1241 } else if (name == "paragraph") {
1242 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1243 } else if (name == "prefs") {
1244 owner->getDialogs().update(name, string());
1249 case LFUN_DIALOG_HIDE:
1250 Dialogs::hide(argument, 0);
1253 case LFUN_DIALOG_DISCONNECT_INSET:
1254 owner->getDialogs().disconnect(argument);
1258 case LFUN_INSERT_CITATION: {
1259 if (!argument.empty()) {
1260 // we can have one optional argument, delimited by '|'
1261 // citation-insert <key>|<text_before>
1262 // this should be enhanced to also support text_after
1263 // and citation style
1264 string arg = argument;
1266 if (contains(argument, "|")) {
1267 arg = token(argument, '|', 0);
1268 opt1 = '[' + token(argument, '|', 1) + ']';
1270 std::ostringstream os;
1271 os << "citation LatexCommand\n"
1272 << "\\cite" << opt1 << "{" << arg << "}\n"
1274 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1277 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1281 case LFUN_CHILDOPEN: {
1282 string const filename =
1283 MakeAbsPath(argument, owner->buffer()->filePath());
1284 setMessage(N_("Opening child document ") +
1285 MakeDisplayPath(filename) + "...");
1286 view()->savePosition(0);
1287 string const parentfilename = owner->buffer()->fileName();
1288 if (bufferlist.exists(filename))
1289 view()->setBuffer(bufferlist.getBuffer(filename));
1291 view()->loadLyXFile(filename);
1292 // Set the parent name of the child document.
1293 // This makes insertion of citations and references in the child work,
1294 // when the target is in the parent or another child document.
1295 owner->buffer()->setParentName(parentfilename);
1299 case LFUN_TOGGLECURSORFOLLOW:
1300 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1304 owner->getIntl().KeyMapOn(false);
1307 case LFUN_KMAP_PRIM:
1308 owner->getIntl().KeyMapPrim();
1312 owner->getIntl().KeyMapSec();
1315 case LFUN_KMAP_TOGGLE:
1316 owner->getIntl().ToggleKeyMap();
1322 string rest = split(argument, countstr, ' ');
1323 istringstream is(countstr);
1326 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1327 for (int i = 0; i < count; ++i)
1328 dispatch(lyxaction.lookupFunc(rest));
1332 case LFUN_SEQUENCE: {
1333 // argument contains ';'-terminated commands
1334 string arg = argument;
1335 while (!arg.empty()) {
1337 arg = split(arg, first, ';');
1338 FuncRequest func(lyxaction.lookupFunc(first));
1339 func.origin = cmd.origin;
1345 case LFUN_SAVEPREFERENCES: {
1346 Path p(package().user_support());
1347 lyxrc.write("preferences", false);
1351 case LFUN_SCREEN_FONT_UPDATE:
1352 // handle the screen font changes.
1353 lyxrc.set_font_norm_type();
1354 lyx_gui::update_fonts();
1355 // All visible buffers will need resize
1359 case LFUN_SET_COLOR: {
1361 string const x11_name = split(argument, lyx_name, ' ');
1362 if (lyx_name.empty() || x11_name.empty()) {
1363 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1368 bool const graphicsbg_changed =
1369 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1370 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1372 if (!lcolor.setColor(lyx_name, x11_name)) {
1374 bformat(_("Set-color \"%1$s\" failed "
1375 "- color is undefined or "
1376 "may not be redefined"), lyx_name));
1380 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1382 if (graphicsbg_changed) {
1383 #ifdef WITH_WARNINGS
1384 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1387 lyx::graphics::GCache::get().changeDisplay(true);
1394 owner->message(argument);
1397 case LFUN_TOOLTIPS_TOGGLE:
1398 owner->getDialogs().toggleTooltips();
1401 case LFUN_EXTERNAL_EDIT: {
1402 FuncRequest fr(action, argument);
1403 InsetExternal().dispatch(view()->cursor(), fr);
1407 case LFUN_GRAPHICS_EDIT: {
1408 FuncRequest fr(action, argument);
1409 InsetGraphics().dispatch(view()->cursor(), fr);
1413 case LFUN_INSET_APPLY: {
1414 string const name = cmd.getArg(0);
1415 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1417 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1418 inset->dispatch(view()->cursor(), fr);
1420 FuncRequest fr(LFUN_INSET_INSERT, argument);
1423 // ideally, the update flag should be set by the insets,
1424 // but this is not possible currently
1429 case LFUN_ALL_INSETS_TOGGLE: {
1431 string const name = split(argument, action, ' ');
1432 InsetBase::Code const inset_code =
1433 InsetBase::translate(name);
1435 LCursor & cur = view()->cursor();
1436 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1438 InsetBase & inset = owner->buffer()->inset();
1439 InsetIterator it = inset_iterator_begin(inset);
1440 InsetIterator const end = inset_iterator_end(inset);
1441 for (; it != end; ++it) {
1442 if (inset_code == InsetBase::NO_CODE
1443 || inset_code == it->lyxCode()) {
1444 LCursor tmpcur = cur;
1445 tmpcur.pushLeft(*it);
1446 it->dispatch(tmpcur, fr);
1453 case LFUN_LANGUAGE_BUFFER: {
1454 Buffer & buffer = *owner->buffer();
1455 Language const * oldL = buffer.params().language;
1456 Language const * newL = languages.getLanguage(argument);
1457 if (!newL || oldL == newL)
1460 if (oldL->RightToLeft() == newL->RightToLeft()
1461 && !buffer.isMultiLingual())
1462 buffer.changeLanguage(oldL, newL);
1464 buffer.updateDocLang(newL);
1468 case LFUN_SAVE_AS_DEFAULT: {
1469 string const fname =
1470 AddName(AddPath(package().user_support(), "templates/"),
1472 Buffer defaults(fname);
1474 istringstream ss(argument);
1477 int const unknown_tokens = defaults.readHeader(lex);
1479 if (unknown_tokens != 0) {
1480 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1481 << unknown_tokens << " unknown token"
1482 << (unknown_tokens == 1 ? "" : "s")
1486 if (defaults.writeFile(defaults.fileName()))
1487 setMessage(_("Document defaults saved in ")
1488 + MakeDisplayPath(fname));
1490 setErrorMessage(_("Unable to save document defaults"));
1494 case LFUN_BUFFERPARAMS_APPLY: {
1495 biblio::CiteEngine const engine =
1496 owner->buffer()->params().cite_engine;
1498 istringstream ss(argument);
1501 int const unknown_tokens =
1502 owner->buffer()->readHeader(lex);
1504 if (unknown_tokens != 0) {
1505 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1506 << unknown_tokens << " unknown token"
1507 << (unknown_tokens == 1 ? "" : "s")
1510 if (engine == owner->buffer()->params().cite_engine)
1513 LCursor & cur = view()->cursor();
1514 FuncRequest fr(LFUN_INSET_REFRESH);
1516 InsetBase & inset = owner->buffer()->inset();
1517 InsetIterator it = inset_iterator_begin(inset);
1518 InsetIterator const end = inset_iterator_end(inset);
1519 for (; it != end; ++it)
1520 if (it->lyxCode() == InsetBase::CITE_CODE)
1521 it->dispatch(cur, fr);
1525 case LFUN_TEXTCLASS_APPLY: {
1526 Buffer * buffer = owner->buffer();
1528 lyx::textclass_type const old_class =
1529 buffer->params().textclass;
1531 loadTextclass(argument);
1533 std::pair<bool, lyx::textclass_type> const tc_pair =
1534 textclasslist.NumberOfClass(argument);
1539 lyx::textclass_type const new_class = tc_pair.second;
1540 if (old_class == new_class)
1544 owner->message(_("Converting document to new document class..."));
1545 recordUndoFullDocument(view());
1546 buffer->params().textclass = new_class;
1547 StableDocIterator backcur(view()->cursor());
1549 lyx::cap::SwitchBetweenClasses(
1550 old_class, new_class,
1551 buffer->paragraphs(), el);
1553 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1554 bufferErrors(*buffer, el);
1555 view()->showErrorList(_("Class switch"));
1556 updateCounters(*buffer);
1561 case LFUN_TEXTCLASS_LOAD:
1562 loadTextclass(argument);
1565 case LFUN_LYXRC_APPLY: {
1566 LyXRC const lyxrc_orig = lyxrc;
1568 istringstream ss(argument);
1569 bool const success = lyxrc.read(ss) == 0;
1572 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1573 << "Unable to read lyxrc data"
1578 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1583 view()->cursor().dispatch(cmd);
1584 update |= view()->cursor().result().update();
1585 if (!view()->cursor().result().dispatched())
1586 update |= view()->dispatch(cmd);
1591 if (view()->available()) {
1592 // Redraw screen unless explicitly told otherwise.
1593 // This also initializes the position cache for all insets
1594 // in (at least partially) visible top-level paragraphs.
1596 view()->update(Update::FitCursor | Update::Force);
1598 view()->update(Update::FitCursor);
1600 // if we executed a mutating lfun, mark the buffer as dirty
1602 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1603 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1604 view()->buffer()->markDirty();
1607 if (view()->cursor().inTexted()) {
1608 view()->owner()->updateLayoutChoice();
1611 sendDispatchMessage(_(getMessage()), cmd);
1615 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1617 /* When an action did not originate from the UI/kbd, it makes
1618 * sense to avoid updating the GUI. It turns out that this
1619 * fixes bug 1941, for reasons that are described here:
1620 * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1622 if (cmd.origin != FuncRequest::INTERNAL) {
1623 owner->updateMenubar();
1624 owner->updateToolbars();
1627 const bool verbose = (cmd.origin == FuncRequest::UI
1628 || cmd.origin == FuncRequest::COMMANDBUFFER);
1630 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1631 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1633 owner->message(msg);
1637 string dispatch_msg = msg;
1638 if (!dispatch_msg.empty())
1639 dispatch_msg += ' ';
1641 string comname = lyxaction.getActionName(cmd.action);
1643 bool argsadded = false;
1645 if (!cmd.argument.empty()) {
1646 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1647 comname += ' ' + cmd.argument;
1652 string const shortcuts = toplevel_keymap->printbindings(cmd);
1654 if (!shortcuts.empty())
1655 comname += ": " + shortcuts;
1656 else if (!argsadded && !cmd.argument.empty())
1657 comname += ' ' + cmd.argument;
1659 if (!comname.empty()) {
1660 comname = rtrim(comname);
1661 dispatch_msg += '(' + rtrim(comname) + ')';
1664 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1665 if (!dispatch_msg.empty())
1666 owner->message(dispatch_msg);
1670 void LyXFunc::setupLocalKeymap()
1672 keyseq.stdmap = toplevel_keymap.get();
1673 keyseq.curmap = toplevel_keymap.get();
1674 cancel_meta_seq.stdmap = toplevel_keymap.get();
1675 cancel_meta_seq.curmap = toplevel_keymap.get();
1679 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1681 string initpath = lyxrc.document_path;
1682 string filename(name);
1684 if (view()->available()) {
1685 string const trypath = owner->buffer()->filePath();
1686 // If directory is writeable, use this as default.
1687 if (IsDirWriteable(trypath))
1691 static int newfile_number;
1693 if (filename.empty()) {
1694 filename = AddName(lyxrc.document_path,
1695 "newfile" + convert<string>(++newfile_number) + ".lyx");
1696 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1698 filename = AddName(lyxrc.document_path,
1699 "newfile" + convert<string>(newfile_number) +
1704 // The template stuff
1707 FileDialog fileDlg(_("Select template file"),
1708 LFUN_SELECT_FILE_SYNC,
1709 make_pair(string(_("Documents|#o#O")),
1710 string(lyxrc.document_path)),
1711 make_pair(string(_("Templates|#T#t")),
1712 string(lyxrc.template_path)));
1714 FileDialog::Result result =
1715 fileDlg.open(lyxrc.template_path,
1716 FileFilterList(_("LyX Documents (*.lyx)")),
1719 if (result.first == FileDialog::Later)
1721 if (result.second.empty())
1723 templname = result.second;
1726 view()->newFile(filename, templname, !name.empty());
1730 void LyXFunc::open(string const & fname)
1732 string initpath = lyxrc.document_path;
1734 if (view()->available()) {
1735 string const trypath = owner->buffer()->filePath();
1736 // If directory is writeable, use this as default.
1737 if (IsDirWriteable(trypath))
1743 if (fname.empty()) {
1744 FileDialog fileDlg(_("Select document to open"),
1746 make_pair(string(_("Documents|#o#O")),
1747 string(lyxrc.document_path)),
1748 make_pair(string(_("Examples|#E#e")),
1749 string(AddPath(package().system_support(), "examples"))));
1751 FileDialog::Result result =
1752 fileDlg.open(initpath,
1753 FileFilterList(_("LyX Documents (*.lyx)")),
1756 if (result.first == FileDialog::Later)
1759 filename = result.second;
1761 // check selected filename
1762 if (filename.empty()) {
1763 owner->message(_("Canceled."));
1769 // get absolute path of file and add ".lyx" to the filename if
1771 string const fullpath = FileSearch(string(), filename, "lyx");
1772 if (!fullpath.empty()) {
1773 filename = fullpath;
1776 string const disp_fn(MakeDisplayPath(filename));
1778 // if the file doesn't exist, let the user create one
1779 if (!fs::exists(filename)) {
1780 // the user specifically chose this name. Believe them.
1781 view()->newFile(filename, "", true);
1785 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1788 if (view()->loadLyXFile(filename)) {
1789 str2 = bformat(_("Document %1$s opened."), disp_fn);
1791 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1793 owner->message(str2);
1797 void LyXFunc::doImport(string const & argument)
1800 string filename = split(argument, format, ' ');
1802 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1803 << " file: " << filename << endl;
1805 // need user interaction
1806 if (filename.empty()) {
1807 string initpath = lyxrc.document_path;
1809 if (view()->available()) {
1810 string const trypath = owner->buffer()->filePath();
1811 // If directory is writeable, use this as default.
1812 if (IsDirWriteable(trypath))
1816 string const text = bformat(_("Select %1$s file to import"),
1817 formats.prettyName(format));
1819 FileDialog fileDlg(text,
1821 make_pair(string(_("Documents|#o#O")),
1822 string(lyxrc.document_path)),
1823 make_pair(string(_("Examples|#E#e")),
1824 string(AddPath(package().system_support(), "examples"))));
1826 string const filter = formats.prettyName(format)
1827 + " (*." + formats.extension(format) + ')';
1829 FileDialog::Result result =
1830 fileDlg.open(initpath,
1831 FileFilterList(filter),
1834 if (result.first == FileDialog::Later)
1837 filename = result.second;
1839 // check selected filename
1840 if (filename.empty())
1841 owner->message(_("Canceled."));
1844 if (filename.empty())
1847 // get absolute path of file
1848 filename = MakeAbsPath(filename);
1850 string const lyxfile = ChangeExtension(filename, ".lyx");
1852 // Check if the document already is open
1853 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1854 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1855 owner->message(_("Canceled."));
1860 // if the file exists already, and we didn't do
1861 // -i lyx thefile.lyx, warn
1862 if (fs::exists(lyxfile) && filename != lyxfile) {
1863 string const file = MakeDisplayPath(lyxfile, 30);
1865 string text = bformat(_("The document %1$s already exists.\n\n"
1866 "Do you want to over-write that document?"), file);
1867 int const ret = Alert::prompt(_("Over-write document?"),
1868 text, 0, 1, _("&Over-write"), _("&Cancel"));
1871 owner->message(_("Canceled."));
1876 Importer::Import(owner, filename, format);
1880 void LyXFunc::closeBuffer()
1882 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1883 if (bufferlist.empty()) {
1884 // need this otherwise SEGV may occur while
1885 // trying to set variables that don't exist
1886 // since there's no current buffer
1887 owner->getDialogs().hideBufferDependent();
1889 view()->setBuffer(bufferlist.first());
1895 // Each "owner" should have it's own message method. lyxview and
1896 // the minibuffer would use the minibuffer, but lyxserver would
1897 // send an ERROR signal to its client. Alejandro 970603
1898 // This function is bit problematic when it comes to NLS, to make the
1899 // lyx servers client be language indepenent we must not translate
1900 // strings sent to this func.
1901 void LyXFunc::setErrorMessage(string const & m) const
1903 dispatch_buffer = m;
1908 void LyXFunc::setMessage(string const & m) const
1910 dispatch_buffer = m;
1914 string const LyXFunc::viewStatusMessage()
1916 // When meta-fake key is pressed, show the key sequence so far + "M-".
1918 return keyseq.print() + "M-";
1920 // Else, when a non-complete key sequence is pressed,
1921 // show the available options.
1922 if (keyseq.length() > 0 && !keyseq.deleted())
1923 return keyseq.printOptions();
1925 if (!view()->available())
1926 return _("Welcome to LyX!");
1928 return view()->cursor().currentState();
1932 BufferView * LyXFunc::view() const
1934 BOOST_ASSERT(owner);
1935 return owner->view().get();
1939 bool LyXFunc::wasMetaKey() const
1941 return (meta_fake_bit != key_modifier::none);
1947 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1949 // Why the switch you might ask. It is a trick to ensure that all
1950 // the elements in the LyXRCTags enum is handled. As you can see
1951 // there are no breaks at all. So it is just a huge fall-through.
1952 // The nice thing is that we will get a warning from the compiler
1953 // if we forget an element.
1954 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1956 case LyXRC::RC_ACCEPT_COMPOUND:
1957 case LyXRC::RC_ALT_LANG:
1958 case LyXRC::RC_ASCIIROFF_COMMAND:
1959 case LyXRC::RC_ASCII_LINELEN:
1960 case LyXRC::RC_AUTOREGIONDELETE:
1961 case LyXRC::RC_AUTORESET_OPTIONS:
1962 case LyXRC::RC_AUTOSAVE:
1963 case LyXRC::RC_AUTO_NUMBER:
1964 case LyXRC::RC_BACKUPDIR_PATH:
1965 case LyXRC::RC_BIBTEX_COMMAND:
1966 case LyXRC::RC_BINDFILE:
1967 case LyXRC::RC_CHECKLASTFILES:
1968 case LyXRC::RC_CHKTEX_COMMAND:
1969 case LyXRC::RC_CONVERTER:
1970 case LyXRC::RC_COPIER:
1971 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1972 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1973 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1974 case LyXRC::RC_CYGWIN_PATH_FIX:
1975 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1976 namespace os = lyx::support::os;
1977 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1979 case LyXRC::RC_DATE_INSERT_FORMAT:
1980 case LyXRC::RC_DEFAULT_LANGUAGE:
1981 case LyXRC::RC_DEFAULT_PAPERSIZE:
1982 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1983 case LyXRC::RC_DISPLAY_GRAPHICS:
1984 case LyXRC::RC_DOCUMENTPATH:
1985 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1986 if (fs::exists(lyxrc_new.document_path) &&
1987 fs::is_directory(lyxrc_new.document_path)) {
1988 using lyx::support::package;
1989 package().document_dir() = lyxrc.document_path;
1992 case LyXRC::RC_ESC_CHARS:
1993 case LyXRC::RC_FONT_ENCODING:
1994 case LyXRC::RC_FORMAT:
1995 case LyXRC::RC_INDEX_COMMAND:
1996 case LyXRC::RC_INPUT:
1997 case LyXRC::RC_KBMAP:
1998 case LyXRC::RC_KBMAP_PRIMARY:
1999 case LyXRC::RC_KBMAP_SECONDARY:
2000 case LyXRC::RC_LABEL_INIT_LENGTH:
2001 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2002 case LyXRC::RC_LANGUAGE_AUTO_END:
2003 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2004 case LyXRC::RC_LANGUAGE_COMMAND_END:
2005 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2006 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2007 case LyXRC::RC_LANGUAGE_PACKAGE:
2008 case LyXRC::RC_LANGUAGE_USE_BABEL:
2009 case LyXRC::RC_LASTFILES:
2010 case LyXRC::RC_MAKE_BACKUP:
2011 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2012 case LyXRC::RC_NUMLASTFILES:
2013 case LyXRC::RC_PATH_PREFIX:
2014 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2015 using lyx::support::prependEnvPath;
2016 prependEnvPath("PATH", lyxrc.path_prefix);
2018 case LyXRC::RC_PERS_DICT:
2019 case LyXRC::RC_POPUP_BOLD_FONT:
2020 case LyXRC::RC_POPUP_FONT_ENCODING:
2021 case LyXRC::RC_POPUP_NORMAL_FONT:
2022 case LyXRC::RC_PREVIEW:
2023 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2024 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2025 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2026 case LyXRC::RC_PRINTCOPIESFLAG:
2027 case LyXRC::RC_PRINTER:
2028 case LyXRC::RC_PRINTEVENPAGEFLAG:
2029 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2030 case LyXRC::RC_PRINTFILEEXTENSION:
2031 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2032 case LyXRC::RC_PRINTODDPAGEFLAG:
2033 case LyXRC::RC_PRINTPAGERANGEFLAG:
2034 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2035 case LyXRC::RC_PRINTPAPERFLAG:
2036 case LyXRC::RC_PRINTREVERSEFLAG:
2037 case LyXRC::RC_PRINTSPOOL_COMMAND:
2038 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2039 case LyXRC::RC_PRINTTOFILE:
2040 case LyXRC::RC_PRINTTOPRINTER:
2041 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2042 case LyXRC::RC_PRINT_COMMAND:
2043 case LyXRC::RC_RTL_SUPPORT:
2044 case LyXRC::RC_SCREEN_DPI:
2045 case LyXRC::RC_SCREEN_FONT_ENCODING:
2046 case LyXRC::RC_SCREEN_FONT_ROMAN:
2047 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2048 case LyXRC::RC_SCREEN_FONT_SANS:
2049 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2050 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2051 case LyXRC::RC_SCREEN_FONT_SIZES:
2052 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2053 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2054 case LyXRC::RC_SCREEN_ZOOM:
2055 case LyXRC::RC_SERVERPIPE:
2056 case LyXRC::RC_SET_COLOR:
2057 case LyXRC::RC_SHOW_BANNER:
2058 case LyXRC::RC_SPELL_COMMAND:
2059 case LyXRC::RC_TEMPDIRPATH:
2060 case LyXRC::RC_TEMPLATEPATH:
2061 case LyXRC::RC_TEX_ALLOWS_SPACES:
2062 case LyXRC::RC_UIFILE:
2063 case LyXRC::RC_USER_EMAIL:
2064 case LyXRC::RC_USER_NAME:
2065 case LyXRC::RC_USETEMPDIR:
2066 case LyXRC::RC_USE_ALT_LANG:
2067 case LyXRC::RC_USE_ESC_CHARS:
2068 case LyXRC::RC_USE_INP_ENC:
2069 case LyXRC::RC_USE_PERS_DICT:
2070 case LyXRC::RC_USE_SPELL_LIB:
2071 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2072 case LyXRC::RC_VIEWER:
2073 case LyXRC::RC_WHEEL_JUMP:
2074 case LyXRC::RC_LAST: