3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
24 #include "BranchList.h"
26 #include "buffer_funcs.h"
27 #include "bufferlist.h"
28 #include "bufferparams.h"
29 #include "BufferView.h"
31 #include "CutAndPaste.h"
33 #include "dispatchresult.h"
35 #include "errorlist.h"
38 #include "funcrequest.h"
41 #include "insetiterator.h"
47 #include "LyXAction.h"
52 #include "lyxserver.h"
53 #include "lyxtextclasslist.h"
55 #include "paragraph.h"
56 #include "pariterator.h"
57 #include "ParagraphParameters.h"
60 #include "insets/insetbox.h"
61 #include "insets/insetbranch.h"
62 #include "insets/insetcommand.h"
63 #include "insets/insetert.h"
64 #include "insets/insetexternal.h"
65 #include "insets/insetfloat.h"
66 #include "insets/insetgraphics.h"
67 #include "insets/insetinclude.h"
68 #include "insets/insetnote.h"
69 #include "insets/insettabular.h"
70 #include "insets/insetvspace.h"
71 #include "insets/insetwrap.h"
73 #include "frontends/Alert.h"
74 #include "frontends/Dialogs.h"
75 #include "frontends/FileDialog.h"
76 #include "frontends/lyx_gui.h"
77 #include "frontends/LyXKeySym.h"
78 #include "frontends/LyXView.h"
79 #include "frontends/Menubar.h"
80 #include "frontends/Toolbars.h"
82 #include "support/environment.h"
83 #include "support/filefilterlist.h"
84 #include "support/filetools.h"
85 #include "support/forkedcontr.h"
86 #include "support/fs_extras.h"
87 #include "support/lstrings.h"
88 #include "support/path.h"
89 #include "support/package.h"
90 #include "support/systemcall.h"
91 #include "support/convert.h"
92 #include "support/os.h"
94 #include <boost/current_function.hpp>
95 #include <boost/filesystem/operations.hpp>
99 using bv_funcs::freefont2string;
101 using lyx::support::AbsolutePath;
102 using lyx::support::AddName;
103 using lyx::support::AddPath;
104 using lyx::support::bformat;
105 using lyx::support::ChangeExtension;
106 using lyx::support::contains;
107 using lyx::support::FileFilterList;
108 using lyx::support::FileSearch;
109 using lyx::support::ForkedcallsController;
110 using lyx::support::i18nLibFileSearch;
111 using lyx::support::IsDirWriteable;
112 using lyx::support::IsFileReadable;
113 using lyx::support::isStrInt;
114 using lyx::support::MakeAbsPath;
115 using lyx::support::MakeDisplayPath;
116 using lyx::support::package;
117 using lyx::support::Path;
118 using lyx::support::QuoteName;
119 using lyx::support::rtrim;
120 using lyx::support::split;
121 using lyx::support::subst;
122 using lyx::support::Systemcall;
123 using lyx::support::token;
124 using lyx::support::trim;
125 using lyx::support::prefixIs;
128 using std::make_pair;
131 using std::istringstream;
133 namespace biblio = lyx::biblio;
134 namespace fs = boost::filesystem;
137 extern BufferList bufferlist;
138 extern LyXServer * lyxserver;
140 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
143 extern tex_accent_struct get_accent(kb_action action);
148 bool getStatus(LCursor cursor,
149 FuncRequest const & cmd, FuncStatus & status)
151 // Try to fix cursor in case it is broken.
152 cursor.fixIfBroken();
154 // This is, of course, a mess. Better create a new doc iterator and use
155 // this in Inset::getStatus. This might require an additional
156 // BufferView * arg, though (which should be avoided)
157 //LCursor safe = *this;
159 for ( ; cursor.depth(); cursor.pop()) {
160 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
161 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
162 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
163 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
165 // The inset's getStatus() will return 'true' if it made
166 // a definitive decision on whether it want to handle the
167 // request or not. The result of this decision is put into
168 // the 'status' parameter.
169 if (cursor.inset().getStatus(cursor, cmd, status)) {
178 /** Return the change status at cursor position, taking in account the
179 * status at each level of the document iterator (a table in a deleted
180 * footnote is deleted).
181 * When \param outer is true, the top slice is not looked at.
183 Change::Type lookupChange(DocIterator const & dit, bool outer = false)
185 size_t const depth = dit.depth() - (outer ? 1 : 0);
187 for (size_t i = 0 ; i < depth ; ++i) {
188 CursorSlice const & slice = dit[i];
189 if (!slice.inset().inMathed()
190 && slice.pos() < slice.paragraph().size()) {
191 Change::Type const ch = slice.paragraph().lookupChange(slice.pos());
192 if (ch != Change::UNCHANGED)
196 return Change::UNCHANGED;
201 LyXFunc::LyXFunc(LyXView * lv)
204 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
205 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
206 meta_fake_bit(key_modifier::none)
211 void LyXFunc::handleKeyFunc(kb_action action)
213 char c = encoded_last_key;
215 if (keyseq.length()) {
219 owner->getIntl().getTransManager()
220 .deadkey(c, get_accent(action).accent, view()->getLyXText());
221 // Need to clear, in case the minibuffer calls these
224 // copied verbatim from do_accent_char
225 view()->cursor().resetAnchor();
230 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
232 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
234 // Do nothing if we have nothing (JMarc)
235 if (!keysym->isOK()) {
236 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
241 if (keysym->isModifier()) {
242 lyxerr[Debug::KEY] << "isModifier true" << endl;
246 Encoding const * encoding = view()->cursor().getEncoding();
248 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
250 // Do a one-deep top-level lookup for
251 // cancel and meta-fake keys. RVDK_PATCH_5
252 cancel_meta_seq.reset();
254 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
255 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
256 << " action first set to [" << func.action << ']'
259 // When not cancel or meta-fake, do the normal lookup.
260 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
261 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
262 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
263 // remove Caps Lock and Mod2 as a modifiers
264 func = keyseq.addkey(keysym, (state | meta_fake_bit));
265 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
266 << "action now set to ["
267 << func.action << ']' << endl;
270 // Dont remove this unless you know what you are doing.
271 meta_fake_bit = key_modifier::none;
273 // Can this happen now ?
274 if (func.action == LFUN_NOACTION) {
275 func = FuncRequest(LFUN_PREFIX);
278 if (lyxerr.debugging(Debug::KEY)) {
279 lyxerr << BOOST_CURRENT_FUNCTION
281 << func.action << "]["
282 << keyseq.print() << ']'
286 // already here we know if it any point in going further
287 // why not return already here if action == -1 and
288 // num_bytes == 0? (Lgb)
290 if (keyseq.length() > 1) {
291 owner->message(keyseq.print());
295 // Maybe user can only reach the key via holding down shift.
296 // Let's see. But only if shift is the only modifier
297 if (func.action == LFUN_UNKNOWN_ACTION &&
298 state == key_modifier::shift) {
299 lyxerr[Debug::KEY] << "Trying without shift" << endl;
300 func = keyseq.addkey(keysym, key_modifier::none);
301 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
304 if (func.action == LFUN_UNKNOWN_ACTION) {
305 // Hmm, we didn't match any of the keysequences. See
306 // if it's normal insertable text not already covered
308 if (keysym->isText() && keyseq.length() == 1) {
309 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
310 func = FuncRequest(LFUN_SELFINSERT);
312 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
313 owner->message(_("Unknown function."));
318 if (func.action == LFUN_SELFINSERT) {
319 if (encoded_last_key != 0) {
320 string const arg(1, encoded_last_key);
321 dispatch(FuncRequest(LFUN_SELFINSERT, arg));
323 << "SelfInsert arg[`" << arg << "']" << endl;
331 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
333 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
335 LCursor & cur = view()->cursor();
337 /* In LyX/Mac, when a dialog is open, the menus of the
338 application can still be accessed without giving focus to
339 the main window. In this case, we want to disable the menu
340 entries that are buffer-related.
342 Note that this code is not perfect, as bug 1941 attests:
343 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
346 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
349 buf = owner->buffer();
351 if (cmd.action == LFUN_NOACTION) {
352 flag.message(N_("Nothing to do"));
357 switch (cmd.action) {
358 case LFUN_UNKNOWN_ACTION:
359 #ifndef HAVE_LIBAIKSAURUS
360 case LFUN_THESAURUS_ENTRY:
366 flag |= lyx_gui::getStatus(cmd);
369 if (flag.unknown()) {
370 flag.message(N_("Unknown action"));
374 if (!flag.enabled()) {
375 if (flag.message().empty())
376 flag.message(N_("Command disabled"));
380 // Check whether we need a buffer
381 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
383 flag.message(N_("Command not allowed with"
384 "out any document open"));
389 // I would really like to avoid having this switch and rather try to
390 // encode this in the function itself.
391 // -- And I'd rather let an inset decide which LFUNs it is willing
392 // to handle (Andre')
394 switch (cmd.action) {
395 case LFUN_TOOLTIPS_TOGGLE:
396 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
399 case LFUN_READ_ONLY_TOGGLE:
400 flag.setOnOff(buf->isReadonly());
403 case LFUN_SWITCHBUFFER:
404 // toggle on the current buffer, but do not toggle off
405 // the other ones (is that a good idea?)
406 if (cmd.argument == buf->fileName())
411 enable = cmd.argument == "custom"
412 || Exporter::IsExportable(*buf, cmd.argument);
416 enable = buf->isLatex() && lyxrc.chktex_command != "none";
420 enable = Exporter::IsExportable(*buf, "program");
423 case LFUN_LAYOUT_TABULAR:
424 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
428 case LFUN_LAYOUT_PARAGRAPH:
429 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
432 case LFUN_VC_REGISTER:
433 enable = !buf->lyxvc().inUse();
435 case LFUN_VC_CHECKIN:
436 enable = buf->lyxvc().inUse() && !buf->isReadonly();
438 case LFUN_VC_CHECKOUT:
439 enable = buf->lyxvc().inUse() && buf->isReadonly();
443 enable = buf->lyxvc().inUse();
445 case LFUN_MENURELOAD:
446 enable = !buf->isUnnamed() && !buf->isClean();
449 case LFUN_INSET_SETTINGS: {
453 InsetBase::Code code = cur.inset().lyxCode();
455 case InsetBase::TABULAR_CODE:
456 enable = cmd.argument == "tabular";
458 case InsetBase::ERT_CODE:
459 enable = cmd.argument == "ert";
461 case InsetBase::FLOAT_CODE:
462 enable = cmd.argument == "float";
464 case InsetBase::WRAP_CODE:
465 enable = cmd.argument == "wrap";
467 case InsetBase::NOTE_CODE:
468 enable = cmd.argument == "note";
470 case InsetBase::BRANCH_CODE:
471 enable = cmd.argument == "branch";
473 case InsetBase::BOX_CODE:
474 enable = cmd.argument == "box";
482 case LFUN_INSET_APPLY: {
483 string const name = cmd.getArg(0);
484 InsetBase * inset = owner->getDialogs().getOpenInset(name);
486 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
488 bool const success = inset->getStatus(cur, fr, fs);
489 // Every inset is supposed to handle this
490 BOOST_ASSERT(success);
493 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
494 flag |= getStatus(fr);
496 enable = flag.enabled();
500 case LFUN_DIALOG_SHOW: {
501 string const name = cmd.getArg(0);
503 enable = name == "aboutlyx"
507 || name == "texinfo";
508 else if (name == "print")
509 enable = Exporter::IsExportable(*buf, "dvi")
510 && lyxrc.print_command != "none";
511 else if (name == "character" || name == "mathpanel")
512 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
513 else if (name == "latexlog")
514 enable = IsFileReadable(buf->getLogName().second);
515 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
516 else if (name == "spellchecker")
519 else if (name == "vclog")
520 enable = buf->lyxvc().inUse();
524 case LFUN_DIALOG_SHOW_NEW_INSET:
525 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
528 case LFUN_DIALOG_UPDATE: {
529 string const name = cmd.getArg(0);
531 enable = name == "prefs";
535 case LFUN_INSERT_CITATION: {
536 FuncRequest fr(LFUN_INSET_INSERT, "citation");
537 enable = getStatus(fr).enabled();
541 // this one is difficult to get right. As a half-baked
542 // solution, we consider only the first action of the sequence
543 case LFUN_SEQUENCE: {
544 // argument contains ';'-terminated commands
545 string const firstcmd = token(cmd.argument, ';', 0);
546 FuncRequest func(lyxaction.lookupFunc(firstcmd));
547 func.origin = cmd.origin;
548 flag = getStatus(func);
552 case LFUN_MENUNEWTMPLT:
553 case LFUN_WORDFINDFORWARD:
554 case LFUN_WORDFINDBACKWARD:
556 case LFUN_EXEC_COMMAND:
559 case LFUN_CLOSEBUFFER:
568 case LFUN_RECONFIGURE:
572 case LFUN_DROP_LAYOUTS_CHOICE:
573 case LFUN_MENU_OPEN_BY_NAME:
576 case LFUN_GOTOFILEROW:
577 case LFUN_DIALOG_SHOW_NEXT_INSET:
578 case LFUN_DIALOG_HIDE:
579 case LFUN_DIALOG_DISCONNECT_INSET:
581 case LFUN_TOGGLECURSORFOLLOW:
585 case LFUN_KMAP_TOGGLE:
587 case LFUN_EXPORT_CUSTOM:
589 case LFUN_SAVEPREFERENCES:
590 case LFUN_SCREEN_FONT_UPDATE:
593 case LFUN_EXTERNAL_EDIT:
594 case LFUN_GRAPHICS_EDIT:
595 case LFUN_ALL_INSETS_TOGGLE:
596 case LFUN_LANGUAGE_BUFFER:
597 case LFUN_TEXTCLASS_APPLY:
598 case LFUN_TEXTCLASS_LOAD:
599 case LFUN_SAVE_AS_DEFAULT:
600 case LFUN_BUFFERPARAMS_APPLY:
601 case LFUN_LYXRC_APPLY:
602 case LFUN_NEXTBUFFER:
603 case LFUN_PREVIOUSBUFFER:
604 // these are handled in our dispatch()
609 if (!::getStatus(cur, cmd, flag))
610 flag = view()->getStatus(cmd);
616 // Can we use a readonly buffer?
617 if (buf && buf->isReadonly()
618 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
619 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
620 flag.message(N_("Document is read-only"));
624 // Are we in a DELETED change-tracking region?
625 if (buf && buf->params().tracking_changes
626 && lookupChange(cur, true) == Change::DELETED
627 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
628 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
629 flag.message(N_("This portion of the document is deleted."));
633 // the default error message if we disable the command
634 if (!flag.enabled() && flag.message().empty())
635 flag.message(N_("Command disabled"));
643 bool ensureBufferClean(BufferView * bv)
645 Buffer & buf = *bv->buffer();
649 string const file = MakeDisplayPath(buf.fileName(), 30);
650 string text = bformat(_("The document %1$s has unsaved "
651 "changes.\n\nDo you want to save "
652 "the document?"), file);
653 int const ret = Alert::prompt(_("Save changed document?"),
654 text, 0, 1, _("&Save"),
658 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
660 return buf.isClean();
664 void showPrintError(string const & name)
666 string str = bformat(_("Could not print the document %1$s.\n"
667 "Check that your printer is set up correctly."),
668 MakeDisplayPath(name, 50));
669 Alert::error(_("Print document failed"), str);
673 void loadTextclass(string const & name)
675 std::pair<bool, lyx::textclass_type> const tc_pair =
676 textclasslist.NumberOfClass(name);
678 if (!tc_pair.first) {
679 lyxerr << "Document class \"" << name
680 << "\" does not exist."
685 lyx::textclass_type const tc = tc_pair.second;
687 if (!textclasslist[tc].load()) {
688 string s = bformat(_("The document could not be converted\n"
689 "into the document class %1$s."),
690 textclasslist[tc].name());
691 Alert::error(_("Could not change class"), s);
696 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
701 void LyXFunc::dispatch(FuncRequest const & cmd)
703 BOOST_ASSERT(view());
704 string const argument = cmd.argument;
705 kb_action const action = cmd.action;
707 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
708 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
710 // we have not done anything wrong yet.
712 dispatch_buffer.erase();
716 FuncStatus const flag = getStatus(cmd);
717 if (!flag.enabled()) {
718 // We cannot use this function here
719 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
720 << lyxaction.getActionName(action)
721 << " [" << action << "] is disabled at this location"
723 setErrorMessage(flag.message());
726 if (view()->available())
727 view()->hideCursor();
731 case LFUN_WORDFINDFORWARD:
732 case LFUN_WORDFINDBACKWARD: {
733 static string last_search;
734 string searched_string;
736 if (!argument.empty()) {
737 last_search = argument;
738 searched_string = argument;
740 searched_string = last_search;
743 if (searched_string.empty())
746 bool const fw = action == LFUN_WORDFINDFORWARD;
748 lyx::find::find2string(searched_string, true, false, fw);
749 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
754 owner->message(keyseq.printOptions());
757 case LFUN_EXEC_COMMAND:
758 owner->getToolbars().display("minibuffer", true);
759 owner->focus_command_buffer();
764 meta_fake_bit = key_modifier::none;
765 if (view()->available())
766 // cancel any selection
767 dispatch(FuncRequest(LFUN_MARK_OFF));
768 setMessage(N_("Cancel"));
772 meta_fake_bit = key_modifier::alt;
773 setMessage(keyseq.print());
776 case LFUN_READ_ONLY_TOGGLE:
777 if (owner->buffer()->lyxvc().inUse())
778 owner->buffer()->lyxvc().toggleReadOnly();
780 owner->buffer()->setReadonly(
781 !owner->buffer()->isReadonly());
784 // --- Menus -----------------------------------------------
786 menuNew(argument, false);
789 case LFUN_MENUNEWTMPLT:
790 menuNew(argument, true);
793 case LFUN_CLOSEBUFFER:
798 if (!owner->buffer()->isUnnamed()) {
799 string const str = bformat(_("Saving document %1$s..."),
800 MakeDisplayPath(owner->buffer()->fileName()));
802 MenuWrite(owner->buffer());
803 owner->message(str + _(" done."));
805 WriteAs(owner->buffer());
809 WriteAs(owner->buffer(), argument);
812 case LFUN_MENURELOAD: {
813 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
814 string text = bformat(_("Any changes will be lost. Are you sure "
815 "you want to revert to the saved version of the document %1$s?"), file);
816 int const ret = Alert::prompt(_("Revert to saved document?"),
817 text, 0, 1, _("&Revert"), _("&Cancel"));
825 Exporter::Export(owner->buffer(), argument, true);
826 view()->showErrorList(BufferFormat(*owner->buffer()));
830 Exporter::Preview(owner->buffer(), argument);
831 view()->showErrorList(BufferFormat(*owner->buffer()));
835 Exporter::Export(owner->buffer(), "program", true);
836 view()->showErrorList(_("Build"));
840 owner->buffer()->runChktex();
841 view()->showErrorList(_("ChkTeX"));
845 if (argument == "custom")
846 owner->getDialogs().show("sendto");
848 Exporter::Export(owner->buffer(), argument, false);
849 view()->showErrorList(BufferFormat(*owner->buffer()));
853 case LFUN_EXPORT_CUSTOM: {
855 string command = split(argument, format_name, ' ');
856 Format const * format = formats.getFormat(format_name);
858 lyxerr << "Format \"" << format_name
859 << "\" not recognized!"
864 Buffer * buffer = owner->buffer();
866 // The name of the file created by the conversion process
869 // Output to filename
870 if (format->name() == "lyx") {
871 string const latexname =
872 buffer->getLatexName(false);
873 filename = ChangeExtension(latexname,
874 format->extension());
875 filename = AddName(buffer->temppath(), filename);
877 if (!buffer->writeFile(filename))
881 Exporter::Export(buffer, format_name, true,
885 // Substitute $$FName for filename
886 if (!contains(command, "$$FName"))
887 command = "( " + command + " ) < $$FName";
888 command = subst(command, "$$FName", filename);
890 // Execute the command in the background
892 call.startscript(Systemcall::DontWait, command);
899 string command = split(split(argument, target, ' '),
903 || target_name.empty()
904 || command.empty()) {
905 lyxerr << "Unable to parse \""
906 << argument << '"' << std::endl;
909 if (target != "printer" && target != "file") {
910 lyxerr << "Unrecognized target \""
911 << target << '"' << std::endl;
915 Buffer * buffer = owner->buffer();
917 if (!Exporter::Export(buffer, "dvi", true)) {
918 showPrintError(buffer->fileName());
922 // Push directory path.
923 string const path = buffer->temppath();
926 // there are three cases here:
927 // 1. we print to a file
928 // 2. we print directly to a printer
929 // 3. we print using a spool command (print to file first)
932 string const dviname =
933 ChangeExtension(buffer->getLatexName(true),
936 if (target == "printer") {
937 if (!lyxrc.print_spool_command.empty()) {
938 // case 3: print using a spool
939 string const psname =
940 ChangeExtension(dviname,".ps");
941 command += lyxrc.print_to_file
944 + QuoteName(dviname);
947 lyxrc.print_spool_command +' ';
948 if (target_name != "default") {
949 command2 += lyxrc.print_spool_printerprefix
953 command2 += QuoteName(psname);
955 // If successful, then spool command
956 res = one.startscript(
961 res = one.startscript(
962 Systemcall::DontWait,
965 // case 2: print directly to a printer
966 res = one.startscript(
967 Systemcall::DontWait,
968 command + QuoteName(dviname));
972 // case 1: print to a file
973 command += lyxrc.print_to_file
974 + QuoteName(MakeAbsPath(target_name,
977 + QuoteName(dviname);
978 res = one.startscript(Systemcall::DontWait,
983 showPrintError(buffer->fileName());
992 QuitLyX(argument == "force");
996 InsetCommandParams p("tableofcontents");
997 string const data = InsetCommandMailer::params2string("toc", p);
998 owner->getDialogs().show("toc", data, 0);
1006 case LFUN_RECONFIGURE:
1007 Reconfigure(view());
1010 case LFUN_HELP_OPEN: {
1011 string const arg = argument;
1013 setErrorMessage(N_("Missing argument"));
1016 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1017 if (fname.empty()) {
1018 lyxerr << "LyX: unable to find documentation file `"
1019 << arg << "'. Bad installation?" << endl;
1022 owner->message(bformat(_("Opening help file %1$s..."),
1023 MakeDisplayPath(fname)));
1024 view()->loadLyXFile(fname, false);
1028 // --- version control -------------------------------
1029 case LFUN_VC_REGISTER:
1030 if (!ensureBufferClean(view()))
1032 if (!owner->buffer()->lyxvc().inUse()) {
1033 owner->buffer()->lyxvc().registrer();
1038 case LFUN_VC_CHECKIN:
1039 if (!ensureBufferClean(view()))
1041 if (owner->buffer()->lyxvc().inUse()
1042 && !owner->buffer()->isReadonly()) {
1043 owner->buffer()->lyxvc().checkIn();
1048 case LFUN_VC_CHECKOUT:
1049 if (!ensureBufferClean(view()))
1051 if (owner->buffer()->lyxvc().inUse()
1052 && owner->buffer()->isReadonly()) {
1053 owner->buffer()->lyxvc().checkOut();
1058 case LFUN_VC_REVERT:
1059 owner->buffer()->lyxvc().revert();
1064 owner->buffer()->lyxvc().undoLast();
1068 // --- buffers ----------------------------------------
1069 case LFUN_SWITCHBUFFER:
1070 view()->setBuffer(bufferlist.getBuffer(argument));
1073 case LFUN_NEXTBUFFER:
1074 view()->setBuffer(bufferlist.next(view()->buffer()));
1077 case LFUN_PREVIOUSBUFFER:
1078 view()->setBuffer(bufferlist.previous(view()->buffer()));
1082 NewFile(view(), argument);
1085 case LFUN_FILE_OPEN:
1089 case LFUN_DROP_LAYOUTS_CHOICE:
1090 owner->getToolbars().openLayoutList();
1093 case LFUN_MENU_OPEN_BY_NAME:
1094 owner->getMenubar().openByName(argument);
1097 // --- lyxserver commands ----------------------------
1099 setMessage(owner->buffer()->fileName());
1100 lyxerr[Debug::INFO] << "FNAME["
1101 << owner->buffer()->fileName()
1106 dispatch_buffer = keyseq.print();
1107 lyxserver->notifyClient(dispatch_buffer);
1110 case LFUN_GOTOFILEROW: {
1113 istringstream is(argument);
1114 is >> file_name >> row;
1115 if (prefixIs(file_name, package().temp_dir())) {
1116 // Needed by inverse dvi search. If it is a file
1117 // in tmpdir, call the apropriated function
1118 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1120 // Must replace extension of the file to be .lyx
1121 // and get full path
1122 string const s = ChangeExtension(file_name, ".lyx");
1123 // Either change buffer or load the file
1124 if (bufferlist.exists(s)) {
1125 view()->setBuffer(bufferlist.getBuffer(s));
1127 view()->loadLyXFile(s);
1131 view()->setCursorFromRow(row);
1134 // see BufferView_pimpl::center()
1135 view()->updateScrollbar();
1139 case LFUN_DIALOG_SHOW: {
1140 string const name = cmd.getArg(0);
1141 string data = trim(cmd.argument.substr(name.size()));
1143 if (name == "character") {
1144 data = freefont2string();
1146 owner->getDialogs().show("character", data);
1149 else if (name == "latexlog") {
1150 pair<Buffer::LogType, string> const logfile =
1151 owner->buffer()->getLogName();
1152 switch (logfile.first) {
1153 case Buffer::latexlog:
1156 case Buffer::buildlog:
1160 data += logfile.second;
1161 owner->getDialogs().show("log", data);
1163 else if (name == "vclog") {
1164 string const data = "vc " +
1165 owner->buffer()->lyxvc().getLogFile();
1166 owner->getDialogs().show("log", data);
1169 owner->getDialogs().show(name, data);
1173 case LFUN_DIALOG_SHOW_NEW_INSET: {
1174 string const name = cmd.getArg(0);
1175 string data = trim(cmd.argument.substr(name.size()));
1176 if (name == "bibitem" ||
1183 InsetCommandParams p(name);
1184 data = InsetCommandMailer::params2string(name, p);
1185 } else if (name == "include") {
1186 InsetCommandParams p(data);
1187 data = InsetIncludeMailer::params2string(p);
1188 } else if (name == "box") {
1189 // \c data == "Boxed" || "Frameless" etc
1190 InsetBoxParams p(data);
1191 data = InsetBoxMailer::params2string(p);
1192 } else if (name == "branch") {
1193 InsetBranchParams p;
1194 data = InsetBranchMailer::params2string(p);
1195 } else if (name == "citation") {
1196 InsetCommandParams p("cite");
1197 data = InsetCommandMailer::params2string(name, p);
1198 } else if (name == "ert") {
1199 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1200 } else if (name == "external") {
1201 InsetExternalParams p;
1202 Buffer const & buffer = *owner->buffer();
1203 data = InsetExternalMailer::params2string(p, buffer);
1204 } else if (name == "float") {
1206 data = InsetFloatMailer::params2string(p);
1207 } else if (name == "graphics") {
1208 InsetGraphicsParams p;
1209 Buffer const & buffer = *owner->buffer();
1210 data = InsetGraphicsMailer::params2string(p, buffer);
1211 } else if (name == "note") {
1213 data = InsetNoteMailer::params2string(p);
1214 } else if (name == "vspace") {
1216 data = InsetVSpaceMailer::params2string(space);
1217 } else if (name == "wrap") {
1219 data = InsetWrapMailer::params2string(p);
1221 owner->getDialogs().show(name, data, 0);
1225 case LFUN_DIALOG_SHOW_NEXT_INSET:
1228 case LFUN_DIALOG_UPDATE: {
1229 string const & name = argument;
1230 // Can only update a dialog connected to an existing inset
1231 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1233 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1234 inset->dispatch(view()->cursor(), fr);
1235 } else if (name == "paragraph") {
1236 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1237 } else if (name == "prefs") {
1238 owner->getDialogs().update(name, string());
1243 case LFUN_DIALOG_HIDE:
1244 Dialogs::hide(argument, 0);
1247 case LFUN_DIALOG_DISCONNECT_INSET:
1248 owner->getDialogs().disconnect(argument);
1252 case LFUN_INSERT_CITATION: {
1253 if (!argument.empty()) {
1254 // we can have one optional argument, delimited by '|'
1255 // citation-insert <key>|<text_before>
1256 // this should be enhanced to also support text_after
1257 // and citation style
1258 string arg = argument;
1260 if (contains(argument, "|")) {
1261 arg = token(argument, '|', 0);
1262 opt1 = '[' + token(argument, '|', 1) + ']';
1264 std::ostringstream os;
1265 os << "citation LatexCommand\n"
1266 << "\\cite" << opt1 << "{" << arg << "}\n"
1268 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1271 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1275 case LFUN_CHILDOPEN: {
1276 string const filename =
1277 MakeAbsPath(argument, owner->buffer()->filePath());
1278 setMessage(N_("Opening child document ") +
1279 MakeDisplayPath(filename) + "...");
1280 view()->savePosition(0);
1281 string const parentfilename = owner->buffer()->fileName();
1282 if (bufferlist.exists(filename))
1283 view()->setBuffer(bufferlist.getBuffer(filename));
1285 view()->loadLyXFile(filename);
1286 // Set the parent name of the child document.
1287 // This makes insertion of citations and references in the child work,
1288 // when the target is in the parent or another child document.
1289 owner->buffer()->setParentName(parentfilename);
1293 case LFUN_TOGGLECURSORFOLLOW:
1294 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1298 owner->getIntl().KeyMapOn(false);
1301 case LFUN_KMAP_PRIM:
1302 owner->getIntl().KeyMapPrim();
1306 owner->getIntl().KeyMapSec();
1309 case LFUN_KMAP_TOGGLE:
1310 owner->getIntl().ToggleKeyMap();
1316 string rest = split(argument, countstr, ' ');
1317 istringstream is(countstr);
1320 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1321 for (int i = 0; i < count; ++i)
1322 dispatch(lyxaction.lookupFunc(rest));
1326 case LFUN_SEQUENCE: {
1327 // argument contains ';'-terminated commands
1328 string arg = argument;
1329 while (!arg.empty()) {
1331 arg = split(arg, first, ';');
1332 FuncRequest func(lyxaction.lookupFunc(first));
1333 func.origin = cmd.origin;
1339 case LFUN_SAVEPREFERENCES: {
1340 Path p(package().user_support());
1341 lyxrc.write("preferences", false);
1345 case LFUN_SCREEN_FONT_UPDATE:
1346 // handle the screen font changes.
1347 lyxrc.set_font_norm_type();
1348 lyx_gui::update_fonts();
1349 // All visible buffers will need resize
1353 case LFUN_SET_COLOR: {
1355 string const x11_name = split(argument, lyx_name, ' ');
1356 if (lyx_name.empty() || x11_name.empty()) {
1357 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1362 bool const graphicsbg_changed =
1363 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1364 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1366 if (!lcolor.setColor(lyx_name, x11_name)) {
1368 bformat(_("Set-color \"%1$s\" failed "
1369 "- color is undefined or "
1370 "may not be redefined"), lyx_name));
1374 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1376 if (graphicsbg_changed) {
1377 #ifdef WITH_WARNINGS
1378 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1381 lyx::graphics::GCache::get().changeDisplay(true);
1388 owner->message(argument);
1391 case LFUN_TOOLTIPS_TOGGLE:
1392 owner->getDialogs().toggleTooltips();
1395 case LFUN_EXTERNAL_EDIT: {
1396 FuncRequest fr(action, argument);
1397 InsetExternal().dispatch(view()->cursor(), fr);
1401 case LFUN_GRAPHICS_EDIT: {
1402 FuncRequest fr(action, argument);
1403 InsetGraphics().dispatch(view()->cursor(), fr);
1407 case LFUN_INSET_APPLY: {
1408 string const name = cmd.getArg(0);
1409 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1411 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1412 inset->dispatch(view()->cursor(), fr);
1414 FuncRequest fr(LFUN_INSET_INSERT, argument);
1417 // ideally, the update flag should be set by the insets,
1418 // but this is not possible currently
1423 case LFUN_ALL_INSETS_TOGGLE: {
1425 string const name = split(argument, action, ' ');
1426 InsetBase::Code const inset_code =
1427 InsetBase::translate(name);
1429 LCursor & cur = view()->cursor();
1430 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1432 InsetBase & inset = owner->buffer()->inset();
1433 InsetIterator it = inset_iterator_begin(inset);
1434 InsetIterator const end = inset_iterator_end(inset);
1435 for (; it != end; ++it) {
1436 if (inset_code == InsetBase::NO_CODE
1437 || inset_code == it->lyxCode()) {
1438 LCursor tmpcur = cur;
1439 tmpcur.pushLeft(*it);
1440 it->dispatch(tmpcur, fr);
1447 case LFUN_LANGUAGE_BUFFER: {
1448 Buffer & buffer = *owner->buffer();
1449 Language const * oldL = buffer.params().language;
1450 Language const * newL = languages.getLanguage(argument);
1451 if (!newL || oldL == newL)
1454 if (oldL->RightToLeft() == newL->RightToLeft()
1455 && !buffer.isMultiLingual())
1456 buffer.changeLanguage(oldL, newL);
1458 buffer.updateDocLang(newL);
1462 case LFUN_SAVE_AS_DEFAULT: {
1463 string const fname =
1464 AddName(AddPath(package().user_support(), "templates/"),
1466 Buffer defaults(fname);
1468 istringstream ss(argument);
1471 int const unknown_tokens = defaults.readHeader(lex);
1473 if (unknown_tokens != 0) {
1474 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1475 << unknown_tokens << " unknown token"
1476 << (unknown_tokens == 1 ? "" : "s")
1480 if (defaults.writeFile(defaults.fileName()))
1481 setMessage(_("Document defaults saved in ")
1482 + MakeDisplayPath(fname));
1484 setErrorMessage(_("Unable to save document defaults"));
1488 case LFUN_BUFFERPARAMS_APPLY: {
1489 biblio::CiteEngine const engine =
1490 owner->buffer()->params().cite_engine;
1492 istringstream ss(argument);
1495 int const unknown_tokens =
1496 owner->buffer()->readHeader(lex);
1498 if (unknown_tokens != 0) {
1499 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1500 << unknown_tokens << " unknown token"
1501 << (unknown_tokens == 1 ? "" : "s")
1504 if (engine == owner->buffer()->params().cite_engine)
1507 LCursor & cur = view()->cursor();
1508 FuncRequest fr(LFUN_INSET_REFRESH);
1510 InsetBase & inset = owner->buffer()->inset();
1511 InsetIterator it = inset_iterator_begin(inset);
1512 InsetIterator const end = inset_iterator_end(inset);
1513 for (; it != end; ++it)
1514 if (it->lyxCode() == InsetBase::CITE_CODE)
1515 it->dispatch(cur, fr);
1519 case LFUN_TEXTCLASS_APPLY: {
1520 Buffer * buffer = owner->buffer();
1522 lyx::textclass_type const old_class =
1523 buffer->params().textclass;
1525 loadTextclass(argument);
1527 std::pair<bool, lyx::textclass_type> const tc_pair =
1528 textclasslist.NumberOfClass(argument);
1533 lyx::textclass_type const new_class = tc_pair.second;
1534 if (old_class == new_class)
1538 owner->message(_("Converting document to new document class..."));
1539 recordUndoFullDocument(view());
1540 buffer->params().textclass = new_class;
1541 StableDocIterator backcur(view()->cursor());
1543 lyx::cap::SwitchBetweenClasses(
1544 old_class, new_class,
1545 buffer->paragraphs(), el);
1547 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1548 bufferErrors(*buffer, el);
1549 view()->showErrorList(_("Class switch"));
1550 updateCounters(*buffer);
1555 case LFUN_TEXTCLASS_LOAD:
1556 loadTextclass(argument);
1559 case LFUN_LYXRC_APPLY: {
1560 LyXRC const lyxrc_orig = lyxrc;
1562 istringstream ss(argument);
1563 bool const success = lyxrc.read(ss) == 0;
1566 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1567 << "Unable to read lyxrc data"
1572 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1577 view()->cursor().dispatch(cmd);
1578 update |= view()->cursor().result().update();
1579 if (!view()->cursor().result().dispatched())
1580 update |= view()->dispatch(cmd);
1585 if (view()->available()) {
1586 // Redraw screen unless explicitly told otherwise.
1587 // This also initializes the position cache for all insets
1588 // in (at least partially) visible top-level paragraphs.
1590 view()->update(Update::FitCursor | Update::Force);
1592 view()->update(Update::FitCursor);
1594 // if we executed a mutating lfun, mark the buffer as dirty
1595 // FIXME: Why not use flag.enabled() but call getStatus again?
1596 if (getStatus(cmd).enabled()
1597 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1598 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1599 view()->buffer()->markDirty();
1602 if (view()->cursor().inTexted()) {
1603 view()->owner()->updateLayoutChoice();
1606 sendDispatchMessage(_(getMessage()), cmd);
1610 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1612 /* When an action did not originate from the UI/kbd, it makes
1613 * sense to avoid updating the GUI. It turns out that this
1614 * fixes bug 1941, for reasons that are described here:
1615 * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1617 if (cmd.origin != FuncRequest::INTERNAL) {
1618 owner->updateMenubar();
1619 owner->updateToolbars();
1622 const bool verbose = (cmd.origin == FuncRequest::UI
1623 || cmd.origin == FuncRequest::COMMANDBUFFER);
1625 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1626 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1628 owner->message(msg);
1632 string dispatch_msg = msg;
1633 if (!dispatch_msg.empty())
1634 dispatch_msg += ' ';
1636 string comname = lyxaction.getActionName(cmd.action);
1638 bool argsadded = false;
1640 if (!cmd.argument.empty()) {
1641 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1642 comname += ' ' + cmd.argument;
1647 string const shortcuts = toplevel_keymap->printbindings(cmd);
1649 if (!shortcuts.empty())
1650 comname += ": " + shortcuts;
1651 else if (!argsadded && !cmd.argument.empty())
1652 comname += ' ' + cmd.argument;
1654 if (!comname.empty()) {
1655 comname = rtrim(comname);
1656 dispatch_msg += '(' + rtrim(comname) + ')';
1659 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1660 if (!dispatch_msg.empty())
1661 owner->message(dispatch_msg);
1665 void LyXFunc::setupLocalKeymap()
1667 keyseq.stdmap = toplevel_keymap.get();
1668 keyseq.curmap = toplevel_keymap.get();
1669 cancel_meta_seq.stdmap = toplevel_keymap.get();
1670 cancel_meta_seq.curmap = toplevel_keymap.get();
1674 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1676 string initpath = lyxrc.document_path;
1677 string filename(name);
1679 if (view()->available()) {
1680 string const trypath = owner->buffer()->filePath();
1681 // If directory is writeable, use this as default.
1682 if (IsDirWriteable(trypath))
1686 static int newfile_number;
1688 if (filename.empty()) {
1689 filename = AddName(lyxrc.document_path,
1690 "newfile" + convert<string>(++newfile_number) + ".lyx");
1691 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1693 filename = AddName(lyxrc.document_path,
1694 "newfile" + convert<string>(newfile_number) +
1699 // The template stuff
1702 FileDialog fileDlg(_("Select template file"),
1703 LFUN_SELECT_FILE_SYNC,
1704 make_pair(string(_("Documents|#o#O")),
1705 string(lyxrc.document_path)),
1706 make_pair(string(_("Templates|#T#t")),
1707 string(lyxrc.template_path)));
1709 FileDialog::Result result =
1710 fileDlg.open(lyxrc.template_path,
1711 FileFilterList(_("LyX Documents (*.lyx)")),
1714 if (result.first == FileDialog::Later)
1716 if (result.second.empty())
1718 templname = result.second;
1721 view()->newFile(filename, templname, !name.empty());
1725 void LyXFunc::open(string const & fname)
1727 string initpath = lyxrc.document_path;
1729 if (view()->available()) {
1730 string const trypath = owner->buffer()->filePath();
1731 // If directory is writeable, use this as default.
1732 if (IsDirWriteable(trypath))
1738 if (fname.empty()) {
1739 FileDialog fileDlg(_("Select document to open"),
1741 make_pair(string(_("Documents|#o#O")),
1742 string(lyxrc.document_path)),
1743 make_pair(string(_("Examples|#E#e")),
1744 string(AddPath(package().system_support(), "examples"))));
1746 FileDialog::Result result =
1747 fileDlg.open(initpath,
1748 FileFilterList(_("LyX Documents (*.lyx)")),
1751 if (result.first == FileDialog::Later)
1754 filename = result.second;
1756 // check selected filename
1757 if (filename.empty()) {
1758 owner->message(_("Canceled."));
1764 // get absolute path of file and add ".lyx" to the filename if
1766 string const fullpath = FileSearch(string(), filename, "lyx");
1767 if (!fullpath.empty()) {
1768 filename = fullpath;
1771 string const disp_fn(MakeDisplayPath(filename));
1773 // if the file doesn't exist, let the user create one
1774 if (!fs::exists(filename)) {
1775 // the user specifically chose this name. Believe them.
1776 view()->newFile(filename, "", true);
1780 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1783 if (view()->loadLyXFile(filename)) {
1784 str2 = bformat(_("Document %1$s opened."), disp_fn);
1786 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1788 owner->message(str2);
1792 void LyXFunc::doImport(string const & argument)
1795 string filename = split(argument, format, ' ');
1797 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1798 << " file: " << filename << endl;
1800 // need user interaction
1801 if (filename.empty()) {
1802 string initpath = lyxrc.document_path;
1804 if (view()->available()) {
1805 string const trypath = owner->buffer()->filePath();
1806 // If directory is writeable, use this as default.
1807 if (IsDirWriteable(trypath))
1811 string const text = bformat(_("Select %1$s file to import"),
1812 formats.prettyName(format));
1814 FileDialog fileDlg(text,
1816 make_pair(string(_("Documents|#o#O")),
1817 string(lyxrc.document_path)),
1818 make_pair(string(_("Examples|#E#e")),
1819 string(AddPath(package().system_support(), "examples"))));
1821 string const filter = formats.prettyName(format)
1822 + " (*." + formats.extension(format) + ')';
1824 FileDialog::Result result =
1825 fileDlg.open(initpath,
1826 FileFilterList(filter),
1829 if (result.first == FileDialog::Later)
1832 filename = result.second;
1834 // check selected filename
1835 if (filename.empty())
1836 owner->message(_("Canceled."));
1839 if (filename.empty())
1842 // get absolute path of file
1843 filename = MakeAbsPath(filename);
1845 string const lyxfile = ChangeExtension(filename, ".lyx");
1847 // Check if the document already is open
1848 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1849 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1850 owner->message(_("Canceled."));
1855 // if the file exists already, and we didn't do
1856 // -i lyx thefile.lyx, warn
1857 if (fs::exists(lyxfile) && filename != lyxfile) {
1858 string const file = MakeDisplayPath(lyxfile, 30);
1860 string text = bformat(_("The document %1$s already exists.\n\n"
1861 "Do you want to over-write that document?"), file);
1862 int const ret = Alert::prompt(_("Over-write document?"),
1863 text, 0, 1, _("&Over-write"), _("&Cancel"));
1866 owner->message(_("Canceled."));
1871 Importer::Import(owner, filename, format);
1875 void LyXFunc::closeBuffer()
1877 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1878 if (bufferlist.empty()) {
1879 // need this otherwise SEGV may occur while
1880 // trying to set variables that don't exist
1881 // since there's no current buffer
1882 owner->getDialogs().hideBufferDependent();
1884 view()->setBuffer(bufferlist.first());
1890 // Each "owner" should have it's own message method. lyxview and
1891 // the minibuffer would use the minibuffer, but lyxserver would
1892 // send an ERROR signal to its client. Alejandro 970603
1893 // This function is bit problematic when it comes to NLS, to make the
1894 // lyx servers client be language indepenent we must not translate
1895 // strings sent to this func.
1896 void LyXFunc::setErrorMessage(string const & m) const
1898 dispatch_buffer = m;
1903 void LyXFunc::setMessage(string const & m) const
1905 dispatch_buffer = m;
1909 string const LyXFunc::viewStatusMessage()
1911 // When meta-fake key is pressed, show the key sequence so far + "M-".
1913 return keyseq.print() + "M-";
1915 // Else, when a non-complete key sequence is pressed,
1916 // show the available options.
1917 if (keyseq.length() > 0 && !keyseq.deleted())
1918 return keyseq.printOptions();
1920 if (!view()->available())
1921 return _("Welcome to LyX!");
1923 return view()->cursor().currentState();
1927 BufferView * LyXFunc::view() const
1929 BOOST_ASSERT(owner);
1930 return owner->view().get();
1934 bool LyXFunc::wasMetaKey() const
1936 return (meta_fake_bit != key_modifier::none);
1942 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1944 // Why the switch you might ask. It is a trick to ensure that all
1945 // the elements in the LyXRCTags enum is handled. As you can see
1946 // there are no breaks at all. So it is just a huge fall-through.
1947 // The nice thing is that we will get a warning from the compiler
1948 // if we forget an element.
1949 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1951 case LyXRC::RC_ACCEPT_COMPOUND:
1952 case LyXRC::RC_ALT_LANG:
1953 case LyXRC::RC_ASCIIROFF_COMMAND:
1954 case LyXRC::RC_ASCII_LINELEN:
1955 case LyXRC::RC_AUTOREGIONDELETE:
1956 case LyXRC::RC_AUTORESET_OPTIONS:
1957 case LyXRC::RC_AUTOSAVE:
1958 case LyXRC::RC_AUTO_NUMBER:
1959 case LyXRC::RC_BACKUPDIR_PATH:
1960 case LyXRC::RC_BIBTEX_COMMAND:
1961 case LyXRC::RC_BINDFILE:
1962 case LyXRC::RC_CHECKLASTFILES:
1963 case LyXRC::RC_CHKTEX_COMMAND:
1964 case LyXRC::RC_CONVERTER:
1965 case LyXRC::RC_COPIER:
1966 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1967 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1968 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1969 case LyXRC::RC_CYGWIN_PATH_FIX:
1970 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1971 namespace os = lyx::support::os;
1972 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1974 case LyXRC::RC_DATE_INSERT_FORMAT:
1975 case LyXRC::RC_DEFAULT_LANGUAGE:
1976 case LyXRC::RC_DEFAULT_PAPERSIZE:
1977 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1978 case LyXRC::RC_DISPLAY_GRAPHICS:
1979 case LyXRC::RC_DOCUMENTPATH:
1980 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1981 if (fs::exists(lyxrc_new.document_path) &&
1982 fs::is_directory(lyxrc_new.document_path)) {
1983 using lyx::support::package;
1984 package().document_dir() = lyxrc.document_path;
1987 case LyXRC::RC_ESC_CHARS:
1988 case LyXRC::RC_FONT_ENCODING:
1989 case LyXRC::RC_FORMAT:
1990 case LyXRC::RC_INDEX_COMMAND:
1991 case LyXRC::RC_INPUT:
1992 case LyXRC::RC_KBMAP:
1993 case LyXRC::RC_KBMAP_PRIMARY:
1994 case LyXRC::RC_KBMAP_SECONDARY:
1995 case LyXRC::RC_LABEL_INIT_LENGTH:
1996 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1997 case LyXRC::RC_LANGUAGE_AUTO_END:
1998 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1999 case LyXRC::RC_LANGUAGE_COMMAND_END:
2000 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2001 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2002 case LyXRC::RC_LANGUAGE_PACKAGE:
2003 case LyXRC::RC_LANGUAGE_USE_BABEL:
2004 case LyXRC::RC_LASTFILES:
2005 case LyXRC::RC_MAKE_BACKUP:
2006 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2007 case LyXRC::RC_NUMLASTFILES:
2008 case LyXRC::RC_PATH_PREFIX:
2009 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2010 using lyx::support::prependEnvPath;
2011 prependEnvPath("PATH", lyxrc.path_prefix);
2013 case LyXRC::RC_PERS_DICT:
2014 case LyXRC::RC_POPUP_BOLD_FONT:
2015 case LyXRC::RC_POPUP_FONT_ENCODING:
2016 case LyXRC::RC_POPUP_NORMAL_FONT:
2017 case LyXRC::RC_PREVIEW:
2018 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2019 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2020 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2021 case LyXRC::RC_PRINTCOPIESFLAG:
2022 case LyXRC::RC_PRINTER:
2023 case LyXRC::RC_PRINTEVENPAGEFLAG:
2024 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2025 case LyXRC::RC_PRINTFILEEXTENSION:
2026 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2027 case LyXRC::RC_PRINTODDPAGEFLAG:
2028 case LyXRC::RC_PRINTPAGERANGEFLAG:
2029 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2030 case LyXRC::RC_PRINTPAPERFLAG:
2031 case LyXRC::RC_PRINTREVERSEFLAG:
2032 case LyXRC::RC_PRINTSPOOL_COMMAND:
2033 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2034 case LyXRC::RC_PRINTTOFILE:
2035 case LyXRC::RC_PRINTTOPRINTER:
2036 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2037 case LyXRC::RC_PRINT_COMMAND:
2038 case LyXRC::RC_RTL_SUPPORT:
2039 case LyXRC::RC_SCREEN_DPI:
2040 case LyXRC::RC_SCREEN_FONT_ENCODING:
2041 case LyXRC::RC_SCREEN_FONT_ROMAN:
2042 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2043 case LyXRC::RC_SCREEN_FONT_SANS:
2044 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2045 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2046 case LyXRC::RC_SCREEN_FONT_SIZES:
2047 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2048 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2049 case LyXRC::RC_SCREEN_ZOOM:
2050 case LyXRC::RC_SERVERPIPE:
2051 case LyXRC::RC_SET_COLOR:
2052 case LyXRC::RC_SHOW_BANNER:
2053 case LyXRC::RC_SPELL_COMMAND:
2054 case LyXRC::RC_TEMPDIRPATH:
2055 case LyXRC::RC_TEMPLATEPATH:
2056 case LyXRC::RC_TEX_ALLOWS_SPACES:
2057 case LyXRC::RC_UIFILE:
2058 case LyXRC::RC_USER_EMAIL:
2059 case LyXRC::RC_USER_NAME:
2060 case LyXRC::RC_USETEMPDIR:
2061 case LyXRC::RC_USE_ALT_LANG:
2062 case LyXRC::RC_USE_ESC_CHARS:
2063 case LyXRC::RC_USE_INP_ENC:
2064 case LyXRC::RC_USE_PERS_DICT:
2065 case LyXRC::RC_USE_SPELL_LIB:
2066 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2067 case LyXRC::RC_VIEWER:
2068 case LyXRC::RC_WHEEL_JUMP:
2069 case LyXRC::RC_LAST: