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 = cur.selection();
420 enable = buf->isLatex() && lyxrc.chktex_command != "none";
424 enable = Exporter::IsExportable(*buf, "program");
427 case LFUN_LAYOUT_TABULAR:
428 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
432 case LFUN_LAYOUT_PARAGRAPH:
433 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
436 case LFUN_VC_REGISTER:
437 enable = !buf->lyxvc().inUse();
439 case LFUN_VC_CHECKIN:
440 enable = buf->lyxvc().inUse() && !buf->isReadonly();
442 case LFUN_VC_CHECKOUT:
443 enable = buf->lyxvc().inUse() && buf->isReadonly();
447 enable = buf->lyxvc().inUse();
449 case LFUN_MENURELOAD:
450 enable = !buf->isUnnamed() && !buf->isClean();
453 case LFUN_INSET_SETTINGS: {
457 InsetBase::Code code = cur.inset().lyxCode();
459 case InsetBase::TABULAR_CODE:
460 enable = cmd.argument == "tabular";
462 case InsetBase::ERT_CODE:
463 enable = cmd.argument == "ert";
465 case InsetBase::FLOAT_CODE:
466 enable = cmd.argument == "float";
468 case InsetBase::WRAP_CODE:
469 enable = cmd.argument == "wrap";
471 case InsetBase::NOTE_CODE:
472 enable = cmd.argument == "note";
474 case InsetBase::BRANCH_CODE:
475 enable = cmd.argument == "branch";
477 case InsetBase::BOX_CODE:
478 enable = cmd.argument == "box";
486 case LFUN_INSET_APPLY: {
487 string const name = cmd.getArg(0);
488 InsetBase * inset = owner->getDialogs().getOpenInset(name);
490 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
492 bool const success = inset->getStatus(cur, fr, fs);
493 // Every inset is supposed to handle this
494 BOOST_ASSERT(success);
497 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
498 flag |= getStatus(fr);
500 enable = flag.enabled();
504 case LFUN_DIALOG_SHOW: {
505 string const name = cmd.getArg(0);
507 enable = name == "aboutlyx"
511 || name == "texinfo";
512 else if (name == "print")
513 enable = Exporter::IsExportable(*buf, "dvi")
514 && lyxrc.print_command != "none";
515 else if (name == "character" || name == "mathpanel")
516 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
517 else if (name == "latexlog")
518 enable = IsFileReadable(buf->getLogName().second);
519 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
520 else if (name == "spellchecker")
523 else if (name == "vclog")
524 enable = buf->lyxvc().inUse();
528 case LFUN_DIALOG_SHOW_NEW_INSET:
529 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
532 case LFUN_DIALOG_UPDATE: {
533 string const name = cmd.getArg(0);
535 enable = name == "prefs";
539 case LFUN_INSERT_CITATION: {
540 FuncRequest fr(LFUN_INSET_INSERT, "citation");
541 enable = getStatus(fr).enabled();
545 // this one is difficult to get right. As a half-baked
546 // solution, we consider only the first action of the sequence
547 case LFUN_SEQUENCE: {
548 // argument contains ';'-terminated commands
549 string const firstcmd = token(cmd.argument, ';', 0);
550 FuncRequest func(lyxaction.lookupFunc(firstcmd));
551 func.origin = cmd.origin;
552 flag = getStatus(func);
556 case LFUN_MENUNEWTMPLT:
557 case LFUN_WORDFINDFORWARD:
558 case LFUN_WORDFINDBACKWARD:
560 case LFUN_EXEC_COMMAND:
563 case LFUN_CLOSEBUFFER:
572 case LFUN_RECONFIGURE:
576 case LFUN_DROP_LAYOUTS_CHOICE:
577 case LFUN_MENU_OPEN_BY_NAME:
580 case LFUN_GOTOFILEROW:
581 case LFUN_DIALOG_SHOW_NEXT_INSET:
582 case LFUN_DIALOG_HIDE:
583 case LFUN_DIALOG_DISCONNECT_INSET:
585 case LFUN_TOGGLECURSORFOLLOW:
589 case LFUN_KMAP_TOGGLE:
591 case LFUN_EXPORT_CUSTOM:
593 case LFUN_SAVEPREFERENCES:
594 case LFUN_SCREEN_FONT_UPDATE:
597 case LFUN_EXTERNAL_EDIT:
598 case LFUN_GRAPHICS_EDIT:
599 case LFUN_ALL_INSETS_TOGGLE:
600 case LFUN_LANGUAGE_BUFFER:
601 case LFUN_TEXTCLASS_APPLY:
602 case LFUN_TEXTCLASS_LOAD:
603 case LFUN_SAVE_AS_DEFAULT:
604 case LFUN_BUFFERPARAMS_APPLY:
605 case LFUN_LYXRC_APPLY:
606 case LFUN_NEXTBUFFER:
607 case LFUN_PREVIOUSBUFFER:
608 // these are handled in our dispatch()
613 if (!::getStatus(cur, cmd, flag))
614 flag = view()->getStatus(cmd);
620 // Can we use a readonly buffer?
621 if (buf && buf->isReadonly()
622 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
623 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
624 flag.message(N_("Document is read-only"));
628 // Are we in a DELETED change-tracking region?
629 if (buf && buf->params().tracking_changes
630 && lookupChange(cur, true) == Change::DELETED
631 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
632 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
633 flag.message(N_("This portion of the document is deleted."));
637 // the default error message if we disable the command
638 if (!flag.enabled() && flag.message().empty())
639 flag.message(N_("Command disabled"));
647 bool ensureBufferClean(BufferView * bv)
649 Buffer & buf = *bv->buffer();
653 string const file = MakeDisplayPath(buf.fileName(), 30);
654 string text = bformat(_("The document %1$s has unsaved "
655 "changes.\n\nDo you want to save "
656 "the document?"), file);
657 int const ret = Alert::prompt(_("Save changed document?"),
658 text, 0, 1, _("&Save"),
662 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
664 return buf.isClean();
668 void showPrintError(string const & name)
670 string str = bformat(_("Could not print the document %1$s.\n"
671 "Check that your printer is set up correctly."),
672 MakeDisplayPath(name, 50));
673 Alert::error(_("Print document failed"), str);
677 void loadTextclass(string const & name)
679 std::pair<bool, lyx::textclass_type> const tc_pair =
680 textclasslist.NumberOfClass(name);
682 if (!tc_pair.first) {
683 lyxerr << "Document class \"" << name
684 << "\" does not exist."
689 lyx::textclass_type const tc = tc_pair.second;
691 if (!textclasslist[tc].load()) {
692 string s = bformat(_("The document could not be converted\n"
693 "into the document class %1$s."),
694 textclasslist[tc].name());
695 Alert::error(_("Could not change class"), s);
700 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
705 void LyXFunc::dispatch(FuncRequest const & cmd)
707 BOOST_ASSERT(view());
708 string const argument = cmd.argument;
709 kb_action const action = cmd.action;
711 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
712 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
714 // we have not done anything wrong yet.
716 dispatch_buffer.erase();
720 FuncStatus const flag = getStatus(cmd);
721 if (!flag.enabled()) {
722 // We cannot use this function here
723 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
724 << lyxaction.getActionName(action)
725 << " [" << action << "] is disabled at this location"
727 setErrorMessage(flag.message());
730 if (view()->available())
731 view()->hideCursor();
735 case LFUN_WORDFINDFORWARD:
736 case LFUN_WORDFINDBACKWARD: {
737 static string last_search;
738 string searched_string;
740 if (!argument.empty()) {
741 last_search = argument;
742 searched_string = argument;
744 searched_string = last_search;
747 if (searched_string.empty())
750 bool const fw = action == LFUN_WORDFINDFORWARD;
752 lyx::find::find2string(searched_string, true, false, fw);
753 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
758 owner->message(keyseq.printOptions());
761 case LFUN_EXEC_COMMAND:
762 owner->getToolbars().display("minibuffer", true);
763 owner->focus_command_buffer();
768 meta_fake_bit = key_modifier::none;
769 if (view()->available())
770 // cancel any selection
771 dispatch(FuncRequest(LFUN_MARK_OFF));
772 setMessage(N_("Cancel"));
776 meta_fake_bit = key_modifier::alt;
777 setMessage(keyseq.print());
780 case LFUN_READ_ONLY_TOGGLE:
781 if (owner->buffer()->lyxvc().inUse())
782 owner->buffer()->lyxvc().toggleReadOnly();
784 owner->buffer()->setReadonly(
785 !owner->buffer()->isReadonly());
788 // --- Menus -----------------------------------------------
790 menuNew(argument, false);
793 case LFUN_MENUNEWTMPLT:
794 menuNew(argument, true);
797 case LFUN_CLOSEBUFFER:
802 if (!owner->buffer()->isUnnamed()) {
803 string const str = bformat(_("Saving document %1$s..."),
804 MakeDisplayPath(owner->buffer()->fileName()));
806 MenuWrite(owner->buffer());
807 owner->message(str + _(" done."));
809 WriteAs(owner->buffer());
813 WriteAs(owner->buffer(), argument);
816 case LFUN_MENURELOAD: {
817 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
818 string text = bformat(_("Any changes will be lost. Are you sure "
819 "you want to revert to the saved version of the document %1$s?"), file);
820 int const ret = Alert::prompt(_("Revert to saved document?"),
821 text, 0, 1, _("&Revert"), _("&Cancel"));
829 Exporter::Export(owner->buffer(), argument, true);
830 view()->showErrorList(BufferFormat(*owner->buffer()));
834 Exporter::Preview(owner->buffer(), argument);
835 view()->showErrorList(BufferFormat(*owner->buffer()));
839 Exporter::Export(owner->buffer(), "program", true);
840 view()->showErrorList(_("Build"));
844 owner->buffer()->runChktex();
845 view()->showErrorList(_("ChkTeX"));
849 if (argument == "custom")
850 owner->getDialogs().show("sendto");
852 Exporter::Export(owner->buffer(), argument, false);
853 view()->showErrorList(BufferFormat(*owner->buffer()));
857 case LFUN_EXPORT_CUSTOM: {
859 string command = split(argument, format_name, ' ');
860 Format const * format = formats.getFormat(format_name);
862 lyxerr << "Format \"" << format_name
863 << "\" not recognized!"
868 Buffer * buffer = owner->buffer();
870 // The name of the file created by the conversion process
873 // Output to filename
874 if (format->name() == "lyx") {
875 string const latexname =
876 buffer->getLatexName(false);
877 filename = ChangeExtension(latexname,
878 format->extension());
879 filename = AddName(buffer->temppath(), filename);
881 if (!buffer->writeFile(filename))
885 Exporter::Export(buffer, format_name, true,
889 // Substitute $$FName for filename
890 if (!contains(command, "$$FName"))
891 command = "( " + command + " ) < $$FName";
892 command = subst(command, "$$FName", filename);
894 // Execute the command in the background
896 call.startscript(Systemcall::DontWait, command);
903 string command = split(split(argument, target, ' '),
907 || target_name.empty()
908 || command.empty()) {
909 lyxerr << "Unable to parse \""
910 << argument << '"' << std::endl;
913 if (target != "printer" && target != "file") {
914 lyxerr << "Unrecognized target \""
915 << target << '"' << std::endl;
919 Buffer * buffer = owner->buffer();
921 if (!Exporter::Export(buffer, "dvi", true)) {
922 showPrintError(buffer->fileName());
926 // Push directory path.
927 string const path = buffer->temppath();
930 // there are three cases here:
931 // 1. we print to a file
932 // 2. we print directly to a printer
933 // 3. we print using a spool command (print to file first)
936 string const dviname =
937 ChangeExtension(buffer->getLatexName(true),
940 if (target == "printer") {
941 if (!lyxrc.print_spool_command.empty()) {
942 // case 3: print using a spool
943 string const psname =
944 ChangeExtension(dviname,".ps");
945 command += lyxrc.print_to_file
948 + QuoteName(dviname);
951 lyxrc.print_spool_command +' ';
952 if (target_name != "default") {
953 command2 += lyxrc.print_spool_printerprefix
957 command2 += QuoteName(psname);
959 // If successful, then spool command
960 res = one.startscript(
965 res = one.startscript(
966 Systemcall::DontWait,
969 // case 2: print directly to a printer
970 res = one.startscript(
971 Systemcall::DontWait,
972 command + QuoteName(dviname));
976 // case 1: print to a file
977 command += lyxrc.print_to_file
978 + QuoteName(MakeAbsPath(target_name,
981 + QuoteName(dviname);
982 res = one.startscript(Systemcall::DontWait,
987 showPrintError(buffer->fileName());
996 QuitLyX(argument == "force");
1000 InsetCommandParams p("tableofcontents");
1001 string const data = InsetCommandMailer::params2string("toc", p);
1002 owner->getDialogs().show("toc", data, 0);
1010 case LFUN_RECONFIGURE:
1011 Reconfigure(view());
1014 case LFUN_HELP_OPEN: {
1015 string const arg = argument;
1017 setErrorMessage(N_("Missing argument"));
1020 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1021 if (fname.empty()) {
1022 lyxerr << "LyX: unable to find documentation file `"
1023 << arg << "'. Bad installation?" << endl;
1026 owner->message(bformat(_("Opening help file %1$s..."),
1027 MakeDisplayPath(fname)));
1028 view()->loadLyXFile(fname, false);
1032 // --- version control -------------------------------
1033 case LFUN_VC_REGISTER:
1034 if (!ensureBufferClean(view()))
1036 if (!owner->buffer()->lyxvc().inUse()) {
1037 owner->buffer()->lyxvc().registrer();
1042 case LFUN_VC_CHECKIN:
1043 if (!ensureBufferClean(view()))
1045 if (owner->buffer()->lyxvc().inUse()
1046 && !owner->buffer()->isReadonly()) {
1047 owner->buffer()->lyxvc().checkIn();
1052 case LFUN_VC_CHECKOUT:
1053 if (!ensureBufferClean(view()))
1055 if (owner->buffer()->lyxvc().inUse()
1056 && owner->buffer()->isReadonly()) {
1057 owner->buffer()->lyxvc().checkOut();
1062 case LFUN_VC_REVERT:
1063 owner->buffer()->lyxvc().revert();
1068 owner->buffer()->lyxvc().undoLast();
1072 // --- buffers ----------------------------------------
1073 case LFUN_SWITCHBUFFER:
1074 view()->setBuffer(bufferlist.getBuffer(argument));
1077 case LFUN_NEXTBUFFER:
1078 view()->setBuffer(bufferlist.next(view()->buffer()));
1081 case LFUN_PREVIOUSBUFFER:
1082 view()->setBuffer(bufferlist.previous(view()->buffer()));
1086 NewFile(view(), argument);
1089 case LFUN_FILE_OPEN:
1093 case LFUN_DROP_LAYOUTS_CHOICE:
1094 owner->getToolbars().openLayoutList();
1097 case LFUN_MENU_OPEN_BY_NAME:
1098 owner->getMenubar().openByName(argument);
1101 // --- lyxserver commands ----------------------------
1103 setMessage(owner->buffer()->fileName());
1104 lyxerr[Debug::INFO] << "FNAME["
1105 << owner->buffer()->fileName()
1110 dispatch_buffer = keyseq.print();
1111 lyxserver->notifyClient(dispatch_buffer);
1114 case LFUN_GOTOFILEROW: {
1117 istringstream is(argument);
1118 is >> file_name >> row;
1119 if (prefixIs(file_name, package().temp_dir())) {
1120 // Needed by inverse dvi search. If it is a file
1121 // in tmpdir, call the apropriated function
1122 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1124 // Must replace extension of the file to be .lyx
1125 // and get full path
1126 string const s = ChangeExtension(file_name, ".lyx");
1127 // Either change buffer or load the file
1128 if (bufferlist.exists(s)) {
1129 view()->setBuffer(bufferlist.getBuffer(s));
1131 view()->loadLyXFile(s);
1135 view()->setCursorFromRow(row);
1138 // see BufferView_pimpl::center()
1139 view()->updateScrollbar();
1143 case LFUN_DIALOG_SHOW: {
1144 string const name = cmd.getArg(0);
1145 string data = trim(cmd.argument.substr(name.size()));
1147 if (name == "character") {
1148 data = freefont2string();
1150 owner->getDialogs().show("character", data);
1153 else if (name == "latexlog") {
1154 pair<Buffer::LogType, string> const logfile =
1155 owner->buffer()->getLogName();
1156 switch (logfile.first) {
1157 case Buffer::latexlog:
1160 case Buffer::buildlog:
1164 data += logfile.second;
1165 owner->getDialogs().show("log", data);
1167 else if (name == "vclog") {
1168 string const data = "vc " +
1169 owner->buffer()->lyxvc().getLogFile();
1170 owner->getDialogs().show("log", data);
1173 owner->getDialogs().show(name, data);
1177 case LFUN_DIALOG_SHOW_NEW_INSET: {
1178 string const name = cmd.getArg(0);
1179 string data = trim(cmd.argument.substr(name.size()));
1180 if (name == "bibitem" ||
1187 InsetCommandParams p(name);
1188 data = InsetCommandMailer::params2string(name, p);
1189 } else if (name == "include") {
1190 InsetCommandParams p(data);
1191 data = InsetIncludeMailer::params2string(p);
1192 } else if (name == "box") {
1193 // \c data == "Boxed" || "Frameless" etc
1194 InsetBoxParams p(data);
1195 data = InsetBoxMailer::params2string(p);
1196 } else if (name == "branch") {
1197 InsetBranchParams p;
1198 data = InsetBranchMailer::params2string(p);
1199 } else if (name == "citation") {
1200 InsetCommandParams p("cite");
1201 data = InsetCommandMailer::params2string(name, p);
1202 } else if (name == "ert") {
1203 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1204 } else if (name == "external") {
1205 InsetExternalParams p;
1206 Buffer const & buffer = *owner->buffer();
1207 data = InsetExternalMailer::params2string(p, buffer);
1208 } else if (name == "float") {
1210 data = InsetFloatMailer::params2string(p);
1211 } else if (name == "graphics") {
1212 InsetGraphicsParams p;
1213 Buffer const & buffer = *owner->buffer();
1214 data = InsetGraphicsMailer::params2string(p, buffer);
1215 } else if (name == "note") {
1217 data = InsetNoteMailer::params2string(p);
1218 } else if (name == "vspace") {
1220 data = InsetVSpaceMailer::params2string(space);
1221 } else if (name == "wrap") {
1223 data = InsetWrapMailer::params2string(p);
1225 owner->getDialogs().show(name, data, 0);
1229 case LFUN_DIALOG_SHOW_NEXT_INSET:
1232 case LFUN_DIALOG_UPDATE: {
1233 string const & name = argument;
1234 // Can only update a dialog connected to an existing inset
1235 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1237 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1238 inset->dispatch(view()->cursor(), fr);
1239 } else if (name == "paragraph") {
1240 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1241 } else if (name == "prefs") {
1242 owner->getDialogs().update(name, string());
1247 case LFUN_DIALOG_HIDE:
1248 Dialogs::hide(argument, 0);
1251 case LFUN_DIALOG_DISCONNECT_INSET:
1252 owner->getDialogs().disconnect(argument);
1256 case LFUN_INSERT_CITATION: {
1257 if (!argument.empty()) {
1258 // we can have one optional argument, delimited by '|'
1259 // citation-insert <key>|<text_before>
1260 // this should be enhanced to also support text_after
1261 // and citation style
1262 string arg = argument;
1264 if (contains(argument, "|")) {
1265 arg = token(argument, '|', 0);
1266 opt1 = '[' + token(argument, '|', 1) + ']';
1268 std::ostringstream os;
1269 os << "citation LatexCommand\n"
1270 << "\\cite" << opt1 << "{" << arg << "}\n"
1272 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1275 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1279 case LFUN_CHILDOPEN: {
1280 string const filename =
1281 MakeAbsPath(argument, owner->buffer()->filePath());
1282 setMessage(N_("Opening child document ") +
1283 MakeDisplayPath(filename) + "...");
1284 view()->savePosition(0);
1285 string const parentfilename = owner->buffer()->fileName();
1286 if (bufferlist.exists(filename))
1287 view()->setBuffer(bufferlist.getBuffer(filename));
1289 view()->loadLyXFile(filename);
1290 // Set the parent name of the child document.
1291 // This makes insertion of citations and references in the child work,
1292 // when the target is in the parent or another child document.
1293 owner->buffer()->setParentName(parentfilename);
1297 case LFUN_TOGGLECURSORFOLLOW:
1298 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1302 owner->getIntl().KeyMapOn(false);
1305 case LFUN_KMAP_PRIM:
1306 owner->getIntl().KeyMapPrim();
1310 owner->getIntl().KeyMapSec();
1313 case LFUN_KMAP_TOGGLE:
1314 owner->getIntl().ToggleKeyMap();
1320 string rest = split(argument, countstr, ' ');
1321 istringstream is(countstr);
1324 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1325 for (int i = 0; i < count; ++i)
1326 dispatch(lyxaction.lookupFunc(rest));
1330 case LFUN_SEQUENCE: {
1331 // argument contains ';'-terminated commands
1332 string arg = argument;
1333 while (!arg.empty()) {
1335 arg = split(arg, first, ';');
1336 FuncRequest func(lyxaction.lookupFunc(first));
1337 func.origin = cmd.origin;
1343 case LFUN_SAVEPREFERENCES: {
1344 Path p(package().user_support());
1345 lyxrc.write("preferences", false);
1349 case LFUN_SCREEN_FONT_UPDATE:
1350 // handle the screen font changes.
1351 lyxrc.set_font_norm_type();
1352 lyx_gui::update_fonts();
1353 // All visible buffers will need resize
1357 case LFUN_SET_COLOR: {
1359 string const x11_name = split(argument, lyx_name, ' ');
1360 if (lyx_name.empty() || x11_name.empty()) {
1361 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1366 bool const graphicsbg_changed =
1367 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1368 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1370 if (!lcolor.setColor(lyx_name, x11_name)) {
1372 bformat(_("Set-color \"%1$s\" failed "
1373 "- color is undefined or "
1374 "may not be redefined"), lyx_name));
1378 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1380 if (graphicsbg_changed) {
1381 #ifdef WITH_WARNINGS
1382 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1385 lyx::graphics::GCache::get().changeDisplay(true);
1392 owner->message(argument);
1395 case LFUN_TOOLTIPS_TOGGLE:
1396 owner->getDialogs().toggleTooltips();
1399 case LFUN_EXTERNAL_EDIT: {
1400 FuncRequest fr(action, argument);
1401 InsetExternal().dispatch(view()->cursor(), fr);
1405 case LFUN_GRAPHICS_EDIT: {
1406 FuncRequest fr(action, argument);
1407 InsetGraphics().dispatch(view()->cursor(), fr);
1411 case LFUN_INSET_APPLY: {
1412 string const name = cmd.getArg(0);
1413 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1415 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1416 inset->dispatch(view()->cursor(), fr);
1418 FuncRequest fr(LFUN_INSET_INSERT, argument);
1421 // ideally, the update flag should be set by the insets,
1422 // but this is not possible currently
1427 case LFUN_ALL_INSETS_TOGGLE: {
1429 string const name = split(argument, action, ' ');
1430 InsetBase::Code const inset_code =
1431 InsetBase::translate(name);
1433 LCursor & cur = view()->cursor();
1434 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1436 InsetBase & inset = owner->buffer()->inset();
1437 InsetIterator it = inset_iterator_begin(inset);
1438 InsetIterator const end = inset_iterator_end(inset);
1439 for (; it != end; ++it) {
1440 if (inset_code == InsetBase::NO_CODE
1441 || inset_code == it->lyxCode()) {
1442 LCursor tmpcur = cur;
1443 tmpcur.pushLeft(*it);
1444 it->dispatch(tmpcur, fr);
1451 case LFUN_LANGUAGE_BUFFER: {
1452 Buffer & buffer = *owner->buffer();
1453 Language const * oldL = buffer.params().language;
1454 Language const * newL = languages.getLanguage(argument);
1455 if (!newL || oldL == newL)
1458 if (oldL->RightToLeft() == newL->RightToLeft()
1459 && !buffer.isMultiLingual())
1460 buffer.changeLanguage(oldL, newL);
1462 buffer.updateDocLang(newL);
1466 case LFUN_SAVE_AS_DEFAULT: {
1467 string const fname =
1468 AddName(AddPath(package().user_support(), "templates/"),
1470 Buffer defaults(fname);
1472 istringstream ss(argument);
1475 int const unknown_tokens = defaults.readHeader(lex);
1477 if (unknown_tokens != 0) {
1478 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1479 << unknown_tokens << " unknown token"
1480 << (unknown_tokens == 1 ? "" : "s")
1484 if (defaults.writeFile(defaults.fileName()))
1485 setMessage(_("Document defaults saved in ")
1486 + MakeDisplayPath(fname));
1488 setErrorMessage(_("Unable to save document defaults"));
1492 case LFUN_BUFFERPARAMS_APPLY: {
1493 biblio::CiteEngine const engine =
1494 owner->buffer()->params().cite_engine;
1496 istringstream ss(argument);
1499 int const unknown_tokens =
1500 owner->buffer()->readHeader(lex);
1502 if (unknown_tokens != 0) {
1503 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1504 << unknown_tokens << " unknown token"
1505 << (unknown_tokens == 1 ? "" : "s")
1508 if (engine == owner->buffer()->params().cite_engine)
1511 LCursor & cur = view()->cursor();
1512 FuncRequest fr(LFUN_INSET_REFRESH);
1514 InsetBase & inset = owner->buffer()->inset();
1515 InsetIterator it = inset_iterator_begin(inset);
1516 InsetIterator const end = inset_iterator_end(inset);
1517 for (; it != end; ++it)
1518 if (it->lyxCode() == InsetBase::CITE_CODE)
1519 it->dispatch(cur, fr);
1523 case LFUN_TEXTCLASS_APPLY: {
1524 Buffer * buffer = owner->buffer();
1526 lyx::textclass_type const old_class =
1527 buffer->params().textclass;
1529 loadTextclass(argument);
1531 std::pair<bool, lyx::textclass_type> const tc_pair =
1532 textclasslist.NumberOfClass(argument);
1537 lyx::textclass_type const new_class = tc_pair.second;
1538 if (old_class == new_class)
1542 owner->message(_("Converting document to new document class..."));
1543 recordUndoFullDocument(view());
1544 buffer->params().textclass = new_class;
1545 StableDocIterator backcur(view()->cursor());
1547 lyx::cap::SwitchBetweenClasses(
1548 old_class, new_class,
1549 buffer->paragraphs(), el);
1551 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1552 bufferErrors(*buffer, el);
1553 view()->showErrorList(_("Class switch"));
1554 updateCounters(*buffer);
1559 case LFUN_TEXTCLASS_LOAD:
1560 loadTextclass(argument);
1563 case LFUN_LYXRC_APPLY: {
1564 LyXRC const lyxrc_orig = lyxrc;
1566 istringstream ss(argument);
1567 bool const success = lyxrc.read(ss) == 0;
1570 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1571 << "Unable to read lyxrc data"
1576 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1581 view()->cursor().dispatch(cmd);
1582 update |= view()->cursor().result().update();
1583 if (!view()->cursor().result().dispatched())
1584 update |= view()->dispatch(cmd);
1589 if (view()->available()) {
1590 // Redraw screen unless explicitly told otherwise.
1591 // This also initializes the position cache for all insets
1592 // in (at least partially) visible top-level paragraphs.
1594 view()->update(Update::FitCursor | Update::Force);
1596 view()->update(Update::FitCursor);
1598 // if we executed a mutating lfun, mark the buffer as dirty
1599 // FIXME: Why not use flag.enabled() but call getStatus again?
1600 if (getStatus(cmd).enabled()
1601 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1602 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1603 view()->buffer()->markDirty();
1606 if (view()->cursor().inTexted()) {
1607 view()->owner()->updateLayoutChoice();
1610 sendDispatchMessage(_(getMessage()), cmd);
1614 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1616 /* When an action did not originate from the UI/kbd, it makes
1617 * sense to avoid updating the GUI. It turns out that this
1618 * fixes bug 1941, for reasons that are described here:
1619 * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1621 if (cmd.origin != FuncRequest::INTERNAL) {
1622 owner->updateMenubar();
1623 owner->updateToolbars();
1626 const bool verbose = (cmd.origin == FuncRequest::UI
1627 || cmd.origin == FuncRequest::COMMANDBUFFER);
1629 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1630 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1632 owner->message(msg);
1636 string dispatch_msg = msg;
1637 if (!dispatch_msg.empty())
1638 dispatch_msg += ' ';
1640 string comname = lyxaction.getActionName(cmd.action);
1642 bool argsadded = false;
1644 if (!cmd.argument.empty()) {
1645 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1646 comname += ' ' + cmd.argument;
1651 string const shortcuts = toplevel_keymap->printbindings(cmd);
1653 if (!shortcuts.empty())
1654 comname += ": " + shortcuts;
1655 else if (!argsadded && !cmd.argument.empty())
1656 comname += ' ' + cmd.argument;
1658 if (!comname.empty()) {
1659 comname = rtrim(comname);
1660 dispatch_msg += '(' + rtrim(comname) + ')';
1663 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1664 if (!dispatch_msg.empty())
1665 owner->message(dispatch_msg);
1669 void LyXFunc::setupLocalKeymap()
1671 keyseq.stdmap = toplevel_keymap.get();
1672 keyseq.curmap = toplevel_keymap.get();
1673 cancel_meta_seq.stdmap = toplevel_keymap.get();
1674 cancel_meta_seq.curmap = toplevel_keymap.get();
1678 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1680 string initpath = lyxrc.document_path;
1681 string filename(name);
1683 if (view()->available()) {
1684 string const trypath = owner->buffer()->filePath();
1685 // If directory is writeable, use this as default.
1686 if (IsDirWriteable(trypath))
1690 static int newfile_number;
1692 if (filename.empty()) {
1693 filename = AddName(lyxrc.document_path,
1694 "newfile" + convert<string>(++newfile_number) + ".lyx");
1695 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1697 filename = AddName(lyxrc.document_path,
1698 "newfile" + convert<string>(newfile_number) +
1703 // The template stuff
1706 FileDialog fileDlg(_("Select template file"),
1707 LFUN_SELECT_FILE_SYNC,
1708 make_pair(string(_("Documents|#o#O")),
1709 string(lyxrc.document_path)),
1710 make_pair(string(_("Templates|#T#t")),
1711 string(lyxrc.template_path)));
1713 FileDialog::Result result =
1714 fileDlg.open(lyxrc.template_path,
1715 FileFilterList(_("LyX Documents (*.lyx)")),
1718 if (result.first == FileDialog::Later)
1720 if (result.second.empty())
1722 templname = result.second;
1725 view()->newFile(filename, templname, !name.empty());
1729 void LyXFunc::open(string const & fname)
1731 string initpath = lyxrc.document_path;
1733 if (view()->available()) {
1734 string const trypath = owner->buffer()->filePath();
1735 // If directory is writeable, use this as default.
1736 if (IsDirWriteable(trypath))
1742 if (fname.empty()) {
1743 FileDialog fileDlg(_("Select document to open"),
1745 make_pair(string(_("Documents|#o#O")),
1746 string(lyxrc.document_path)),
1747 make_pair(string(_("Examples|#E#e")),
1748 string(AddPath(package().system_support(), "examples"))));
1750 FileDialog::Result result =
1751 fileDlg.open(initpath,
1752 FileFilterList(_("LyX Documents (*.lyx)")),
1755 if (result.first == FileDialog::Later)
1758 filename = result.second;
1760 // check selected filename
1761 if (filename.empty()) {
1762 owner->message(_("Canceled."));
1768 // get absolute path of file and add ".lyx" to the filename if
1770 string const fullpath = FileSearch(string(), filename, "lyx");
1771 if (!fullpath.empty()) {
1772 filename = fullpath;
1775 string const disp_fn(MakeDisplayPath(filename));
1777 // if the file doesn't exist, let the user create one
1778 if (!fs::exists(filename)) {
1779 // the user specifically chose this name. Believe them.
1780 view()->newFile(filename, "", true);
1784 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1787 if (view()->loadLyXFile(filename)) {
1788 str2 = bformat(_("Document %1$s opened."), disp_fn);
1790 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1792 owner->message(str2);
1796 void LyXFunc::doImport(string const & argument)
1799 string filename = split(argument, format, ' ');
1801 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1802 << " file: " << filename << endl;
1804 // need user interaction
1805 if (filename.empty()) {
1806 string initpath = lyxrc.document_path;
1808 if (view()->available()) {
1809 string const trypath = owner->buffer()->filePath();
1810 // If directory is writeable, use this as default.
1811 if (IsDirWriteable(trypath))
1815 string const text = bformat(_("Select %1$s file to import"),
1816 formats.prettyName(format));
1818 FileDialog fileDlg(text,
1820 make_pair(string(_("Documents|#o#O")),
1821 string(lyxrc.document_path)),
1822 make_pair(string(_("Examples|#E#e")),
1823 string(AddPath(package().system_support(), "examples"))));
1825 string const filter = formats.prettyName(format)
1826 + " (*." + formats.extension(format) + ')';
1828 FileDialog::Result result =
1829 fileDlg.open(initpath,
1830 FileFilterList(filter),
1833 if (result.first == FileDialog::Later)
1836 filename = result.second;
1838 // check selected filename
1839 if (filename.empty())
1840 owner->message(_("Canceled."));
1843 if (filename.empty())
1846 // get absolute path of file
1847 filename = MakeAbsPath(filename);
1849 string const lyxfile = ChangeExtension(filename, ".lyx");
1851 // Check if the document already is open
1852 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1853 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1854 owner->message(_("Canceled."));
1859 // if the file exists already, and we didn't do
1860 // -i lyx thefile.lyx, warn
1861 if (fs::exists(lyxfile) && filename != lyxfile) {
1862 string const file = MakeDisplayPath(lyxfile, 30);
1864 string text = bformat(_("The document %1$s already exists.\n\n"
1865 "Do you want to over-write that document?"), file);
1866 int const ret = Alert::prompt(_("Over-write document?"),
1867 text, 0, 1, _("&Over-write"), _("&Cancel"));
1870 owner->message(_("Canceled."));
1875 Importer::Import(owner, filename, format);
1879 void LyXFunc::closeBuffer()
1881 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1882 if (bufferlist.empty()) {
1883 // need this otherwise SEGV may occur while
1884 // trying to set variables that don't exist
1885 // since there's no current buffer
1886 owner->getDialogs().hideBufferDependent();
1888 view()->setBuffer(bufferlist.first());
1894 // Each "owner" should have it's own message method. lyxview and
1895 // the minibuffer would use the minibuffer, but lyxserver would
1896 // send an ERROR signal to its client. Alejandro 970603
1897 // This function is bit problematic when it comes to NLS, to make the
1898 // lyx servers client be language indepenent we must not translate
1899 // strings sent to this func.
1900 void LyXFunc::setErrorMessage(string const & m) const
1902 dispatch_buffer = m;
1907 void LyXFunc::setMessage(string const & m) const
1909 dispatch_buffer = m;
1913 string const LyXFunc::viewStatusMessage()
1915 // When meta-fake key is pressed, show the key sequence so far + "M-".
1917 return keyseq.print() + "M-";
1919 // Else, when a non-complete key sequence is pressed,
1920 // show the available options.
1921 if (keyseq.length() > 0 && !keyseq.deleted())
1922 return keyseq.printOptions();
1924 if (!view()->available())
1925 return _("Welcome to LyX!");
1927 return view()->cursor().currentState();
1931 BufferView * LyXFunc::view() const
1933 BOOST_ASSERT(owner);
1934 return owner->view().get();
1938 bool LyXFunc::wasMetaKey() const
1940 return (meta_fake_bit != key_modifier::none);
1946 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1948 // Why the switch you might ask. It is a trick to ensure that all
1949 // the elements in the LyXRCTags enum is handled. As you can see
1950 // there are no breaks at all. So it is just a huge fall-through.
1951 // The nice thing is that we will get a warning from the compiler
1952 // if we forget an element.
1953 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1955 case LyXRC::RC_ACCEPT_COMPOUND:
1956 case LyXRC::RC_ALT_LANG:
1957 case LyXRC::RC_ASCIIROFF_COMMAND:
1958 case LyXRC::RC_ASCII_LINELEN:
1959 case LyXRC::RC_AUTOREGIONDELETE:
1960 case LyXRC::RC_AUTORESET_OPTIONS:
1961 case LyXRC::RC_AUTOSAVE:
1962 case LyXRC::RC_AUTO_NUMBER:
1963 case LyXRC::RC_BACKUPDIR_PATH:
1964 case LyXRC::RC_BIBTEX_COMMAND:
1965 case LyXRC::RC_BINDFILE:
1966 case LyXRC::RC_CHECKLASTFILES:
1967 case LyXRC::RC_CHKTEX_COMMAND:
1968 case LyXRC::RC_CONVERTER:
1969 case LyXRC::RC_COPIER:
1970 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1971 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1972 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1973 case LyXRC::RC_CYGWIN_PATH_FIX:
1974 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1975 namespace os = lyx::support::os;
1976 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1978 case LyXRC::RC_DATE_INSERT_FORMAT:
1979 case LyXRC::RC_DEFAULT_LANGUAGE:
1980 case LyXRC::RC_DEFAULT_PAPERSIZE:
1981 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1982 case LyXRC::RC_DISPLAY_GRAPHICS:
1983 case LyXRC::RC_DOCUMENTPATH:
1984 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1985 if (fs::exists(lyxrc_new.document_path) &&
1986 fs::is_directory(lyxrc_new.document_path)) {
1987 using lyx::support::package;
1988 package().document_dir() = lyxrc.document_path;
1991 case LyXRC::RC_ESC_CHARS:
1992 case LyXRC::RC_FONT_ENCODING:
1993 case LyXRC::RC_FORMAT:
1994 case LyXRC::RC_INDEX_COMMAND:
1995 case LyXRC::RC_INPUT:
1996 case LyXRC::RC_KBMAP:
1997 case LyXRC::RC_KBMAP_PRIMARY:
1998 case LyXRC::RC_KBMAP_SECONDARY:
1999 case LyXRC::RC_LABEL_INIT_LENGTH:
2000 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2001 case LyXRC::RC_LANGUAGE_AUTO_END:
2002 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2003 case LyXRC::RC_LANGUAGE_COMMAND_END:
2004 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2005 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2006 case LyXRC::RC_LANGUAGE_PACKAGE:
2007 case LyXRC::RC_LANGUAGE_USE_BABEL:
2008 case LyXRC::RC_LASTFILES:
2009 case LyXRC::RC_MAKE_BACKUP:
2010 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2011 case LyXRC::RC_NUMLASTFILES:
2012 case LyXRC::RC_PATH_PREFIX:
2013 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2014 using lyx::support::prependEnvPath;
2015 prependEnvPath("PATH", lyxrc.path_prefix);
2017 case LyXRC::RC_PERS_DICT:
2018 case LyXRC::RC_POPUP_BOLD_FONT:
2019 case LyXRC::RC_POPUP_FONT_ENCODING:
2020 case LyXRC::RC_POPUP_NORMAL_FONT:
2021 case LyXRC::RC_PREVIEW:
2022 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2023 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2024 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2025 case LyXRC::RC_PRINTCOPIESFLAG:
2026 case LyXRC::RC_PRINTER:
2027 case LyXRC::RC_PRINTEVENPAGEFLAG:
2028 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2029 case LyXRC::RC_PRINTFILEEXTENSION:
2030 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2031 case LyXRC::RC_PRINTODDPAGEFLAG:
2032 case LyXRC::RC_PRINTPAGERANGEFLAG:
2033 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2034 case LyXRC::RC_PRINTPAPERFLAG:
2035 case LyXRC::RC_PRINTREVERSEFLAG:
2036 case LyXRC::RC_PRINTSPOOL_COMMAND:
2037 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2038 case LyXRC::RC_PRINTTOFILE:
2039 case LyXRC::RC_PRINTTOPRINTER:
2040 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2041 case LyXRC::RC_PRINT_COMMAND:
2042 case LyXRC::RC_RTL_SUPPORT:
2043 case LyXRC::RC_SCREEN_DPI:
2044 case LyXRC::RC_SCREEN_FONT_ENCODING:
2045 case LyXRC::RC_SCREEN_FONT_ROMAN:
2046 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2047 case LyXRC::RC_SCREEN_FONT_SANS:
2048 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2049 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2050 case LyXRC::RC_SCREEN_FONT_SIZES:
2051 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2052 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2053 case LyXRC::RC_SCREEN_ZOOM:
2054 case LyXRC::RC_SERVERPIPE:
2055 case LyXRC::RC_SET_COLOR:
2056 case LyXRC::RC_SHOW_BANNER:
2057 case LyXRC::RC_SPELL_COMMAND:
2058 case LyXRC::RC_TEMPDIRPATH:
2059 case LyXRC::RC_TEMPLATEPATH:
2060 case LyXRC::RC_TEX_ALLOWS_SPACES:
2061 case LyXRC::RC_UIFILE:
2062 case LyXRC::RC_USER_EMAIL:
2063 case LyXRC::RC_USER_NAME:
2064 case LyXRC::RC_USETEMPDIR:
2065 case LyXRC::RC_USE_ALT_LANG:
2066 case LyXRC::RC_USE_ESC_CHARS:
2067 case LyXRC::RC_USE_INP_ENC:
2068 case LyXRC::RC_USE_PERS_DICT:
2069 case LyXRC::RC_USE_SPELL_LIB:
2070 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2071 case LyXRC::RC_VIEWER:
2072 case LyXRC::RC_WHEEL_JUMP:
2073 case LyXRC::RC_LAST: