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 // this one is difficult to get right. As a half-baked
544 // solution, we consider only the first action of the sequence
545 case LFUN_SEQUENCE: {
546 // argument contains ';'-terminated commands
547 string const firstcmd = token(cmd.argument, ';', 0);
548 FuncRequest func(lyxaction.lookupFunc(firstcmd));
549 func.origin = cmd.origin;
550 flag = getStatus(func);
554 case LFUN_MENUNEWTMPLT:
555 case LFUN_WORDFINDFORWARD:
556 case LFUN_WORDFINDBACKWARD:
558 case LFUN_EXEC_COMMAND:
561 case LFUN_CLOSEBUFFER:
570 case LFUN_RECONFIGURE:
574 case LFUN_DROP_LAYOUTS_CHOICE:
575 case LFUN_MENU_OPEN_BY_NAME:
578 case LFUN_GOTOFILEROW:
579 case LFUN_DIALOG_SHOW_NEXT_INSET:
580 case LFUN_DIALOG_HIDE:
581 case LFUN_DIALOG_DISCONNECT_INSET:
583 case LFUN_TOGGLECURSORFOLLOW:
587 case LFUN_KMAP_TOGGLE:
589 case LFUN_EXPORT_CUSTOM:
591 case LFUN_SAVEPREFERENCES:
592 case LFUN_SCREEN_FONT_UPDATE:
595 case LFUN_EXTERNAL_EDIT:
596 case LFUN_GRAPHICS_EDIT:
597 case LFUN_ALL_INSETS_TOGGLE:
598 case LFUN_LANGUAGE_BUFFER:
599 case LFUN_TEXTCLASS_APPLY:
600 case LFUN_TEXTCLASS_LOAD:
601 case LFUN_SAVE_AS_DEFAULT:
602 case LFUN_BUFFERPARAMS_APPLY:
603 case LFUN_LYXRC_APPLY:
604 case LFUN_NEXTBUFFER:
605 case LFUN_PREVIOUSBUFFER:
606 // these are handled in our dispatch()
611 if (!::getStatus(cur, cmd, flag))
612 flag = view()->getStatus(cmd);
618 // Can we use a readonly buffer?
619 if (buf && buf->isReadonly()
620 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
621 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
622 flag.message(N_("Document is read-only"));
626 // Are we in a DELETED change-tracking region?
627 if (buf && buf->params().tracking_changes
628 && lookupChange(cur, true) == Change::DELETED
629 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
630 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
631 flag.message(N_("This portion of the document is deleted."));
635 // the default error message if we disable the command
636 if (!flag.enabled() && flag.message().empty())
637 flag.message(N_("Command disabled"));
645 bool ensureBufferClean(BufferView * bv)
647 Buffer & buf = *bv->buffer();
651 string const file = MakeDisplayPath(buf.fileName(), 30);
652 string text = bformat(_("The document %1$s has unsaved "
653 "changes.\n\nDo you want to save "
654 "the document?"), file);
655 int const ret = Alert::prompt(_("Save changed document?"),
656 text, 0, 1, _("&Save"),
660 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
662 return buf.isClean();
666 void showPrintError(string const & name)
668 string str = bformat(_("Could not print the document %1$s.\n"
669 "Check that your printer is set up correctly."),
670 MakeDisplayPath(name, 50));
671 Alert::error(_("Print document failed"), str);
675 void loadTextclass(string const & name)
677 std::pair<bool, lyx::textclass_type> const tc_pair =
678 textclasslist.NumberOfClass(name);
680 if (!tc_pair.first) {
681 lyxerr << "Document class \"" << name
682 << "\" does not exist."
687 lyx::textclass_type const tc = tc_pair.second;
689 if (!textclasslist[tc].load()) {
690 string s = bformat(_("The document could not be converted\n"
691 "into the document class %1$s."),
692 textclasslist[tc].name());
693 Alert::error(_("Could not change class"), s);
698 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
703 void LyXFunc::dispatch(FuncRequest const & cmd)
705 BOOST_ASSERT(view());
706 string const argument = cmd.argument;
707 kb_action const action = cmd.action;
709 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
710 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
712 // we have not done anything wrong yet.
714 dispatch_buffer.erase();
718 FuncStatus const flag = getStatus(cmd);
719 if (!flag.enabled()) {
720 // We cannot use this function here
721 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
722 << lyxaction.getActionName(action)
723 << " [" << action << "] is disabled at this location"
725 setErrorMessage(flag.message());
728 if (view()->available())
729 view()->hideCursor();
733 case LFUN_WORDFINDFORWARD:
734 case LFUN_WORDFINDBACKWARD: {
735 static string last_search;
736 string searched_string;
738 if (!argument.empty()) {
739 last_search = argument;
740 searched_string = argument;
742 searched_string = last_search;
745 if (searched_string.empty())
748 bool const fw = action == LFUN_WORDFINDFORWARD;
750 lyx::find::find2string(searched_string, true, false, fw);
751 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
756 owner->message(keyseq.printOptions());
759 case LFUN_EXEC_COMMAND:
760 owner->getToolbars().display("minibuffer", true);
761 owner->focus_command_buffer();
766 meta_fake_bit = key_modifier::none;
767 if (view()->available())
768 // cancel any selection
769 dispatch(FuncRequest(LFUN_MARK_OFF));
770 setMessage(N_("Cancel"));
774 meta_fake_bit = key_modifier::alt;
775 setMessage(keyseq.print());
778 case LFUN_READ_ONLY_TOGGLE:
779 if (owner->buffer()->lyxvc().inUse())
780 owner->buffer()->lyxvc().toggleReadOnly();
782 owner->buffer()->setReadonly(
783 !owner->buffer()->isReadonly());
786 // --- Menus -----------------------------------------------
788 menuNew(argument, false);
791 case LFUN_MENUNEWTMPLT:
792 menuNew(argument, true);
795 case LFUN_CLOSEBUFFER:
800 if (!owner->buffer()->isUnnamed()) {
801 string const str = bformat(_("Saving document %1$s..."),
802 MakeDisplayPath(owner->buffer()->fileName()));
804 MenuWrite(owner->buffer());
805 owner->message(str + _(" done."));
807 WriteAs(owner->buffer());
811 WriteAs(owner->buffer(), argument);
814 case LFUN_MENURELOAD: {
815 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
816 string text = bformat(_("Any changes will be lost. Are you sure "
817 "you want to revert to the saved version of the document %1$s?"), file);
818 int const ret = Alert::prompt(_("Revert to saved document?"),
819 text, 0, 1, _("&Revert"), _("&Cancel"));
827 Exporter::Export(owner->buffer(), argument, true);
828 view()->showErrorList(BufferFormat(*owner->buffer()));
832 Exporter::Preview(owner->buffer(), argument);
833 view()->showErrorList(BufferFormat(*owner->buffer()));
837 Exporter::Export(owner->buffer(), "program", true);
838 view()->showErrorList(_("Build"));
842 owner->buffer()->runChktex();
843 view()->showErrorList(_("ChkTeX"));
847 if (argument == "custom")
848 owner->getDialogs().show("sendto");
850 Exporter::Export(owner->buffer(), argument, false);
851 view()->showErrorList(BufferFormat(*owner->buffer()));
855 case LFUN_EXPORT_CUSTOM: {
857 string command = split(argument, format_name, ' ');
858 Format const * format = formats.getFormat(format_name);
860 lyxerr << "Format \"" << format_name
861 << "\" not recognized!"
866 Buffer * buffer = owner->buffer();
868 // The name of the file created by the conversion process
871 // Output to filename
872 if (format->name() == "lyx") {
873 string const latexname =
874 buffer->getLatexName(false);
875 filename = ChangeExtension(latexname,
876 format->extension());
877 filename = AddName(buffer->temppath(), filename);
879 if (!buffer->writeFile(filename))
883 Exporter::Export(buffer, format_name, true,
887 // Substitute $$FName for filename
888 if (!contains(command, "$$FName"))
889 command = "( " + command + " ) < $$FName";
890 command = subst(command, "$$FName", filename);
892 // Execute the command in the background
894 call.startscript(Systemcall::DontWait, command);
901 string command = split(split(argument, target, ' '),
905 || target_name.empty()
906 || command.empty()) {
907 lyxerr << "Unable to parse \""
908 << argument << '"' << std::endl;
911 if (target != "printer" && target != "file") {
912 lyxerr << "Unrecognized target \""
913 << target << '"' << std::endl;
917 Buffer * buffer = owner->buffer();
919 if (!Exporter::Export(buffer, "dvi", true)) {
920 showPrintError(buffer->fileName());
924 // Push directory path.
925 string const path = buffer->temppath();
928 // there are three cases here:
929 // 1. we print to a file
930 // 2. we print directly to a printer
931 // 3. we print using a spool command (print to file first)
934 string const dviname =
935 ChangeExtension(buffer->getLatexName(true),
938 if (target == "printer") {
939 if (!lyxrc.print_spool_command.empty()) {
940 // case 3: print using a spool
941 string const psname =
942 ChangeExtension(dviname,".ps");
943 command += lyxrc.print_to_file
946 + QuoteName(dviname);
949 lyxrc.print_spool_command +' ';
950 if (target_name != "default") {
951 command2 += lyxrc.print_spool_printerprefix
955 command2 += QuoteName(psname);
957 // If successful, then spool command
958 res = one.startscript(
963 res = one.startscript(
964 Systemcall::DontWait,
967 // case 2: print directly to a printer
968 res = one.startscript(
969 Systemcall::DontWait,
970 command + QuoteName(dviname));
974 // case 1: print to a file
975 command += lyxrc.print_to_file
976 + QuoteName(MakeAbsPath(target_name,
979 + QuoteName(dviname);
980 res = one.startscript(Systemcall::DontWait,
985 showPrintError(buffer->fileName());
994 QuitLyX(argument == "force");
998 InsetCommandParams p("tableofcontents");
999 string const data = InsetCommandMailer::params2string("toc", p);
1000 owner->getDialogs().show("toc", data, 0);
1008 case LFUN_RECONFIGURE:
1009 Reconfigure(view());
1012 case LFUN_HELP_OPEN: {
1013 string const arg = argument;
1015 setErrorMessage(N_("Missing argument"));
1018 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1019 if (fname.empty()) {
1020 lyxerr << "LyX: unable to find documentation file `"
1021 << arg << "'. Bad installation?" << endl;
1024 owner->message(bformat(_("Opening help file %1$s..."),
1025 MakeDisplayPath(fname)));
1026 view()->loadLyXFile(fname, false);
1030 // --- version control -------------------------------
1031 case LFUN_VC_REGISTER:
1032 if (!ensureBufferClean(view()))
1034 if (!owner->buffer()->lyxvc().inUse()) {
1035 owner->buffer()->lyxvc().registrer();
1040 case LFUN_VC_CHECKIN:
1041 if (!ensureBufferClean(view()))
1043 if (owner->buffer()->lyxvc().inUse()
1044 && !owner->buffer()->isReadonly()) {
1045 owner->buffer()->lyxvc().checkIn();
1050 case LFUN_VC_CHECKOUT:
1051 if (!ensureBufferClean(view()))
1053 if (owner->buffer()->lyxvc().inUse()
1054 && owner->buffer()->isReadonly()) {
1055 owner->buffer()->lyxvc().checkOut();
1060 case LFUN_VC_REVERT:
1061 owner->buffer()->lyxvc().revert();
1066 owner->buffer()->lyxvc().undoLast();
1070 // --- buffers ----------------------------------------
1071 case LFUN_SWITCHBUFFER:
1072 view()->setBuffer(bufferlist.getBuffer(argument));
1075 case LFUN_NEXTBUFFER:
1076 view()->setBuffer(bufferlist.next(view()->buffer()));
1079 case LFUN_PREVIOUSBUFFER:
1080 view()->setBuffer(bufferlist.previous(view()->buffer()));
1084 NewFile(view(), argument);
1087 case LFUN_FILE_OPEN:
1091 case LFUN_DROP_LAYOUTS_CHOICE:
1092 owner->getToolbars().openLayoutList();
1095 case LFUN_MENU_OPEN_BY_NAME:
1096 owner->getMenubar().openByName(argument);
1099 // --- lyxserver commands ----------------------------
1101 setMessage(owner->buffer()->fileName());
1102 lyxerr[Debug::INFO] << "FNAME["
1103 << owner->buffer()->fileName()
1108 dispatch_buffer = keyseq.print();
1109 lyxserver->notifyClient(dispatch_buffer);
1112 case LFUN_GOTOFILEROW: {
1115 istringstream is(argument);
1116 is >> file_name >> row;
1117 if (prefixIs(file_name, package().temp_dir())) {
1118 // Needed by inverse dvi search. If it is a file
1119 // in tmpdir, call the apropriated function
1120 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1122 // Must replace extension of the file to be .lyx
1123 // and get full path
1124 string const s = ChangeExtension(file_name, ".lyx");
1125 // Either change buffer or load the file
1126 if (bufferlist.exists(s)) {
1127 view()->setBuffer(bufferlist.getBuffer(s));
1129 view()->loadLyXFile(s);
1133 view()->setCursorFromRow(row);
1136 // see BufferView_pimpl::center()
1137 view()->updateScrollbar();
1141 case LFUN_DIALOG_SHOW: {
1142 string const name = cmd.getArg(0);
1143 string data = trim(cmd.argument.substr(name.size()));
1145 if (name == "character") {
1146 data = freefont2string();
1148 owner->getDialogs().show("character", data);
1151 else if (name == "latexlog") {
1152 pair<Buffer::LogType, string> const logfile =
1153 owner->buffer()->getLogName();
1154 switch (logfile.first) {
1155 case Buffer::latexlog:
1158 case Buffer::buildlog:
1162 data += logfile.second;
1163 owner->getDialogs().show("log", data);
1165 else if (name == "vclog") {
1166 string const data = "vc " +
1167 owner->buffer()->lyxvc().getLogFile();
1168 owner->getDialogs().show("log", data);
1171 owner->getDialogs().show(name, data);
1175 case LFUN_DIALOG_SHOW_NEW_INSET: {
1176 string const name = cmd.getArg(0);
1177 string data = trim(cmd.argument.substr(name.size()));
1178 if (name == "bibitem" ||
1185 InsetCommandParams p(name);
1186 data = InsetCommandMailer::params2string(name, p);
1187 } else if (name == "include") {
1188 InsetCommandParams p(data);
1189 data = InsetIncludeMailer::params2string(p);
1190 } else if (name == "box") {
1191 // \c data == "Boxed" || "Frameless" etc
1192 InsetBoxParams p(data);
1193 data = InsetBoxMailer::params2string(p);
1194 } else if (name == "branch") {
1195 InsetBranchParams p;
1196 data = InsetBranchMailer::params2string(p);
1197 } else if (name == "citation") {
1198 InsetCommandParams p("cite");
1199 data = InsetCommandMailer::params2string(name, p);
1200 } else if (name == "ert") {
1201 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1202 } else if (name == "external") {
1203 InsetExternalParams p;
1204 Buffer const & buffer = *owner->buffer();
1205 data = InsetExternalMailer::params2string(p, buffer);
1206 } else if (name == "float") {
1208 data = InsetFloatMailer::params2string(p);
1209 } else if (name == "graphics") {
1210 InsetGraphicsParams p;
1211 Buffer const & buffer = *owner->buffer();
1212 data = InsetGraphicsMailer::params2string(p, buffer);
1213 } else if (name == "note") {
1215 data = InsetNoteMailer::params2string(p);
1216 } else if (name == "vspace") {
1218 data = InsetVSpaceMailer::params2string(space);
1219 } else if (name == "wrap") {
1221 data = InsetWrapMailer::params2string(p);
1223 owner->getDialogs().show(name, data, 0);
1227 case LFUN_DIALOG_SHOW_NEXT_INSET:
1230 case LFUN_DIALOG_UPDATE: {
1231 string const & name = argument;
1232 // Can only update a dialog connected to an existing inset
1233 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1235 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1236 inset->dispatch(view()->cursor(), fr);
1237 } else if (name == "paragraph") {
1238 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1239 } else if (name == "prefs") {
1240 owner->getDialogs().update(name, string());
1245 case LFUN_DIALOG_HIDE:
1246 Dialogs::hide(argument, 0);
1249 case LFUN_DIALOG_DISCONNECT_INSET:
1250 owner->getDialogs().disconnect(argument);
1254 case LFUN_INSERT_CITATION: {
1255 if (!argument.empty()) {
1256 // we can have one optional argument, delimited by '|'
1257 // citation-insert <key>|<text_before>
1258 // this should be enhanced to also support text_after
1259 // and citation style
1260 string arg = argument;
1262 if (contains(argument, "|")) {
1263 arg = token(argument, '|', 0);
1264 opt1 = '[' + token(argument, '|', 1) + ']';
1266 std::ostringstream os;
1267 os << "citation LatexCommand\n"
1268 << "\\cite" << opt1 << "{" << arg << "}\n"
1270 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1273 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1277 case LFUN_CHILDOPEN: {
1278 string const filename =
1279 MakeAbsPath(argument, owner->buffer()->filePath());
1280 setMessage(N_("Opening child document ") +
1281 MakeDisplayPath(filename) + "...");
1282 view()->savePosition(0);
1283 string const parentfilename = owner->buffer()->fileName();
1284 if (bufferlist.exists(filename))
1285 view()->setBuffer(bufferlist.getBuffer(filename));
1287 view()->loadLyXFile(filename);
1288 // Set the parent name of the child document.
1289 // This makes insertion of citations and references in the child work,
1290 // when the target is in the parent or another child document.
1291 owner->buffer()->setParentName(parentfilename);
1295 case LFUN_TOGGLECURSORFOLLOW:
1296 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1300 owner->getIntl().KeyMapOn(false);
1303 case LFUN_KMAP_PRIM:
1304 owner->getIntl().KeyMapPrim();
1308 owner->getIntl().KeyMapSec();
1311 case LFUN_KMAP_TOGGLE:
1312 owner->getIntl().ToggleKeyMap();
1318 string rest = split(argument, countstr, ' ');
1319 istringstream is(countstr);
1322 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1323 for (int i = 0; i < count; ++i)
1324 dispatch(lyxaction.lookupFunc(rest));
1328 case LFUN_SEQUENCE: {
1329 // argument contains ';'-terminated commands
1330 string arg = argument;
1331 while (!arg.empty()) {
1333 arg = split(arg, first, ';');
1334 FuncRequest func(lyxaction.lookupFunc(first));
1335 func.origin = cmd.origin;
1341 case LFUN_SAVEPREFERENCES: {
1342 Path p(package().user_support());
1343 lyxrc.write("preferences", false);
1347 case LFUN_SCREEN_FONT_UPDATE:
1348 // handle the screen font changes.
1349 lyxrc.set_font_norm_type();
1350 lyx_gui::update_fonts();
1351 // All visible buffers will need resize
1355 case LFUN_SET_COLOR: {
1357 string const x11_name = split(argument, lyx_name, ' ');
1358 if (lyx_name.empty() || x11_name.empty()) {
1359 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1364 bool const graphicsbg_changed =
1365 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1366 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1368 if (!lcolor.setColor(lyx_name, x11_name)) {
1370 bformat(_("Set-color \"%1$s\" failed "
1371 "- color is undefined or "
1372 "may not be redefined"), lyx_name));
1376 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1378 if (graphicsbg_changed) {
1379 #ifdef WITH_WARNINGS
1380 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1383 lyx::graphics::GCache::get().changeDisplay(true);
1390 owner->message(argument);
1393 case LFUN_TOOLTIPS_TOGGLE:
1394 owner->getDialogs().toggleTooltips();
1397 case LFUN_EXTERNAL_EDIT: {
1398 FuncRequest fr(action, argument);
1399 InsetExternal().dispatch(view()->cursor(), fr);
1403 case LFUN_GRAPHICS_EDIT: {
1404 FuncRequest fr(action, argument);
1405 InsetGraphics().dispatch(view()->cursor(), fr);
1409 case LFUN_INSET_APPLY: {
1410 string const name = cmd.getArg(0);
1411 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1413 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1414 inset->dispatch(view()->cursor(), fr);
1416 FuncRequest fr(LFUN_INSET_INSERT, argument);
1419 // ideally, the update flag should be set by the insets,
1420 // but this is not possible currently
1425 case LFUN_ALL_INSETS_TOGGLE: {
1427 string const name = split(argument, action, ' ');
1428 InsetBase::Code const inset_code =
1429 InsetBase::translate(name);
1431 LCursor & cur = view()->cursor();
1432 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1434 InsetBase & inset = owner->buffer()->inset();
1435 InsetIterator it = inset_iterator_begin(inset);
1436 InsetIterator const end = inset_iterator_end(inset);
1437 for (; it != end; ++it) {
1438 if (inset_code == InsetBase::NO_CODE
1439 || inset_code == it->lyxCode()) {
1440 LCursor tmpcur = cur;
1441 tmpcur.pushLeft(*it);
1442 it->dispatch(tmpcur, fr);
1449 case LFUN_LANGUAGE_BUFFER: {
1450 Buffer & buffer = *owner->buffer();
1451 Language const * oldL = buffer.params().language;
1452 Language const * newL = languages.getLanguage(argument);
1453 if (!newL || oldL == newL)
1456 if (oldL->RightToLeft() == newL->RightToLeft()
1457 && !buffer.isMultiLingual())
1458 buffer.changeLanguage(oldL, newL);
1460 buffer.updateDocLang(newL);
1464 case LFUN_SAVE_AS_DEFAULT: {
1465 string const fname =
1466 AddName(AddPath(package().user_support(), "templates/"),
1468 Buffer defaults(fname);
1470 istringstream ss(argument);
1473 int const unknown_tokens = defaults.readHeader(lex);
1475 if (unknown_tokens != 0) {
1476 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1477 << unknown_tokens << " unknown token"
1478 << (unknown_tokens == 1 ? "" : "s")
1482 if (defaults.writeFile(defaults.fileName()))
1483 setMessage(_("Document defaults saved in ")
1484 + MakeDisplayPath(fname));
1486 setErrorMessage(_("Unable to save document defaults"));
1490 case LFUN_BUFFERPARAMS_APPLY: {
1491 biblio::CiteEngine const engine =
1492 owner->buffer()->params().cite_engine;
1494 istringstream ss(argument);
1497 int const unknown_tokens =
1498 owner->buffer()->readHeader(lex);
1500 if (unknown_tokens != 0) {
1501 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1502 << unknown_tokens << " unknown token"
1503 << (unknown_tokens == 1 ? "" : "s")
1506 if (engine == owner->buffer()->params().cite_engine)
1509 LCursor & cur = view()->cursor();
1510 FuncRequest fr(LFUN_INSET_REFRESH);
1512 InsetBase & inset = owner->buffer()->inset();
1513 InsetIterator it = inset_iterator_begin(inset);
1514 InsetIterator const end = inset_iterator_end(inset);
1515 for (; it != end; ++it)
1516 if (it->lyxCode() == InsetBase::CITE_CODE)
1517 it->dispatch(cur, fr);
1521 case LFUN_TEXTCLASS_APPLY: {
1522 Buffer * buffer = owner->buffer();
1524 lyx::textclass_type const old_class =
1525 buffer->params().textclass;
1527 loadTextclass(argument);
1529 std::pair<bool, lyx::textclass_type> const tc_pair =
1530 textclasslist.NumberOfClass(argument);
1535 lyx::textclass_type const new_class = tc_pair.second;
1536 if (old_class == new_class)
1540 owner->message(_("Converting document to new document class..."));
1541 recordUndoFullDocument(view());
1542 buffer->params().textclass = new_class;
1543 StableDocIterator backcur(view()->cursor());
1545 lyx::cap::SwitchBetweenClasses(
1546 old_class, new_class,
1547 buffer->paragraphs(), el);
1549 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1550 bufferErrors(*buffer, el);
1551 view()->showErrorList(_("Class switch"));
1552 updateCounters(*buffer);
1557 case LFUN_TEXTCLASS_LOAD:
1558 loadTextclass(argument);
1561 case LFUN_LYXRC_APPLY: {
1562 LyXRC const lyxrc_orig = lyxrc;
1564 istringstream ss(argument);
1565 bool const success = lyxrc.read(ss) == 0;
1568 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1569 << "Unable to read lyxrc data"
1574 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1579 view()->cursor().dispatch(cmd);
1580 update |= view()->cursor().result().update();
1581 if (!view()->cursor().result().dispatched())
1582 update |= view()->dispatch(cmd);
1587 if (view()->available()) {
1588 // Redraw screen unless explicitly told otherwise.
1589 // This also initializes the position cache for all insets
1590 // in (at least partially) visible top-level paragraphs.
1592 view()->update(Update::FitCursor | Update::Force);
1594 view()->update(Update::FitCursor);
1596 // if we executed a mutating lfun, mark the buffer as dirty
1598 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1599 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1600 view()->buffer()->markDirty();
1603 if (view()->cursor().inTexted()) {
1604 view()->owner()->updateLayoutChoice();
1607 sendDispatchMessage(_(getMessage()), cmd);
1611 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1613 /* When an action did not originate from the UI/kbd, it makes
1614 * sense to avoid updating the GUI. It turns out that this
1615 * fixes bug 1941, for reasons that are described here:
1616 * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1618 if (cmd.origin != FuncRequest::INTERNAL) {
1619 owner->updateMenubar();
1620 owner->updateToolbars();
1623 const bool verbose = (cmd.origin == FuncRequest::UI
1624 || cmd.origin == FuncRequest::COMMANDBUFFER);
1626 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1627 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1629 owner->message(msg);
1633 string dispatch_msg = msg;
1634 if (!dispatch_msg.empty())
1635 dispatch_msg += ' ';
1637 string comname = lyxaction.getActionName(cmd.action);
1639 bool argsadded = false;
1641 if (!cmd.argument.empty()) {
1642 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1643 comname += ' ' + cmd.argument;
1648 string const shortcuts = toplevel_keymap->printbindings(cmd);
1650 if (!shortcuts.empty())
1651 comname += ": " + shortcuts;
1652 else if (!argsadded && !cmd.argument.empty())
1653 comname += ' ' + cmd.argument;
1655 if (!comname.empty()) {
1656 comname = rtrim(comname);
1657 dispatch_msg += '(' + rtrim(comname) + ')';
1660 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1661 if (!dispatch_msg.empty())
1662 owner->message(dispatch_msg);
1666 void LyXFunc::setupLocalKeymap()
1668 keyseq.stdmap = toplevel_keymap.get();
1669 keyseq.curmap = toplevel_keymap.get();
1670 cancel_meta_seq.stdmap = toplevel_keymap.get();
1671 cancel_meta_seq.curmap = toplevel_keymap.get();
1675 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1677 string initpath = lyxrc.document_path;
1678 string filename(name);
1680 if (view()->available()) {
1681 string const trypath = owner->buffer()->filePath();
1682 // If directory is writeable, use this as default.
1683 if (IsDirWriteable(trypath))
1687 static int newfile_number;
1689 if (filename.empty()) {
1690 filename = AddName(lyxrc.document_path,
1691 "newfile" + convert<string>(++newfile_number) + ".lyx");
1692 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1694 filename = AddName(lyxrc.document_path,
1695 "newfile" + convert<string>(newfile_number) +
1700 // The template stuff
1703 FileDialog fileDlg(_("Select template file"),
1704 LFUN_SELECT_FILE_SYNC,
1705 make_pair(string(_("Documents|#o#O")),
1706 string(lyxrc.document_path)),
1707 make_pair(string(_("Templates|#T#t")),
1708 string(lyxrc.template_path)));
1710 FileDialog::Result result =
1711 fileDlg.open(lyxrc.template_path,
1712 FileFilterList(_("LyX Documents (*.lyx)")),
1715 if (result.first == FileDialog::Later)
1717 if (result.second.empty())
1719 templname = result.second;
1722 view()->newFile(filename, templname, !name.empty());
1726 void LyXFunc::open(string const & fname)
1728 string initpath = lyxrc.document_path;
1730 if (view()->available()) {
1731 string const trypath = owner->buffer()->filePath();
1732 // If directory is writeable, use this as default.
1733 if (IsDirWriteable(trypath))
1739 if (fname.empty()) {
1740 FileDialog fileDlg(_("Select document to open"),
1742 make_pair(string(_("Documents|#o#O")),
1743 string(lyxrc.document_path)),
1744 make_pair(string(_("Examples|#E#e")),
1745 string(AddPath(package().system_support(), "examples"))));
1747 FileDialog::Result result =
1748 fileDlg.open(initpath,
1749 FileFilterList(_("LyX Documents (*.lyx)")),
1752 if (result.first == FileDialog::Later)
1755 filename = result.second;
1757 // check selected filename
1758 if (filename.empty()) {
1759 owner->message(_("Canceled."));
1765 // get absolute path of file and add ".lyx" to the filename if
1767 string const fullpath = FileSearch(string(), filename, "lyx");
1768 if (!fullpath.empty()) {
1769 filename = fullpath;
1772 string const disp_fn(MakeDisplayPath(filename));
1774 // if the file doesn't exist, let the user create one
1775 if (!fs::exists(filename)) {
1776 // the user specifically chose this name. Believe them.
1777 view()->newFile(filename, "", true);
1781 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1784 if (view()->loadLyXFile(filename)) {
1785 str2 = bformat(_("Document %1$s opened."), disp_fn);
1787 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1789 owner->message(str2);
1793 void LyXFunc::doImport(string const & argument)
1796 string filename = split(argument, format, ' ');
1798 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1799 << " file: " << filename << endl;
1801 // need user interaction
1802 if (filename.empty()) {
1803 string initpath = lyxrc.document_path;
1805 if (view()->available()) {
1806 string const trypath = owner->buffer()->filePath();
1807 // If directory is writeable, use this as default.
1808 if (IsDirWriteable(trypath))
1812 string const text = bformat(_("Select %1$s file to import"),
1813 formats.prettyName(format));
1815 FileDialog fileDlg(text,
1817 make_pair(string(_("Documents|#o#O")),
1818 string(lyxrc.document_path)),
1819 make_pair(string(_("Examples|#E#e")),
1820 string(AddPath(package().system_support(), "examples"))));
1822 string const filter = formats.prettyName(format)
1823 + " (*." + formats.extension(format) + ')';
1825 FileDialog::Result result =
1826 fileDlg.open(initpath,
1827 FileFilterList(filter),
1830 if (result.first == FileDialog::Later)
1833 filename = result.second;
1835 // check selected filename
1836 if (filename.empty())
1837 owner->message(_("Canceled."));
1840 if (filename.empty())
1843 // get absolute path of file
1844 filename = MakeAbsPath(filename);
1846 string const lyxfile = ChangeExtension(filename, ".lyx");
1848 // Check if the document already is open
1849 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1850 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1851 owner->message(_("Canceled."));
1856 // if the file exists already, and we didn't do
1857 // -i lyx thefile.lyx, warn
1858 if (fs::exists(lyxfile) && filename != lyxfile) {
1859 string const file = MakeDisplayPath(lyxfile, 30);
1861 string text = bformat(_("The document %1$s already exists.\n\n"
1862 "Do you want to over-write that document?"), file);
1863 int const ret = Alert::prompt(_("Over-write document?"),
1864 text, 0, 1, _("&Over-write"), _("&Cancel"));
1867 owner->message(_("Canceled."));
1872 Importer::Import(owner, filename, format);
1876 void LyXFunc::closeBuffer()
1878 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1879 if (bufferlist.empty()) {
1880 // need this otherwise SEGV may occur while
1881 // trying to set variables that don't exist
1882 // since there's no current buffer
1883 owner->getDialogs().hideBufferDependent();
1885 view()->setBuffer(bufferlist.first());
1891 // Each "owner" should have it's own message method. lyxview and
1892 // the minibuffer would use the minibuffer, but lyxserver would
1893 // send an ERROR signal to its client. Alejandro 970603
1894 // This function is bit problematic when it comes to NLS, to make the
1895 // lyx servers client be language indepenent we must not translate
1896 // strings sent to this func.
1897 void LyXFunc::setErrorMessage(string const & m) const
1899 dispatch_buffer = m;
1904 void LyXFunc::setMessage(string const & m) const
1906 dispatch_buffer = m;
1910 string const LyXFunc::viewStatusMessage()
1912 // When meta-fake key is pressed, show the key sequence so far + "M-".
1914 return keyseq.print() + "M-";
1916 // Else, when a non-complete key sequence is pressed,
1917 // show the available options.
1918 if (keyseq.length() > 0 && !keyseq.deleted())
1919 return keyseq.printOptions();
1921 if (!view()->available())
1922 return _("Welcome to LyX!");
1924 return view()->cursor().currentState();
1928 BufferView * LyXFunc::view() const
1930 BOOST_ASSERT(owner);
1931 return owner->view().get();
1935 bool LyXFunc::wasMetaKey() const
1937 return (meta_fake_bit != key_modifier::none);
1943 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1945 // Why the switch you might ask. It is a trick to ensure that all
1946 // the elements in the LyXRCTags enum is handled. As you can see
1947 // there are no breaks at all. So it is just a huge fall-through.
1948 // The nice thing is that we will get a warning from the compiler
1949 // if we forget an element.
1950 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1952 case LyXRC::RC_ACCEPT_COMPOUND:
1953 case LyXRC::RC_ALT_LANG:
1954 case LyXRC::RC_ASCIIROFF_COMMAND:
1955 case LyXRC::RC_ASCII_LINELEN:
1956 case LyXRC::RC_AUTOREGIONDELETE:
1957 case LyXRC::RC_AUTORESET_OPTIONS:
1958 case LyXRC::RC_AUTOSAVE:
1959 case LyXRC::RC_AUTO_NUMBER:
1960 case LyXRC::RC_BACKUPDIR_PATH:
1961 case LyXRC::RC_BIBTEX_COMMAND:
1962 case LyXRC::RC_BINDFILE:
1963 case LyXRC::RC_CHECKLASTFILES:
1964 case LyXRC::RC_CHKTEX_COMMAND:
1965 case LyXRC::RC_CONVERTER:
1966 case LyXRC::RC_COPIER:
1967 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1968 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1969 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1970 case LyXRC::RC_CYGWIN_PATH_FIX:
1971 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1972 namespace os = lyx::support::os;
1973 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1975 case LyXRC::RC_DATE_INSERT_FORMAT:
1976 case LyXRC::RC_DEFAULT_LANGUAGE:
1977 case LyXRC::RC_DEFAULT_PAPERSIZE:
1978 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1979 case LyXRC::RC_DISPLAY_GRAPHICS:
1980 case LyXRC::RC_DOCUMENTPATH:
1981 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1982 if (fs::exists(lyxrc_new.document_path) &&
1983 fs::is_directory(lyxrc_new.document_path)) {
1984 using lyx::support::package;
1985 package().document_dir() = lyxrc.document_path;
1988 case LyXRC::RC_ESC_CHARS:
1989 case LyXRC::RC_FONT_ENCODING:
1990 case LyXRC::RC_FORMAT:
1991 case LyXRC::RC_INDEX_COMMAND:
1992 case LyXRC::RC_INPUT:
1993 case LyXRC::RC_KBMAP:
1994 case LyXRC::RC_KBMAP_PRIMARY:
1995 case LyXRC::RC_KBMAP_SECONDARY:
1996 case LyXRC::RC_LABEL_INIT_LENGTH:
1997 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1998 case LyXRC::RC_LANGUAGE_AUTO_END:
1999 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2000 case LyXRC::RC_LANGUAGE_COMMAND_END:
2001 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2002 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2003 case LyXRC::RC_LANGUAGE_PACKAGE:
2004 case LyXRC::RC_LANGUAGE_USE_BABEL:
2005 case LyXRC::RC_LASTFILES:
2006 case LyXRC::RC_MAKE_BACKUP:
2007 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2008 case LyXRC::RC_NUMLASTFILES:
2009 case LyXRC::RC_PATH_PREFIX:
2010 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2011 using lyx::support::prependEnvPath;
2012 prependEnvPath("PATH", lyxrc.path_prefix);
2014 case LyXRC::RC_PERS_DICT:
2015 case LyXRC::RC_POPUP_BOLD_FONT:
2016 case LyXRC::RC_POPUP_FONT_ENCODING:
2017 case LyXRC::RC_POPUP_NORMAL_FONT:
2018 case LyXRC::RC_PREVIEW:
2019 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2020 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2021 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2022 case LyXRC::RC_PRINTCOPIESFLAG:
2023 case LyXRC::RC_PRINTER:
2024 case LyXRC::RC_PRINTEVENPAGEFLAG:
2025 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2026 case LyXRC::RC_PRINTFILEEXTENSION:
2027 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2028 case LyXRC::RC_PRINTODDPAGEFLAG:
2029 case LyXRC::RC_PRINTPAGERANGEFLAG:
2030 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2031 case LyXRC::RC_PRINTPAPERFLAG:
2032 case LyXRC::RC_PRINTREVERSEFLAG:
2033 case LyXRC::RC_PRINTSPOOL_COMMAND:
2034 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2035 case LyXRC::RC_PRINTTOFILE:
2036 case LyXRC::RC_PRINTTOPRINTER:
2037 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2038 case LyXRC::RC_PRINT_COMMAND:
2039 case LyXRC::RC_RTL_SUPPORT:
2040 case LyXRC::RC_SCREEN_DPI:
2041 case LyXRC::RC_SCREEN_FONT_ENCODING:
2042 case LyXRC::RC_SCREEN_FONT_ROMAN:
2043 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2044 case LyXRC::RC_SCREEN_FONT_SANS:
2045 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2046 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2047 case LyXRC::RC_SCREEN_FONT_SIZES:
2048 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2049 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2050 case LyXRC::RC_SCREEN_ZOOM:
2051 case LyXRC::RC_SERVERPIPE:
2052 case LyXRC::RC_SET_COLOR:
2053 case LyXRC::RC_SHOW_BANNER:
2054 case LyXRC::RC_SPELL_COMMAND:
2055 case LyXRC::RC_TEMPDIRPATH:
2056 case LyXRC::RC_TEMPLATEPATH:
2057 case LyXRC::RC_TEX_ALLOWS_SPACES:
2058 case LyXRC::RC_UIFILE:
2059 case LyXRC::RC_USER_EMAIL:
2060 case LyXRC::RC_USER_NAME:
2061 case LyXRC::RC_USETEMPDIR:
2062 case LyXRC::RC_USE_ALT_LANG:
2063 case LyXRC::RC_USE_ESC_CHARS:
2064 case LyXRC::RC_USE_INP_ENC:
2065 case LyXRC::RC_USE_PERS_DICT:
2066 case LyXRC::RC_USE_SPELL_LIB:
2067 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2068 case LyXRC::RC_VIEWER:
2069 case LyXRC::RC_WHEEL_JUMP:
2070 case LyXRC::RC_LAST: