3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
24 #include "BranchList.h"
26 #include "buffer_funcs.h"
27 #include "bufferlist.h"
28 #include "bufferparams.h"
29 #include "BufferView.h"
31 #include "CutAndPaste.h"
33 #include "dispatchresult.h"
35 #include "errorlist.h"
38 #include "funcrequest.h"
41 #include "insetiterator.h"
47 #include "LyXAction.h"
52 #include "lyxserver.h"
53 #include "lyxtextclasslist.h"
55 #include "paragraph.h"
56 #include "pariterator.h"
57 #include "ParagraphParameters.h"
60 #include "insets/insetbox.h"
61 #include "insets/insetbranch.h"
62 #include "insets/insetcommand.h"
63 #include "insets/insetert.h"
64 #include "insets/insetexternal.h"
65 #include "insets/insetfloat.h"
66 #include "insets/insetgraphics.h"
67 #include "insets/insetinclude.h"
68 #include "insets/insetnote.h"
69 #include "insets/insettabular.h"
70 #include "insets/insetvspace.h"
71 #include "insets/insetwrap.h"
73 #include "frontends/Alert.h"
74 #include "frontends/Dialogs.h"
75 #include "frontends/FileDialog.h"
76 #include "frontends/lyx_gui.h"
77 #include "frontends/LyXKeySym.h"
78 #include "frontends/LyXView.h"
79 #include "frontends/Menubar.h"
80 #include "frontends/Toolbars.h"
82 #include "support/environment.h"
83 #include "support/filefilterlist.h"
84 #include "support/filetools.h"
85 #include "support/forkedcontr.h"
86 #include "support/fs_extras.h"
87 #include "support/lstrings.h"
88 #include "support/path.h"
89 #include "support/package.h"
90 #include "support/systemcall.h"
91 #include "support/convert.h"
92 #include "support/os.h"
94 #include <boost/current_function.hpp>
95 #include <boost/filesystem/operations.hpp>
99 using bv_funcs::freefont2string;
101 using lyx::support::AbsolutePath;
102 using lyx::support::AddName;
103 using lyx::support::AddPath;
104 using lyx::support::bformat;
105 using lyx::support::ChangeExtension;
106 using lyx::support::contains;
107 using lyx::support::FileFilterList;
108 using lyx::support::FileSearch;
109 using lyx::support::ForkedcallsController;
110 using lyx::support::i18nLibFileSearch;
111 using lyx::support::IsDirWriteable;
112 using lyx::support::IsFileReadable;
113 using lyx::support::isStrInt;
114 using lyx::support::MakeAbsPath;
115 using lyx::support::MakeDisplayPath;
116 using lyx::support::package;
117 using lyx::support::Path;
118 using lyx::support::QuoteName;
119 using lyx::support::rtrim;
120 using lyx::support::split;
121 using lyx::support::subst;
122 using lyx::support::Systemcall;
123 using lyx::support::token;
124 using lyx::support::trim;
125 using lyx::support::prefixIs;
128 using std::make_pair;
131 using std::istringstream;
133 namespace biblio = lyx::biblio;
134 namespace fs = boost::filesystem;
137 extern BufferList bufferlist;
138 extern LyXServer * lyxserver;
140 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
143 extern tex_accent_struct get_accent(kb_action action);
148 bool getStatus(LCursor cursor,
149 FuncRequest const & cmd, FuncStatus & status)
151 // Try to fix cursor in case it is broken.
152 cursor.fixIfBroken();
154 // This is, of course, a mess. Better create a new doc iterator and use
155 // this in Inset::getStatus. This might require an additional
156 // BufferView * arg, though (which should be avoided)
157 //LCursor safe = *this;
159 for ( ; cursor.depth(); cursor.pop()) {
160 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
161 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
162 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
163 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
165 // The inset's getStatus() will return 'true' if it made
166 // a definitive decision on whether it want to handle the
167 // request or not. The result of this decision is put into
168 // the 'status' parameter.
169 if (cursor.inset().getStatus(cursor, cmd, status)) {
178 /** Return the change status at cursor position, taking in account the
179 * status at each level of the document iterator (a table in a deleted
180 * footnote is deleted).
181 * When \param outer is true, the top slice is not looked at.
183 Change::Type lookupChange(DocIterator const & dit, bool outer = false)
185 size_t const depth = dit.depth() - (outer ? 1 : 0);
187 for (size_t i = 0 ; i < depth ; ++i) {
188 CursorSlice const & slice = dit[i];
189 if (!slice.inset().inMathed()
190 && slice.pos() < slice.paragraph().size()) {
191 Change::Type const ch = slice.paragraph().lookupChange(slice.pos());
192 if (ch != Change::UNCHANGED)
196 return Change::UNCHANGED;
201 LyXFunc::LyXFunc(LyXView * lv)
204 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
205 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
206 meta_fake_bit(key_modifier::none)
211 void LyXFunc::handleKeyFunc(kb_action action)
213 char c = encoded_last_key;
215 if (keyseq.length()) {
219 owner->getIntl().getTransManager()
220 .deadkey(c, get_accent(action).accent, view()->getLyXText());
221 // Need to clear, in case the minibuffer calls these
224 // copied verbatim from do_accent_char
225 view()->cursor().resetAnchor();
230 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
232 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
234 // Do nothing if we have nothing (JMarc)
235 if (!keysym->isOK()) {
236 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
241 if (keysym->isModifier()) {
242 lyxerr[Debug::KEY] << "isModifier true" << endl;
246 Encoding const * encoding = view()->cursor().getEncoding();
248 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
250 // Do a one-deep top-level lookup for
251 // cancel and meta-fake keys. RVDK_PATCH_5
252 cancel_meta_seq.reset();
254 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
255 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
256 << " action first set to [" << func.action << ']'
259 // When not cancel or meta-fake, do the normal lookup.
260 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
261 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
262 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
263 // remove Caps Lock and Mod2 as a modifiers
264 func = keyseq.addkey(keysym, (state | meta_fake_bit));
265 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
266 << "action now set to ["
267 << func.action << ']' << endl;
270 // Dont remove this unless you know what you are doing.
271 meta_fake_bit = key_modifier::none;
273 // Can this happen now ?
274 if (func.action == LFUN_NOACTION) {
275 func = FuncRequest(LFUN_PREFIX);
278 if (lyxerr.debugging(Debug::KEY)) {
279 lyxerr << BOOST_CURRENT_FUNCTION
281 << func.action << "]["
282 << keyseq.print() << ']'
286 // already here we know if it any point in going further
287 // why not return already here if action == -1 and
288 // num_bytes == 0? (Lgb)
290 if (keyseq.length() > 1) {
291 owner->message(keyseq.print());
295 // Maybe user can only reach the key via holding down shift.
296 // Let's see. But only if shift is the only modifier
297 if (func.action == LFUN_UNKNOWN_ACTION &&
298 state == key_modifier::shift) {
299 lyxerr[Debug::KEY] << "Trying without shift" << endl;
300 func = keyseq.addkey(keysym, key_modifier::none);
301 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
304 if (func.action == LFUN_UNKNOWN_ACTION) {
305 // Hmm, we didn't match any of the keysequences. See
306 // if it's normal insertable text not already covered
308 if (keysym->isText() && keyseq.length() == 1) {
309 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
310 func = FuncRequest(LFUN_SELFINSERT,
311 FuncRequest::KEYBOARD);
313 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
314 owner->message(_("Unknown function."));
319 if (func.action == LFUN_SELFINSERT) {
320 if (encoded_last_key != 0) {
321 string const arg(1, encoded_last_key);
322 dispatch(FuncRequest(LFUN_SELFINSERT, arg,
323 FuncRequest::KEYBOARD));
325 << "SelfInsert arg[`" << arg << "']" << endl;
333 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
335 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
337 LCursor & cur = view()->cursor();
339 /* In LyX/Mac, when a dialog is open, the menus of the
340 application can still be accessed without giving focus to
341 the main window. In this case, we want to disable the menu
342 entries that are buffer-related.
344 Note that this code is not perfect, as bug 1941 attests:
345 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
348 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
351 buf = owner->buffer();
353 if (cmd.action == LFUN_NOACTION) {
354 flag.message(N_("Nothing to do"));
359 switch (cmd.action) {
360 case LFUN_UNKNOWN_ACTION:
361 #ifndef HAVE_LIBAIKSAURUS
362 case LFUN_THESAURUS_ENTRY:
368 flag |= lyx_gui::getStatus(cmd);
371 if (flag.unknown()) {
372 flag.message(N_("Unknown action"));
376 if (!flag.enabled()) {
377 if (flag.message().empty())
378 flag.message(N_("Command disabled"));
382 // Check whether we need a buffer
383 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
385 flag.message(N_("Command not allowed with"
386 "out any document open"));
391 // I would really like to avoid having this switch and rather try to
392 // encode this in the function itself.
393 // -- And I'd rather let an inset decide which LFUNs it is willing
394 // to handle (Andre')
396 switch (cmd.action) {
397 case LFUN_TOOLTIPS_TOGGLE:
398 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
401 case LFUN_READ_ONLY_TOGGLE:
402 flag.setOnOff(buf->isReadonly());
405 case LFUN_SWITCHBUFFER:
406 // toggle on the current buffer, but do not toggle off
407 // the other ones (is that a good idea?)
408 if (cmd.argument == buf->fileName())
413 enable = cmd.argument == "custom"
414 || Exporter::IsExportable(*buf, cmd.argument);
418 enable = buf->isLatex() && lyxrc.chktex_command != "none";
422 enable = Exporter::IsExportable(*buf, "program");
425 case LFUN_LAYOUT_TABULAR:
426 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
430 case LFUN_LAYOUT_PARAGRAPH:
431 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
434 case LFUN_VC_REGISTER:
435 enable = !buf->lyxvc().inUse();
437 case LFUN_VC_CHECKIN:
438 enable = buf->lyxvc().inUse() && !buf->isReadonly();
440 case LFUN_VC_CHECKOUT:
441 enable = buf->lyxvc().inUse() && buf->isReadonly();
445 enable = buf->lyxvc().inUse();
447 case LFUN_MENURELOAD:
448 enable = !buf->isUnnamed() && !buf->isClean();
451 case LFUN_INSET_SETTINGS: {
455 InsetBase::Code code = cur.inset().lyxCode();
457 case InsetBase::TABULAR_CODE:
458 enable = cmd.argument == "tabular";
460 case InsetBase::ERT_CODE:
461 enable = cmd.argument == "ert";
463 case InsetBase::FLOAT_CODE:
464 enable = cmd.argument == "float";
466 case InsetBase::WRAP_CODE:
467 enable = cmd.argument == "wrap";
469 case InsetBase::NOTE_CODE:
470 enable = cmd.argument == "note";
472 case InsetBase::BRANCH_CODE:
473 enable = cmd.argument == "branch";
475 case InsetBase::BOX_CODE:
476 enable = cmd.argument == "box";
484 case LFUN_INSET_APPLY: {
485 string const name = cmd.getArg(0);
486 InsetBase * inset = owner->getDialogs().getOpenInset(name);
488 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
490 bool const success = inset->getStatus(cur, fr, fs);
491 // Every inset is supposed to handle this
492 BOOST_ASSERT(success);
495 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
496 flag |= getStatus(fr);
498 enable = flag.enabled();
502 case LFUN_DIALOG_SHOW: {
503 string const name = cmd.getArg(0);
505 enable = name == "aboutlyx"
509 || name == "texinfo";
510 else if (name == "print")
511 enable = Exporter::IsExportable(*buf, "dvi")
512 && lyxrc.print_command != "none";
513 else if (name == "character" || name == "mathpanel")
514 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
515 else if (name == "latexlog")
516 enable = IsFileReadable(buf->getLogName().second);
517 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
518 else if (name == "spellchecker")
521 else if (name == "vclog")
522 enable = buf->lyxvc().inUse();
526 case LFUN_DIALOG_SHOW_NEW_INSET:
527 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
530 case LFUN_DIALOG_UPDATE: {
531 string const name = cmd.getArg(0);
533 enable = name == "prefs";
537 case LFUN_INSERT_CITATION: {
538 FuncRequest fr(LFUN_INSET_INSERT, "citation");
539 enable = getStatus(fr).enabled();
543 case LFUN_MENUWRITE: {
544 enable = view()->buffer()->isUnnamed()
545 || !view()->buffer()->isClean();
549 // this one is difficult to get right. As a half-baked
550 // solution, we consider only the first action of the sequence
551 case LFUN_SEQUENCE: {
552 // argument contains ';'-terminated commands
553 string const firstcmd = token(cmd.argument, ';', 0);
554 FuncRequest func(lyxaction.lookupFunc(firstcmd));
555 func.origin = cmd.origin;
556 flag = getStatus(func);
560 case LFUN_MENUNEWTMPLT:
561 case LFUN_WORDFINDFORWARD:
562 case LFUN_WORDFINDBACKWARD:
564 case LFUN_EXEC_COMMAND:
567 case LFUN_CLOSEBUFFER:
575 case LFUN_RECONFIGURE:
579 case LFUN_DROP_LAYOUTS_CHOICE:
580 case LFUN_MENU_OPEN_BY_NAME:
583 case LFUN_GOTOFILEROW:
584 case LFUN_DIALOG_SHOW_NEXT_INSET:
585 case LFUN_DIALOG_HIDE:
586 case LFUN_DIALOG_DISCONNECT_INSET:
588 case LFUN_TOGGLECURSORFOLLOW:
592 case LFUN_KMAP_TOGGLE:
594 case LFUN_EXPORT_CUSTOM:
596 case LFUN_SAVEPREFERENCES:
597 case LFUN_SCREEN_FONT_UPDATE:
600 case LFUN_EXTERNAL_EDIT:
601 case LFUN_GRAPHICS_EDIT:
602 case LFUN_ALL_INSETS_TOGGLE:
603 case LFUN_LANGUAGE_BUFFER:
604 case LFUN_TEXTCLASS_APPLY:
605 case LFUN_TEXTCLASS_LOAD:
606 case LFUN_SAVE_AS_DEFAULT:
607 case LFUN_BUFFERPARAMS_APPLY:
608 case LFUN_LYXRC_APPLY:
609 case LFUN_NEXTBUFFER:
610 case LFUN_PREVIOUSBUFFER:
611 // these are handled in our dispatch()
616 if (!::getStatus(cur, cmd, flag))
617 flag = view()->getStatus(cmd);
623 // Can we use a readonly buffer?
624 if (buf && buf->isReadonly()
625 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
626 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
627 flag.message(N_("Document is read-only"));
631 // Are we in a DELETED change-tracking region?
632 if (buf && buf->params().tracking_changes
633 && lookupChange(cur, true) == Change::DELETED
634 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
635 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
636 flag.message(N_("This portion of the document is deleted."));
640 // the default error message if we disable the command
641 if (!flag.enabled() && flag.message().empty())
642 flag.message(N_("Command disabled"));
650 bool ensureBufferClean(BufferView * bv)
652 Buffer & buf = *bv->buffer();
656 string const file = MakeDisplayPath(buf.fileName(), 30);
657 string text = bformat(_("The document %1$s has unsaved "
658 "changes.\n\nDo you want to save "
659 "the document?"), file);
660 int const ret = Alert::prompt(_("Save changed document?"),
661 text, 0, 1, _("&Save"),
665 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
667 return buf.isClean();
671 void showPrintError(string const & name)
673 string str = bformat(_("Could not print the document %1$s.\n"
674 "Check that your printer is set up correctly."),
675 MakeDisplayPath(name, 50));
676 Alert::error(_("Print document failed"), str);
680 void loadTextclass(string const & name)
682 std::pair<bool, lyx::textclass_type> const tc_pair =
683 textclasslist.NumberOfClass(name);
685 if (!tc_pair.first) {
686 lyxerr << "Document class \"" << name
687 << "\" does not exist."
692 lyx::textclass_type const tc = tc_pair.second;
694 if (!textclasslist[tc].load()) {
695 string s = bformat(_("The document could not be converted\n"
696 "into the document class %1$s."),
697 textclasslist[tc].name());
698 Alert::error(_("Could not change class"), s);
703 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
708 void LyXFunc::dispatch(FuncRequest const & cmd)
710 BOOST_ASSERT(view());
711 string const argument = cmd.argument;
712 kb_action const action = cmd.action;
714 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
715 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
717 // we have not done anything wrong yet.
719 dispatch_buffer.erase();
723 FuncStatus const flag = getStatus(cmd);
724 if (!flag.enabled()) {
725 // We cannot use this function here
726 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
727 << lyxaction.getActionName(action)
728 << " [" << action << "] is disabled at this location"
730 setErrorMessage(flag.message());
733 if (view()->available())
734 view()->hideCursor();
738 case LFUN_WORDFINDFORWARD:
739 case LFUN_WORDFINDBACKWARD: {
740 static string last_search;
741 string searched_string;
743 if (!argument.empty()) {
744 last_search = argument;
745 searched_string = argument;
747 searched_string = last_search;
750 if (searched_string.empty())
753 bool const fw = action == LFUN_WORDFINDFORWARD;
755 lyx::find::find2string(searched_string, true, false, fw);
756 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
761 owner->message(keyseq.printOptions());
764 case LFUN_EXEC_COMMAND:
765 owner->getToolbars().display("minibuffer", true);
766 owner->focus_command_buffer();
771 meta_fake_bit = key_modifier::none;
772 if (view()->available())
773 // cancel any selection
774 dispatch(FuncRequest(LFUN_MARK_OFF));
775 setMessage(N_("Cancel"));
779 meta_fake_bit = key_modifier::alt;
780 setMessage(keyseq.print());
783 case LFUN_READ_ONLY_TOGGLE:
784 if (owner->buffer()->lyxvc().inUse())
785 owner->buffer()->lyxvc().toggleReadOnly();
787 owner->buffer()->setReadonly(
788 !owner->buffer()->isReadonly());
791 // --- Menus -----------------------------------------------
793 menuNew(argument, false);
796 case LFUN_MENUNEWTMPLT:
797 menuNew(argument, true);
800 case LFUN_CLOSEBUFFER:
805 if (!owner->buffer()->isUnnamed()) {
806 string const str = bformat(_("Saving document %1$s..."),
807 MakeDisplayPath(owner->buffer()->fileName()));
809 MenuWrite(owner->buffer());
810 owner->message(str + _(" done."));
812 WriteAs(owner->buffer());
816 WriteAs(owner->buffer(), argument);
819 case LFUN_MENURELOAD: {
820 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
821 string text = bformat(_("Any changes will be lost. Are you sure "
822 "you want to revert to the saved version of the document %1$s?"), file);
823 int const ret = Alert::prompt(_("Revert to saved document?"),
824 text, 0, 1, _("&Revert"), _("&Cancel"));
832 Exporter::Export(owner->buffer(), argument, true);
833 view()->showErrorList(BufferFormat(*owner->buffer()));
837 Exporter::Preview(owner->buffer(), argument);
838 view()->showErrorList(BufferFormat(*owner->buffer()));
842 Exporter::Export(owner->buffer(), "program", true);
843 view()->showErrorList(_("Build"));
847 owner->buffer()->runChktex();
848 view()->showErrorList(_("ChkTeX"));
852 if (argument == "custom")
853 owner->getDialogs().show("sendto");
855 Exporter::Export(owner->buffer(), argument, false);
856 view()->showErrorList(BufferFormat(*owner->buffer()));
860 case LFUN_EXPORT_CUSTOM: {
862 string command = split(argument, format_name, ' ');
863 Format const * format = formats.getFormat(format_name);
865 lyxerr << "Format \"" << format_name
866 << "\" not recognized!"
871 Buffer * buffer = owner->buffer();
873 // The name of the file created by the conversion process
876 // Output to filename
877 if (format->name() == "lyx") {
878 string const latexname =
879 buffer->getLatexName(false);
880 filename = ChangeExtension(latexname,
881 format->extension());
882 filename = AddName(buffer->temppath(), filename);
884 if (!buffer->writeFile(filename))
888 Exporter::Export(buffer, format_name, true,
892 // Substitute $$FName for filename
893 if (!contains(command, "$$FName"))
894 command = "( " + command + " ) < $$FName";
895 command = subst(command, "$$FName", filename);
897 // Execute the command in the background
899 call.startscript(Systemcall::DontWait, command);
906 string command = split(split(argument, target, ' '),
910 || target_name.empty()
911 || command.empty()) {
912 lyxerr << "Unable to parse \""
913 << argument << '"' << std::endl;
916 if (target != "printer" && target != "file") {
917 lyxerr << "Unrecognized target \""
918 << target << '"' << std::endl;
922 Buffer * buffer = owner->buffer();
924 if (!Exporter::Export(buffer, "dvi", true)) {
925 showPrintError(buffer->fileName());
929 // Push directory path.
930 string const path = buffer->temppath();
933 // there are three cases here:
934 // 1. we print to a file
935 // 2. we print directly to a printer
936 // 3. we print using a spool command (print to file first)
939 string const dviname =
940 ChangeExtension(buffer->getLatexName(true),
943 if (target == "printer") {
944 if (!lyxrc.print_spool_command.empty()) {
945 // case 3: print using a spool
946 string const psname =
947 ChangeExtension(dviname,".ps");
948 command += lyxrc.print_to_file
951 + QuoteName(dviname);
954 lyxrc.print_spool_command +' ';
955 if (target_name != "default") {
956 command2 += lyxrc.print_spool_printerprefix
960 command2 += QuoteName(psname);
962 // If successful, then spool command
963 res = one.startscript(
968 res = one.startscript(
969 Systemcall::DontWait,
972 // case 2: print directly to a printer
973 res = one.startscript(
974 Systemcall::DontWait,
975 command + QuoteName(dviname));
979 // case 1: print to a file
980 command += lyxrc.print_to_file
981 + QuoteName(MakeAbsPath(target_name,
984 + QuoteName(dviname);
985 res = one.startscript(Systemcall::DontWait,
990 showPrintError(buffer->fileName());
999 QuitLyX(argument == "force");
1002 case LFUN_TOCVIEW: {
1003 InsetCommandParams p("tableofcontents");
1004 string const data = InsetCommandMailer::params2string("toc", p);
1005 owner->getDialogs().show("toc", data, 0);
1013 case LFUN_RECONFIGURE:
1014 Reconfigure(view());
1017 case LFUN_HELP_OPEN: {
1018 string const arg = argument;
1020 setErrorMessage(N_("Missing argument"));
1023 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1024 if (fname.empty()) {
1025 lyxerr << "LyX: unable to find documentation file `"
1026 << arg << "'. Bad installation?" << endl;
1029 owner->message(bformat(_("Opening help file %1$s..."),
1030 MakeDisplayPath(fname)));
1031 view()->loadLyXFile(fname, false);
1035 // --- version control -------------------------------
1036 case LFUN_VC_REGISTER:
1037 if (!ensureBufferClean(view()))
1039 if (!owner->buffer()->lyxvc().inUse()) {
1040 owner->buffer()->lyxvc().registrer();
1045 case LFUN_VC_CHECKIN:
1046 if (!ensureBufferClean(view()))
1048 if (owner->buffer()->lyxvc().inUse()
1049 && !owner->buffer()->isReadonly()) {
1050 owner->buffer()->lyxvc().checkIn();
1055 case LFUN_VC_CHECKOUT:
1056 if (!ensureBufferClean(view()))
1058 if (owner->buffer()->lyxvc().inUse()
1059 && owner->buffer()->isReadonly()) {
1060 owner->buffer()->lyxvc().checkOut();
1065 case LFUN_VC_REVERT:
1066 owner->buffer()->lyxvc().revert();
1071 owner->buffer()->lyxvc().undoLast();
1075 // --- buffers ----------------------------------------
1076 case LFUN_SWITCHBUFFER:
1077 view()->setBuffer(bufferlist.getBuffer(argument));
1080 case LFUN_NEXTBUFFER:
1081 view()->setBuffer(bufferlist.next(view()->buffer()));
1084 case LFUN_PREVIOUSBUFFER:
1085 view()->setBuffer(bufferlist.previous(view()->buffer()));
1089 NewFile(view(), argument);
1092 case LFUN_FILE_OPEN:
1096 case LFUN_DROP_LAYOUTS_CHOICE:
1097 owner->getToolbars().openLayoutList();
1100 case LFUN_MENU_OPEN_BY_NAME:
1101 owner->getMenubar().openByName(argument);
1104 // --- lyxserver commands ----------------------------
1106 setMessage(owner->buffer()->fileName());
1107 lyxerr[Debug::INFO] << "FNAME["
1108 << owner->buffer()->fileName()
1113 dispatch_buffer = keyseq.print();
1114 lyxserver->notifyClient(dispatch_buffer);
1117 case LFUN_GOTOFILEROW: {
1120 istringstream is(argument);
1121 is >> file_name >> row;
1122 if (prefixIs(file_name, package().temp_dir())) {
1123 // Needed by inverse dvi search. If it is a file
1124 // in tmpdir, call the apropriated function
1125 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1127 // Must replace extension of the file to be .lyx
1128 // and get full path
1129 string const s = ChangeExtension(file_name, ".lyx");
1130 // Either change buffer or load the file
1131 if (bufferlist.exists(s)) {
1132 view()->setBuffer(bufferlist.getBuffer(s));
1134 view()->loadLyXFile(s);
1138 view()->setCursorFromRow(row);
1141 // see BufferView_pimpl::center()
1142 view()->updateScrollbar();
1146 case LFUN_DIALOG_SHOW: {
1147 string const name = cmd.getArg(0);
1148 string data = trim(cmd.argument.substr(name.size()));
1150 if (name == "character") {
1151 data = freefont2string();
1153 owner->getDialogs().show("character", data);
1156 else if (name == "latexlog") {
1157 pair<Buffer::LogType, string> const logfile =
1158 owner->buffer()->getLogName();
1159 switch (logfile.first) {
1160 case Buffer::latexlog:
1163 case Buffer::buildlog:
1167 data += logfile.second;
1168 owner->getDialogs().show("log", data);
1170 else if (name == "vclog") {
1171 string const data = "vc " +
1172 owner->buffer()->lyxvc().getLogFile();
1173 owner->getDialogs().show("log", data);
1176 owner->getDialogs().show(name, data);
1180 case LFUN_DIALOG_SHOW_NEW_INSET: {
1181 string const name = cmd.getArg(0);
1182 string data = trim(cmd.argument.substr(name.size()));
1183 if (name == "bibitem" ||
1190 InsetCommandParams p(name);
1191 data = InsetCommandMailer::params2string(name, p);
1192 } else if (name == "include") {
1193 InsetCommandParams p(data);
1194 data = InsetIncludeMailer::params2string(p);
1195 } else if (name == "box") {
1196 // \c data == "Boxed" || "Frameless" etc
1197 InsetBoxParams p(data);
1198 data = InsetBoxMailer::params2string(p);
1199 } else if (name == "branch") {
1200 InsetBranchParams p;
1201 data = InsetBranchMailer::params2string(p);
1202 } else if (name == "citation") {
1203 InsetCommandParams p("cite");
1204 data = InsetCommandMailer::params2string(name, p);
1205 } else if (name == "ert") {
1206 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1207 } else if (name == "external") {
1208 InsetExternalParams p;
1209 Buffer const & buffer = *owner->buffer();
1210 data = InsetExternalMailer::params2string(p, buffer);
1211 } else if (name == "float") {
1213 data = InsetFloatMailer::params2string(p);
1214 } else if (name == "graphics") {
1215 InsetGraphicsParams p;
1216 Buffer const & buffer = *owner->buffer();
1217 data = InsetGraphicsMailer::params2string(p, buffer);
1218 } else if (name == "note") {
1220 data = InsetNoteMailer::params2string(p);
1221 } else if (name == "vspace") {
1223 data = InsetVSpaceMailer::params2string(space);
1224 } else if (name == "wrap") {
1226 data = InsetWrapMailer::params2string(p);
1228 owner->getDialogs().show(name, data, 0);
1232 case LFUN_DIALOG_SHOW_NEXT_INSET:
1235 case LFUN_DIALOG_UPDATE: {
1236 string const & name = argument;
1237 // Can only update a dialog connected to an existing inset
1238 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1240 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1241 inset->dispatch(view()->cursor(), fr);
1242 } else if (name == "paragraph") {
1243 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1244 } else if (name == "prefs") {
1245 owner->getDialogs().update(name, string());
1250 case LFUN_DIALOG_HIDE:
1251 Dialogs::hide(argument, 0);
1254 case LFUN_DIALOG_DISCONNECT_INSET:
1255 owner->getDialogs().disconnect(argument);
1259 case LFUN_INSERT_CITATION: {
1260 if (!argument.empty()) {
1261 // we can have one optional argument, delimited by '|'
1262 // citation-insert <key>|<text_before>
1263 // this should be enhanced to also support text_after
1264 // and citation style
1265 string arg = argument;
1267 if (contains(argument, "|")) {
1268 arg = token(argument, '|', 0);
1269 opt1 = '[' + token(argument, '|', 1) + ']';
1271 std::ostringstream os;
1272 os << "citation LatexCommand\n"
1273 << "\\cite" << opt1 << "{" << arg << "}\n"
1275 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1278 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1282 case LFUN_CHILDOPEN: {
1283 string const filename =
1284 MakeAbsPath(argument, owner->buffer()->filePath());
1285 setMessage(N_("Opening child document ") +
1286 MakeDisplayPath(filename) + "...");
1287 view()->savePosition(0);
1288 string const parentfilename = owner->buffer()->fileName();
1289 if (bufferlist.exists(filename))
1290 view()->setBuffer(bufferlist.getBuffer(filename));
1292 view()->loadLyXFile(filename);
1293 // Set the parent name of the child document.
1294 // This makes insertion of citations and references in the child work,
1295 // when the target is in the parent or another child document.
1296 owner->buffer()->setParentName(parentfilename);
1300 case LFUN_TOGGLECURSORFOLLOW:
1301 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1305 owner->getIntl().KeyMapOn(false);
1308 case LFUN_KMAP_PRIM:
1309 owner->getIntl().KeyMapPrim();
1313 owner->getIntl().KeyMapSec();
1316 case LFUN_KMAP_TOGGLE:
1317 owner->getIntl().ToggleKeyMap();
1323 string rest = split(argument, countstr, ' ');
1324 istringstream is(countstr);
1327 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1328 for (int i = 0; i < count; ++i)
1329 dispatch(lyxaction.lookupFunc(rest));
1333 case LFUN_SEQUENCE: {
1334 // argument contains ';'-terminated commands
1335 string arg = argument;
1336 while (!arg.empty()) {
1338 arg = split(arg, first, ';');
1339 FuncRequest func(lyxaction.lookupFunc(first));
1340 func.origin = cmd.origin;
1346 case LFUN_SAVEPREFERENCES: {
1347 Path p(package().user_support());
1348 lyxrc.write("preferences", false);
1352 case LFUN_SCREEN_FONT_UPDATE:
1353 // handle the screen font changes.
1354 lyxrc.set_font_norm_type();
1355 lyx_gui::update_fonts();
1356 // All visible buffers will need resize
1360 case LFUN_SET_COLOR: {
1362 string const x11_name = split(argument, lyx_name, ' ');
1363 if (lyx_name.empty() || x11_name.empty()) {
1364 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1369 bool const graphicsbg_changed =
1370 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1371 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1373 if (!lcolor.setColor(lyx_name, x11_name)) {
1375 bformat(_("Set-color \"%1$s\" failed "
1376 "- color is undefined or "
1377 "may not be redefined"), lyx_name));
1381 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1383 if (graphicsbg_changed) {
1384 #ifdef WITH_WARNINGS
1385 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1388 lyx::graphics::GCache::get().changeDisplay(true);
1395 owner->message(argument);
1398 case LFUN_TOOLTIPS_TOGGLE:
1399 owner->getDialogs().toggleTooltips();
1402 case LFUN_EXTERNAL_EDIT: {
1403 FuncRequest fr(action, argument);
1404 InsetExternal().dispatch(view()->cursor(), fr);
1408 case LFUN_GRAPHICS_EDIT: {
1409 FuncRequest fr(action, argument);
1410 InsetGraphics().dispatch(view()->cursor(), fr);
1414 case LFUN_INSET_APPLY: {
1415 string const name = cmd.getArg(0);
1416 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1418 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1419 inset->dispatch(view()->cursor(), fr);
1421 FuncRequest fr(LFUN_INSET_INSERT, argument);
1424 // ideally, the update flag should be set by the insets,
1425 // but this is not possible currently
1430 case LFUN_ALL_INSETS_TOGGLE: {
1432 string const name = split(argument, action, ' ');
1433 InsetBase::Code const inset_code =
1434 InsetBase::translate(name);
1436 LCursor & cur = view()->cursor();
1437 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1439 InsetBase & inset = owner->buffer()->inset();
1440 InsetIterator it = inset_iterator_begin(inset);
1441 InsetIterator const end = inset_iterator_end(inset);
1442 for (; it != end; ++it) {
1443 if (inset_code == InsetBase::NO_CODE
1444 || inset_code == it->lyxCode()) {
1445 LCursor tmpcur = cur;
1446 tmpcur.pushLeft(*it);
1447 it->dispatch(tmpcur, fr);
1454 case LFUN_LANGUAGE_BUFFER: {
1455 Buffer & buffer = *owner->buffer();
1456 Language const * oldL = buffer.params().language;
1457 Language const * newL = languages.getLanguage(argument);
1458 if (!newL || oldL == newL)
1461 if (oldL->RightToLeft() == newL->RightToLeft()
1462 && !buffer.isMultiLingual())
1463 buffer.changeLanguage(oldL, newL);
1465 buffer.updateDocLang(newL);
1469 case LFUN_SAVE_AS_DEFAULT: {
1470 string const fname =
1471 AddName(AddPath(package().user_support(), "templates/"),
1473 Buffer defaults(fname);
1475 istringstream ss(argument);
1478 int const unknown_tokens = defaults.readHeader(lex);
1480 if (unknown_tokens != 0) {
1481 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1482 << unknown_tokens << " unknown token"
1483 << (unknown_tokens == 1 ? "" : "s")
1487 if (defaults.writeFile(defaults.fileName()))
1488 setMessage(_("Document defaults saved in ")
1489 + MakeDisplayPath(fname));
1491 setErrorMessage(_("Unable to save document defaults"));
1495 case LFUN_BUFFERPARAMS_APPLY: {
1496 biblio::CiteEngine const engine =
1497 owner->buffer()->params().cite_engine;
1499 istringstream ss(argument);
1502 int const unknown_tokens =
1503 owner->buffer()->readHeader(lex);
1505 if (unknown_tokens != 0) {
1506 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1507 << unknown_tokens << " unknown token"
1508 << (unknown_tokens == 1 ? "" : "s")
1511 if (engine == owner->buffer()->params().cite_engine)
1514 LCursor & cur = view()->cursor();
1515 FuncRequest fr(LFUN_INSET_REFRESH);
1517 InsetBase & inset = owner->buffer()->inset();
1518 InsetIterator it = inset_iterator_begin(inset);
1519 InsetIterator const end = inset_iterator_end(inset);
1520 for (; it != end; ++it)
1521 if (it->lyxCode() == InsetBase::CITE_CODE)
1522 it->dispatch(cur, fr);
1526 case LFUN_TEXTCLASS_APPLY: {
1527 Buffer * buffer = owner->buffer();
1529 lyx::textclass_type const old_class =
1530 buffer->params().textclass;
1532 loadTextclass(argument);
1534 std::pair<bool, lyx::textclass_type> const tc_pair =
1535 textclasslist.NumberOfClass(argument);
1540 lyx::textclass_type const new_class = tc_pair.second;
1541 if (old_class == new_class)
1545 owner->message(_("Converting document to new document class..."));
1546 recordUndoFullDocument(view());
1547 buffer->params().textclass = new_class;
1548 StableDocIterator backcur(view()->cursor());
1550 lyx::cap::SwitchBetweenClasses(
1551 old_class, new_class,
1552 buffer->paragraphs(), el);
1554 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1555 bufferErrors(*buffer, el);
1556 view()->showErrorList(_("Class switch"));
1557 updateCounters(*buffer);
1562 case LFUN_TEXTCLASS_LOAD:
1563 loadTextclass(argument);
1566 case LFUN_LYXRC_APPLY: {
1567 LyXRC const lyxrc_orig = lyxrc;
1569 istringstream ss(argument);
1570 bool const success = lyxrc.read(ss) == 0;
1573 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1574 << "Unable to read lyxrc data"
1579 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1584 view()->cursor().dispatch(cmd);
1585 update |= view()->cursor().result().update();
1586 if (!view()->cursor().result().dispatched())
1587 update |= view()->dispatch(cmd);
1592 if (view()->available()) {
1593 // Redraw screen unless explicitly told otherwise.
1594 // This also initializes the position cache for all insets
1595 // in (at least partially) visible top-level paragraphs.
1597 view()->update(Update::FitCursor | Update::Force);
1599 view()->update(Update::FitCursor);
1601 // if we executed a mutating lfun, mark the buffer as dirty
1603 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1604 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1605 view()->buffer()->markDirty();
1608 if (view()->cursor().inTexted()) {
1609 view()->owner()->updateLayoutChoice();
1612 sendDispatchMessage(_(getMessage()), cmd);
1616 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1618 /* When an action did not originate from the UI/kbd, it makes
1619 * sense to avoid updating the GUI. It turns out that this
1620 * fixes bug 1941, for reasons that are described here:
1621 * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1623 if (cmd.origin != FuncRequest::INTERNAL) {
1624 owner->updateMenubar();
1625 owner->updateToolbars();
1628 const bool verbose = (cmd.origin == FuncRequest::UI
1629 || cmd.origin == FuncRequest::COMMANDBUFFER);
1631 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1632 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1634 owner->message(msg);
1638 string dispatch_msg = msg;
1639 if (!dispatch_msg.empty())
1640 dispatch_msg += ' ';
1642 string comname = lyxaction.getActionName(cmd.action);
1644 bool argsadded = false;
1646 if (!cmd.argument.empty()) {
1647 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1648 comname += ' ' + cmd.argument;
1653 string const shortcuts = toplevel_keymap->printbindings(cmd);
1655 if (!shortcuts.empty())
1656 comname += ": " + shortcuts;
1657 else if (!argsadded && !cmd.argument.empty())
1658 comname += ' ' + cmd.argument;
1660 if (!comname.empty()) {
1661 comname = rtrim(comname);
1662 dispatch_msg += '(' + rtrim(comname) + ')';
1665 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1666 if (!dispatch_msg.empty())
1667 owner->message(dispatch_msg);
1671 void LyXFunc::setupLocalKeymap()
1673 keyseq.stdmap = toplevel_keymap.get();
1674 keyseq.curmap = toplevel_keymap.get();
1675 cancel_meta_seq.stdmap = toplevel_keymap.get();
1676 cancel_meta_seq.curmap = toplevel_keymap.get();
1680 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1682 string initpath = lyxrc.document_path;
1683 string filename(name);
1685 if (view()->available()) {
1686 string const trypath = owner->buffer()->filePath();
1687 // If directory is writeable, use this as default.
1688 if (IsDirWriteable(trypath))
1692 static int newfile_number;
1694 if (filename.empty()) {
1695 filename = AddName(lyxrc.document_path,
1696 "newfile" + convert<string>(++newfile_number) + ".lyx");
1697 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1699 filename = AddName(lyxrc.document_path,
1700 "newfile" + convert<string>(newfile_number) +
1705 // The template stuff
1708 FileDialog fileDlg(_("Select template file"),
1709 LFUN_SELECT_FILE_SYNC,
1710 make_pair(string(_("Documents|#o#O")),
1711 string(lyxrc.document_path)),
1712 make_pair(string(_("Templates|#T#t")),
1713 string(lyxrc.template_path)));
1715 FileDialog::Result result =
1716 fileDlg.open(lyxrc.template_path,
1717 FileFilterList(_("LyX Documents (*.lyx)")),
1720 if (result.first == FileDialog::Later)
1722 if (result.second.empty())
1724 templname = result.second;
1727 view()->newFile(filename, templname, !name.empty());
1731 void LyXFunc::open(string const & fname)
1733 string initpath = lyxrc.document_path;
1735 if (view()->available()) {
1736 string const trypath = owner->buffer()->filePath();
1737 // If directory is writeable, use this as default.
1738 if (IsDirWriteable(trypath))
1744 if (fname.empty()) {
1745 FileDialog fileDlg(_("Select document to open"),
1747 make_pair(string(_("Documents|#o#O")),
1748 string(lyxrc.document_path)),
1749 make_pair(string(_("Examples|#E#e")),
1750 string(AddPath(package().system_support(), "examples"))));
1752 FileDialog::Result result =
1753 fileDlg.open(initpath,
1754 FileFilterList(_("LyX Documents (*.lyx)")),
1757 if (result.first == FileDialog::Later)
1760 filename = result.second;
1762 // check selected filename
1763 if (filename.empty()) {
1764 owner->message(_("Canceled."));
1770 // get absolute path of file and add ".lyx" to the filename if
1772 string const fullpath = FileSearch(string(), filename, "lyx");
1773 if (!fullpath.empty()) {
1774 filename = fullpath;
1777 string const disp_fn(MakeDisplayPath(filename));
1779 // if the file doesn't exist, let the user create one
1780 if (!fs::exists(filename)) {
1781 // the user specifically chose this name. Believe them.
1782 view()->newFile(filename, "", true);
1786 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1789 if (view()->loadLyXFile(filename)) {
1790 str2 = bformat(_("Document %1$s opened."), disp_fn);
1792 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1794 owner->message(str2);
1798 void LyXFunc::doImport(string const & argument)
1801 string filename = split(argument, format, ' ');
1803 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1804 << " file: " << filename << endl;
1806 // need user interaction
1807 if (filename.empty()) {
1808 string initpath = lyxrc.document_path;
1810 if (view()->available()) {
1811 string const trypath = owner->buffer()->filePath();
1812 // If directory is writeable, use this as default.
1813 if (IsDirWriteable(trypath))
1817 string const text = bformat(_("Select %1$s file to import"),
1818 formats.prettyName(format));
1820 FileDialog fileDlg(text,
1822 make_pair(string(_("Documents|#o#O")),
1823 string(lyxrc.document_path)),
1824 make_pair(string(_("Examples|#E#e")),
1825 string(AddPath(package().system_support(), "examples"))));
1827 string const filter = formats.prettyName(format)
1828 + " (*." + formats.extension(format) + ')';
1830 FileDialog::Result result =
1831 fileDlg.open(initpath,
1832 FileFilterList(filter),
1835 if (result.first == FileDialog::Later)
1838 filename = result.second;
1840 // check selected filename
1841 if (filename.empty())
1842 owner->message(_("Canceled."));
1845 if (filename.empty())
1848 // get absolute path of file
1849 filename = MakeAbsPath(filename);
1851 string const lyxfile = ChangeExtension(filename, ".lyx");
1853 // Check if the document already is open
1854 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1855 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1856 owner->message(_("Canceled."));
1861 // if the file exists already, and we didn't do
1862 // -i lyx thefile.lyx, warn
1863 if (fs::exists(lyxfile) && filename != lyxfile) {
1864 string const file = MakeDisplayPath(lyxfile, 30);
1866 string text = bformat(_("The document %1$s already exists.\n\n"
1867 "Do you want to over-write that document?"), file);
1868 int const ret = Alert::prompt(_("Over-write document?"),
1869 text, 0, 1, _("&Over-write"), _("&Cancel"));
1872 owner->message(_("Canceled."));
1877 Importer::Import(owner, filename, format);
1881 void LyXFunc::closeBuffer()
1883 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1884 if (bufferlist.empty()) {
1885 // need this otherwise SEGV may occur while
1886 // trying to set variables that don't exist
1887 // since there's no current buffer
1888 owner->getDialogs().hideBufferDependent();
1890 view()->setBuffer(bufferlist.first());
1896 // Each "owner" should have it's own message method. lyxview and
1897 // the minibuffer would use the minibuffer, but lyxserver would
1898 // send an ERROR signal to its client. Alejandro 970603
1899 // This function is bit problematic when it comes to NLS, to make the
1900 // lyx servers client be language indepenent we must not translate
1901 // strings sent to this func.
1902 void LyXFunc::setErrorMessage(string const & m) const
1904 dispatch_buffer = m;
1909 void LyXFunc::setMessage(string const & m) const
1911 dispatch_buffer = m;
1915 string const LyXFunc::viewStatusMessage()
1917 // When meta-fake key is pressed, show the key sequence so far + "M-".
1919 return keyseq.print() + "M-";
1921 // Else, when a non-complete key sequence is pressed,
1922 // show the available options.
1923 if (keyseq.length() > 0 && !keyseq.deleted())
1924 return keyseq.printOptions();
1926 if (!view()->available())
1927 return _("Welcome to LyX!");
1929 return view()->cursor().currentState();
1933 BufferView * LyXFunc::view() const
1935 BOOST_ASSERT(owner);
1936 return owner->view().get();
1940 bool LyXFunc::wasMetaKey() const
1942 return (meta_fake_bit != key_modifier::none);
1948 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1950 // Why the switch you might ask. It is a trick to ensure that all
1951 // the elements in the LyXRCTags enum is handled. As you can see
1952 // there are no breaks at all. So it is just a huge fall-through.
1953 // The nice thing is that we will get a warning from the compiler
1954 // if we forget an element.
1955 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1957 case LyXRC::RC_ACCEPT_COMPOUND:
1958 case LyXRC::RC_ALT_LANG:
1959 case LyXRC::RC_ASCIIROFF_COMMAND:
1960 case LyXRC::RC_ASCII_LINELEN:
1961 case LyXRC::RC_AUTOREGIONDELETE:
1962 case LyXRC::RC_AUTORESET_OPTIONS:
1963 case LyXRC::RC_AUTOSAVE:
1964 case LyXRC::RC_AUTO_NUMBER:
1965 case LyXRC::RC_BACKUPDIR_PATH:
1966 case LyXRC::RC_BIBTEX_COMMAND:
1967 case LyXRC::RC_BINDFILE:
1968 case LyXRC::RC_CHECKLASTFILES:
1969 case LyXRC::RC_CHKTEX_COMMAND:
1970 case LyXRC::RC_CONVERTER:
1971 case LyXRC::RC_COPIER:
1972 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1973 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1974 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1975 case LyXRC::RC_CYGWIN_PATH_FIX:
1976 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1977 namespace os = lyx::support::os;
1978 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1980 case LyXRC::RC_DATE_INSERT_FORMAT:
1981 case LyXRC::RC_DEFAULT_LANGUAGE:
1982 case LyXRC::RC_DEFAULT_PAPERSIZE:
1983 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1984 case LyXRC::RC_DISPLAY_GRAPHICS:
1985 case LyXRC::RC_DOCUMENTPATH:
1986 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1987 if (fs::exists(lyxrc_new.document_path) &&
1988 fs::is_directory(lyxrc_new.document_path)) {
1989 using lyx::support::package;
1990 package().document_dir() = lyxrc.document_path;
1993 case LyXRC::RC_ESC_CHARS:
1994 case LyXRC::RC_FONT_ENCODING:
1995 case LyXRC::RC_FORMAT:
1996 case LyXRC::RC_INDEX_COMMAND:
1997 case LyXRC::RC_INPUT:
1998 case LyXRC::RC_KBMAP:
1999 case LyXRC::RC_KBMAP_PRIMARY:
2000 case LyXRC::RC_KBMAP_SECONDARY:
2001 case LyXRC::RC_LABEL_INIT_LENGTH:
2002 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2003 case LyXRC::RC_LANGUAGE_AUTO_END:
2004 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2005 case LyXRC::RC_LANGUAGE_COMMAND_END:
2006 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2007 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2008 case LyXRC::RC_LANGUAGE_PACKAGE:
2009 case LyXRC::RC_LANGUAGE_USE_BABEL:
2010 case LyXRC::RC_LASTFILES:
2011 case LyXRC::RC_MAKE_BACKUP:
2012 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2013 case LyXRC::RC_NUMLASTFILES:
2014 case LyXRC::RC_PATH_PREFIX:
2015 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2016 using lyx::support::prependEnvPath;
2017 prependEnvPath("PATH", lyxrc.path_prefix);
2019 case LyXRC::RC_PERS_DICT:
2020 case LyXRC::RC_POPUP_BOLD_FONT:
2021 case LyXRC::RC_POPUP_FONT_ENCODING:
2022 case LyXRC::RC_POPUP_NORMAL_FONT:
2023 case LyXRC::RC_PREVIEW:
2024 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2025 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2026 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2027 case LyXRC::RC_PRINTCOPIESFLAG:
2028 case LyXRC::RC_PRINTER:
2029 case LyXRC::RC_PRINTEVENPAGEFLAG:
2030 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2031 case LyXRC::RC_PRINTFILEEXTENSION:
2032 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2033 case LyXRC::RC_PRINTODDPAGEFLAG:
2034 case LyXRC::RC_PRINTPAGERANGEFLAG:
2035 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2036 case LyXRC::RC_PRINTPAPERFLAG:
2037 case LyXRC::RC_PRINTREVERSEFLAG:
2038 case LyXRC::RC_PRINTSPOOL_COMMAND:
2039 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2040 case LyXRC::RC_PRINTTOFILE:
2041 case LyXRC::RC_PRINTTOPRINTER:
2042 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2043 case LyXRC::RC_PRINT_COMMAND:
2044 case LyXRC::RC_RTL_SUPPORT:
2045 case LyXRC::RC_SCREEN_DPI:
2046 case LyXRC::RC_SCREEN_FONT_ENCODING:
2047 case LyXRC::RC_SCREEN_FONT_ROMAN:
2048 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2049 case LyXRC::RC_SCREEN_FONT_SANS:
2050 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2051 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2052 case LyXRC::RC_SCREEN_FONT_SIZES:
2053 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2054 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2055 case LyXRC::RC_SCREEN_ZOOM:
2056 case LyXRC::RC_SERVERPIPE:
2057 case LyXRC::RC_SET_COLOR:
2058 case LyXRC::RC_SHOW_BANNER:
2059 case LyXRC::RC_SPELL_COMMAND:
2060 case LyXRC::RC_TEMPDIRPATH:
2061 case LyXRC::RC_TEMPLATEPATH:
2062 case LyXRC::RC_TEX_ALLOWS_SPACES:
2063 case LyXRC::RC_UIFILE:
2064 case LyXRC::RC_USER_EMAIL:
2065 case LyXRC::RC_USER_NAME:
2066 case LyXRC::RC_USETEMPDIR:
2067 case LyXRC::RC_USE_ALT_LANG:
2068 case LyXRC::RC_USE_ESC_CHARS:
2069 case LyXRC::RC_USE_INP_ENC:
2070 case LyXRC::RC_USE_PERS_DICT:
2071 case LyXRC::RC_USE_SPELL_LIB:
2072 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2073 case LyXRC::RC_VIEWER:
2074 case LyXRC::RC_WHEEL_JUMP:
2075 case LyXRC::RC_LAST: