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"
49 #include "LyXAction.h"
54 #include "lyxserver.h"
55 #include "lyxtextclasslist.h"
57 #include "paragraph.h"
58 #include "pariterator.h"
59 #include "ParagraphParameters.h"
62 #include "insets/insetbox.h"
63 #include "insets/insetbranch.h"
64 #include "insets/insetcommand.h"
65 #include "insets/insetert.h"
66 #include "insets/insetexternal.h"
67 #include "insets/insetfloat.h"
68 #include "insets/insetgraphics.h"
69 #include "insets/insetinclude.h"
70 #include "insets/insetnote.h"
71 #include "insets/insettabular.h"
72 #include "insets/insetvspace.h"
73 #include "insets/insetwrap.h"
75 #include "frontends/Alert.h"
76 #include "frontends/Dialogs.h"
77 #include "frontends/FileDialog.h"
78 #include "frontends/lyx_gui.h"
79 #include "frontends/LyXKeySym.h"
80 #include "frontends/LyXView.h"
81 #include "frontends/Menubar.h"
82 #include "frontends/Toolbars.h"
84 #include "support/environment.h"
85 #include "support/filefilterlist.h"
86 #include "support/filetools.h"
87 #include "support/forkedcontr.h"
88 #include "support/fs_extras.h"
89 #include "support/lstrings.h"
90 #include "support/path.h"
91 #include "support/package.h"
92 #include "support/systemcall.h"
93 #include "support/convert.h"
94 #include "support/os.h"
96 #include <boost/current_function.hpp>
97 #include <boost/filesystem/operations.hpp>
101 using bv_funcs::freefont2string;
103 using lyx::support::absolutePath;
104 using lyx::support::addName;
105 using lyx::support::addPath;
106 using lyx::support::bformat;
107 using lyx::support::changeExtension;
108 using lyx::support::contains;
109 using lyx::support::FileFilterList;
110 using lyx::support::fileSearch;
111 using lyx::support::ForkedcallsController;
112 using lyx::support::i18nLibFileSearch;
113 using lyx::support::isDirWriteable;
114 using lyx::support::isFileReadable;
115 using lyx::support::isStrInt;
116 using lyx::support::makeAbsPath;
117 using lyx::support::makeDisplayPath;
118 using lyx::support::package;
119 using lyx::support::Path;
120 using lyx::support::quoteName;
121 using lyx::support::rtrim;
122 using lyx::support::split;
123 using lyx::support::subst;
124 using lyx::support::Systemcall;
125 using lyx::support::token;
126 using lyx::support::trim;
127 using lyx::support::prefixIs;
130 using std::make_pair;
133 using std::istringstream;
134 using std::ostringstream;
136 namespace biblio = lyx::biblio;
137 namespace fs = boost::filesystem;
140 extern BufferList bufferlist;
141 extern LyXServer * lyxserver;
143 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
146 extern tex_accent_struct get_accent(kb_action action);
151 bool getStatus(LCursor cursor,
152 FuncRequest const & cmd, FuncStatus & status)
154 // Try to fix cursor in case it is broken.
155 cursor.fixIfBroken();
157 // This is, of course, a mess. Better create a new doc iterator and use
158 // this in Inset::getStatus. This might require an additional
159 // BufferView * arg, though (which should be avoided)
160 //LCursor safe = *this;
162 for ( ; cursor.depth(); cursor.pop()) {
163 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
164 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
165 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
166 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
168 // The inset's getStatus() will return 'true' if it made
169 // a definitive decision on whether it want to handle the
170 // request or not. The result of this decision is put into
171 // the 'status' parameter.
172 if (cursor.inset().getStatus(cursor, cmd, status)) {
181 /** Return the change status at cursor position, taking in account the
182 * status at each level of the document iterator (a table in a deleted
183 * footnote is deleted).
184 * When \param outer is true, the top slice is not looked at.
186 Change::Type lookupChange(DocIterator const & dit, bool outer = false)
188 size_t const depth = dit.depth() - (outer ? 1 : 0);
190 for (size_t i = 0 ; i < depth ; ++i) {
191 CursorSlice const & slice = dit[i];
192 if (!slice.inset().inMathed()
193 && slice.pos() < slice.paragraph().size()) {
194 Change::Type const ch = slice.paragraph().lookupChange(slice.pos());
195 if (ch != Change::UNCHANGED)
199 return Change::UNCHANGED;
204 LyXFunc::LyXFunc(LyXView * lv)
207 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
208 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
209 meta_fake_bit(key_modifier::none)
214 void LyXFunc::handleKeyFunc(kb_action action)
216 char c = encoded_last_key;
218 if (keyseq.length()) {
222 owner->getIntl().getTransManager()
223 .deadkey(c, get_accent(action).accent, view()->getLyXText());
224 // Need to clear, in case the minibuffer calls these
227 // copied verbatim from do_accent_char
228 view()->cursor().resetAnchor();
233 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
235 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
237 // Do nothing if we have nothing (JMarc)
238 if (!keysym->isOK()) {
239 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
244 if (keysym->isModifier()) {
245 lyxerr[Debug::KEY] << "isModifier true" << endl;
249 Encoding const * encoding = view()->cursor().getEncoding();
251 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->name() : "");
253 // Do a one-deep top-level lookup for
254 // cancel and meta-fake keys. RVDK_PATCH_5
255 cancel_meta_seq.reset();
257 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
258 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
259 << " action first set to [" << func.action << ']'
262 // When not cancel or meta-fake, do the normal lookup.
263 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
264 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
265 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
266 // remove Caps Lock and Mod2 as a modifiers
267 func = keyseq.addkey(keysym, (state | meta_fake_bit));
268 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
269 << "action now set to ["
270 << func.action << ']' << endl;
273 // Dont remove this unless you know what you are doing.
274 meta_fake_bit = key_modifier::none;
276 // Can this happen now ?
277 if (func.action == LFUN_NOACTION) {
278 func = FuncRequest(LFUN_PREFIX);
281 if (lyxerr.debugging(Debug::KEY)) {
282 lyxerr << BOOST_CURRENT_FUNCTION
284 << func.action << "]["
285 << keyseq.print() << ']'
289 // already here we know if it any point in going further
290 // why not return already here if action == -1 and
291 // num_bytes == 0? (Lgb)
293 if (keyseq.length() > 1) {
294 owner->message(keyseq.print());
298 // Maybe user can only reach the key via holding down shift.
299 // Let's see. But only if shift is the only modifier
300 if (func.action == LFUN_UNKNOWN_ACTION &&
301 state == key_modifier::shift) {
302 lyxerr[Debug::KEY] << "Trying without shift" << endl;
303 func = keyseq.addkey(keysym, key_modifier::none);
304 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
307 if (func.action == LFUN_UNKNOWN_ACTION) {
308 // Hmm, we didn't match any of the keysequences. See
309 // if it's normal insertable text not already covered
311 if (keysym->isText() && keyseq.length() == 1) {
312 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
313 func = FuncRequest(LFUN_SELFINSERT,
314 FuncRequest::KEYBOARD);
316 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
317 owner->message(_("Unknown function."));
322 if (func.action == LFUN_SELFINSERT) {
323 if (encoded_last_key != 0) {
324 string const arg(1, encoded_last_key);
325 dispatch(FuncRequest(LFUN_SELFINSERT, arg,
326 FuncRequest::KEYBOARD));
328 << "SelfInsert arg[`" << arg << "']" << endl;
336 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
338 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
340 LCursor & cur = view()->cursor();
342 /* In LyX/Mac, when a dialog is open, the menus of the
343 application can still be accessed without giving focus to
344 the main window. In this case, we want to disable the menu
345 entries that are buffer-related.
347 Note that this code is not perfect, as bug 1941 attests:
348 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
351 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
354 buf = owner->buffer();
356 if (cmd.action == LFUN_NOACTION) {
357 flag.message(N_("Nothing to do"));
362 switch (cmd.action) {
363 case LFUN_UNKNOWN_ACTION:
364 #ifndef HAVE_LIBAIKSAURUS
365 case LFUN_THESAURUS_ENTRY:
371 flag |= lyx_gui::getStatus(cmd);
374 if (flag.unknown()) {
375 flag.message(N_("Unknown action"));
379 if (!flag.enabled()) {
380 if (flag.message().empty())
381 flag.message(N_("Command disabled"));
385 // Check whether we need a buffer
386 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
388 flag.message(N_("Command not allowed with"
389 "out any document open"));
394 // I would really like to avoid having this switch and rather try to
395 // encode this in the function itself.
396 // -- And I'd rather let an inset decide which LFUNs it is willing
397 // to handle (Andre')
399 switch (cmd.action) {
400 case LFUN_TOOLTIPS_TOGGLE:
401 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
404 case LFUN_READ_ONLY_TOGGLE:
405 flag.setOnOff(buf->isReadonly());
408 case LFUN_SWITCHBUFFER:
409 // toggle on the current buffer, but do not toggle off
410 // the other ones (is that a good idea?)
411 if (cmd.argument == buf->fileName())
416 enable = cmd.argument == "custom"
417 || Exporter::isExportable(*buf, cmd.argument);
421 enable = buf->isLatex() && lyxrc.chktex_command != "none";
425 enable = Exporter::isExportable(*buf, "program");
428 case LFUN_LAYOUT_TABULAR:
429 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
433 case LFUN_LAYOUT_PARAGRAPH:
434 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
437 case LFUN_VC_REGISTER:
438 enable = !buf->lyxvc().inUse();
440 case LFUN_VC_CHECKIN:
441 enable = buf->lyxvc().inUse() && !buf->isReadonly();
443 case LFUN_VC_CHECKOUT:
444 enable = buf->lyxvc().inUse() && buf->isReadonly();
448 enable = buf->lyxvc().inUse();
450 case LFUN_MENURELOAD:
451 enable = !buf->isUnnamed() && !buf->isClean();
454 case LFUN_INSET_SETTINGS: {
458 InsetBase::Code code = cur.inset().lyxCode();
460 case InsetBase::TABULAR_CODE:
461 enable = cmd.argument == "tabular";
463 case InsetBase::ERT_CODE:
464 enable = cmd.argument == "ert";
466 case InsetBase::FLOAT_CODE:
467 enable = cmd.argument == "float";
469 case InsetBase::WRAP_CODE:
470 enable = cmd.argument == "wrap";
472 case InsetBase::NOTE_CODE:
473 enable = cmd.argument == "note";
475 case InsetBase::BRANCH_CODE:
476 enable = cmd.argument == "branch";
478 case InsetBase::BOX_CODE:
479 enable = cmd.argument == "box";
487 case LFUN_INSET_APPLY: {
488 string const name = cmd.getArg(0);
489 InsetBase * inset = owner->getDialogs().getOpenInset(name);
491 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
493 bool const success = inset->getStatus(cur, fr, fs);
494 // Every inset is supposed to handle this
495 BOOST_ASSERT(success);
498 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
499 flag |= getStatus(fr);
501 enable = flag.enabled();
505 case LFUN_DIALOG_SHOW: {
506 string const name = cmd.getArg(0);
508 enable = name == "aboutlyx"
512 || name == "texinfo";
513 else if (name == "print")
514 enable = Exporter::isExportable(*buf, "dvi")
515 && lyxrc.print_command != "none";
516 else if (name == "character" || name == "mathpanel")
517 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
518 else if (name == "latexlog")
519 enable = isFileReadable(buf->getLogName().second);
520 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
521 else if (name == "spellchecker")
524 else if (name == "vclog")
525 enable = buf->lyxvc().inUse();
526 else if (name == "view-source")
531 case LFUN_DIALOG_SHOW_NEW_INSET:
532 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
535 case LFUN_DIALOG_UPDATE: {
536 string const name = cmd.getArg(0);
538 enable = name == "prefs";
542 case LFUN_INSERT_CITATION: {
543 FuncRequest fr(LFUN_INSET_INSERT, "citation");
544 enable = getStatus(fr).enabled();
548 case LFUN_MENUWRITE: {
549 enable = view()->buffer()->isUnnamed()
550 || !view()->buffer()->isClean();
554 // this one is difficult to get right. As a half-baked
555 // solution, we consider only the first action of the sequence
556 case LFUN_SEQUENCE: {
557 // argument contains ';'-terminated commands
558 string const firstcmd = token(cmd.argument, ';', 0);
559 FuncRequest func(lyxaction.lookupFunc(firstcmd));
560 func.origin = cmd.origin;
561 flag = getStatus(func);
565 case LFUN_MENUNEWTMPLT:
566 case LFUN_WORDFINDFORWARD:
567 case LFUN_WORDFINDBACKWARD:
569 case LFUN_EXEC_COMMAND:
572 case LFUN_CLOSEBUFFER:
580 case LFUN_RECONFIGURE:
584 case LFUN_DROP_LAYOUTS_CHOICE:
585 case LFUN_MENU_OPEN_BY_NAME:
588 case LFUN_GOTOFILEROW:
589 case LFUN_DIALOG_SHOW_NEXT_INSET:
590 case LFUN_DIALOG_HIDE:
591 case LFUN_DIALOG_DISCONNECT_INSET:
593 case LFUN_TOGGLECURSORFOLLOW:
597 case LFUN_KMAP_TOGGLE:
599 case LFUN_EXPORT_CUSTOM:
601 case LFUN_SAVEPREFERENCES:
602 case LFUN_SCREEN_FONT_UPDATE:
605 case LFUN_EXTERNAL_EDIT:
606 case LFUN_GRAPHICS_EDIT:
607 case LFUN_ALL_INSETS_TOGGLE:
608 case LFUN_LANGUAGE_BUFFER:
609 case LFUN_TEXTCLASS_APPLY:
610 case LFUN_TEXTCLASS_LOAD:
611 case LFUN_SAVE_AS_DEFAULT:
612 case LFUN_BUFFERPARAMS_APPLY:
613 case LFUN_LYXRC_APPLY:
614 case LFUN_NEXTBUFFER:
615 case LFUN_PREVIOUSBUFFER:
616 // these are handled in our dispatch()
621 if (!::getStatus(cur, cmd, flag))
622 flag = view()->getStatus(cmd);
628 // Can we use a readonly buffer?
629 if (buf && buf->isReadonly()
630 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
631 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
632 flag.message(N_("Document is read-only"));
636 // Are we in a DELETED change-tracking region?
637 if (buf && buf->params().tracking_changes
638 && lookupChange(cur, true) == Change::DELETED
639 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
640 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
641 flag.message(N_("This portion of the document is deleted."));
645 // the default error message if we disable the command
646 if (!flag.enabled() && flag.message().empty())
647 flag.message(N_("Command disabled"));
655 bool ensureBufferClean(BufferView * bv)
657 Buffer & buf = *bv->buffer();
661 string const file = makeDisplayPath(buf.fileName(), 30);
662 string text = bformat(_("The document %1$s has unsaved "
663 "changes.\n\nDo you want to save "
664 "the document?"), file);
665 int const ret = Alert::prompt(_("Save changed document?"),
666 text, 0, 1, _("&Save"),
670 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
672 return buf.isClean();
676 void showPrintError(string const & name)
678 string str = bformat(_("Could not print the document %1$s.\n"
679 "Check that your printer is set up correctly."),
680 makeDisplayPath(name, 50));
681 Alert::error(_("Print document failed"), str);
685 void loadTextclass(string const & name)
687 std::pair<bool, lyx::textclass_type> const tc_pair =
688 textclasslist.numberOfClass(name);
690 if (!tc_pair.first) {
691 lyxerr << "Document class \"" << name
692 << "\" does not exist."
697 lyx::textclass_type const tc = tc_pair.second;
699 if (!textclasslist[tc].load()) {
700 string s = bformat(_("The document could not be converted\n"
701 "into the document class %1$s."),
702 textclasslist[tc].name());
703 Alert::error(_("Could not change class"), s);
708 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
713 void LyXFunc::dispatch(FuncRequest const & cmd)
715 BOOST_ASSERT(view());
716 string const argument = cmd.argument;
717 kb_action const action = cmd.action;
719 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
720 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
722 // we have not done anything wrong yet.
724 dispatch_buffer.erase();
728 FuncStatus const flag = getStatus(cmd);
729 if (!flag.enabled()) {
730 // We cannot use this function here
731 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
732 << lyxaction.getActionName(action)
733 << " [" << action << "] is disabled at this location"
735 setErrorMessage(flag.message());
738 if (view()->available())
739 view()->hideCursor();
743 case LFUN_WORDFINDFORWARD:
744 case LFUN_WORDFINDBACKWARD: {
745 static string last_search;
746 string searched_string;
748 if (!argument.empty()) {
749 last_search = argument;
750 searched_string = argument;
752 searched_string = last_search;
755 if (searched_string.empty())
758 bool const fw = action == LFUN_WORDFINDFORWARD;
760 lyx::find::find2string(searched_string, true, false, fw);
761 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
766 owner->message(keyseq.printOptions());
769 case LFUN_EXEC_COMMAND:
770 owner->getToolbars().display("minibuffer", true);
771 owner->focus_command_buffer();
776 meta_fake_bit = key_modifier::none;
777 if (view()->available())
778 // cancel any selection
779 dispatch(FuncRequest(LFUN_MARK_OFF));
780 setMessage(N_("Cancel"));
784 meta_fake_bit = key_modifier::alt;
785 setMessage(keyseq.print());
788 case LFUN_READ_ONLY_TOGGLE:
789 if (owner->buffer()->lyxvc().inUse())
790 owner->buffer()->lyxvc().toggleReadOnly();
792 owner->buffer()->setReadonly(
793 !owner->buffer()->isReadonly());
796 // --- Menus -----------------------------------------------
798 menuNew(argument, false);
801 case LFUN_MENUNEWTMPLT:
802 menuNew(argument, true);
805 case LFUN_CLOSEBUFFER:
810 if (!owner->buffer()->isUnnamed()) {
811 string const str = bformat(_("Saving document %1$s..."),
812 makeDisplayPath(owner->buffer()->fileName()));
814 menuWrite(owner->buffer());
815 owner->message(str + _(" done."));
817 writeAs(owner->buffer());
821 writeAs(owner->buffer(), argument);
824 case LFUN_MENURELOAD: {
825 string const file = makeDisplayPath(view()->buffer()->fileName(), 20);
826 string text = bformat(_("Any changes will be lost. Are you sure "
827 "you want to revert to the saved version of the document %1$s?"), file);
828 int const ret = Alert::prompt(_("Revert to saved document?"),
829 text, 0, 1, _("&Revert"), _("&Cancel"));
837 Exporter::Export(owner->buffer(), argument, true);
838 view()->showErrorList(bufferFormat(*owner->buffer()));
842 Exporter::preview(owner->buffer(), argument);
843 view()->showErrorList(bufferFormat(*owner->buffer()));
847 Exporter::Export(owner->buffer(), "program", true);
848 view()->showErrorList(_("Build"));
852 owner->buffer()->runChktex();
853 view()->showErrorList(_("ChkTeX"));
857 if (argument == "custom")
858 owner->getDialogs().show("sendto");
860 Exporter::Export(owner->buffer(), argument, false);
861 view()->showErrorList(bufferFormat(*owner->buffer()));
865 case LFUN_EXPORT_CUSTOM: {
867 string command = split(argument, format_name, ' ');
868 Format const * format = formats.getFormat(format_name);
870 lyxerr << "Format \"" << format_name
871 << "\" not recognized!"
876 Buffer * buffer = owner->buffer();
878 // The name of the file created by the conversion process
881 // Output to filename
882 if (format->name() == "lyx") {
883 string const latexname =
884 buffer->getLatexName(false);
885 filename = changeExtension(latexname,
886 format->extension());
887 filename = addName(buffer->temppath(), filename);
889 if (!buffer->writeFile(filename))
893 Exporter::Export(buffer, format_name, true,
897 // Substitute $$FName for filename
898 if (!contains(command, "$$FName"))
899 command = "( " + command + " ) < $$FName";
900 command = subst(command, "$$FName", filename);
902 // Execute the command in the background
904 call.startscript(Systemcall::DontWait, command);
911 string command = split(split(argument, target, ' '),
915 || target_name.empty()
916 || command.empty()) {
917 lyxerr << "Unable to parse \""
918 << argument << '"' << std::endl;
921 if (target != "printer" && target != "file") {
922 lyxerr << "Unrecognized target \""
923 << target << '"' << std::endl;
927 Buffer * buffer = owner->buffer();
929 if (!Exporter::Export(buffer, "dvi", true)) {
930 showPrintError(buffer->fileName());
934 // Push directory path.
935 string const path = buffer->temppath();
938 // there are three cases here:
939 // 1. we print to a file
940 // 2. we print directly to a printer
941 // 3. we print using a spool command (print to file first)
944 string const dviname =
945 changeExtension(buffer->getLatexName(true),
948 if (target == "printer") {
949 if (!lyxrc.print_spool_command.empty()) {
950 // case 3: print using a spool
951 string const psname =
952 changeExtension(dviname,".ps");
953 command += lyxrc.print_to_file
956 + quoteName(dviname);
959 lyxrc.print_spool_command +' ';
960 if (target_name != "default") {
961 command2 += lyxrc.print_spool_printerprefix
965 command2 += quoteName(psname);
967 // If successful, then spool command
968 res = one.startscript(
973 res = one.startscript(
974 Systemcall::DontWait,
977 // case 2: print directly to a printer
978 res = one.startscript(
979 Systemcall::DontWait,
980 command + quoteName(dviname));
984 // case 1: print to a file
985 command += lyxrc.print_to_file
986 + quoteName(makeAbsPath(target_name,
989 + quoteName(dviname);
990 res = one.startscript(Systemcall::DontWait,
995 showPrintError(buffer->fileName());
1004 if (view()->available()) {
1005 // save cursor Position for opened files to .lyx/session
1006 LyX::ref().session().saveFilePosition(owner->buffer()->fileName(),
1007 boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1008 // save opened file name to .lyx/session
1009 LyX::ref().session().setLastOpenedFiles( bufferlist.getFileNames());
1010 // save bookmarks to .lyx/session
1011 view()->saveSavedPositions();
1013 quitLyX(argument == "force");
1016 case LFUN_TOCVIEW: {
1017 InsetCommandParams p("tableofcontents");
1018 string const data = InsetCommandMailer::params2string("toc", p);
1019 owner->getDialogs().show("toc", data, 0);
1027 case LFUN_RECONFIGURE:
1028 reconfigure(view());
1031 case LFUN_HELP_OPEN: {
1032 string const arg = argument;
1034 setErrorMessage(N_("Missing argument"));
1037 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1038 if (fname.empty()) {
1039 lyxerr << "LyX: unable to find documentation file `"
1040 << arg << "'. Bad installation?" << endl;
1043 owner->message(bformat(_("Opening help file %1$s..."),
1044 makeDisplayPath(fname)));
1045 view()->loadLyXFile(fname, false);
1049 // --- version control -------------------------------
1050 case LFUN_VC_REGISTER:
1051 if (!ensureBufferClean(view()))
1053 if (!owner->buffer()->lyxvc().inUse()) {
1054 owner->buffer()->lyxvc().registrer();
1059 case LFUN_VC_CHECKIN:
1060 if (!ensureBufferClean(view()))
1062 if (owner->buffer()->lyxvc().inUse()
1063 && !owner->buffer()->isReadonly()) {
1064 owner->buffer()->lyxvc().checkIn();
1069 case LFUN_VC_CHECKOUT:
1070 if (!ensureBufferClean(view()))
1072 if (owner->buffer()->lyxvc().inUse()
1073 && owner->buffer()->isReadonly()) {
1074 owner->buffer()->lyxvc().checkOut();
1079 case LFUN_VC_REVERT:
1080 owner->buffer()->lyxvc().revert();
1085 owner->buffer()->lyxvc().undoLast();
1089 // --- buffers ----------------------------------------
1090 case LFUN_SWITCHBUFFER:
1091 view()->setBuffer(bufferlist.getBuffer(argument));
1094 case LFUN_NEXTBUFFER:
1095 view()->setBuffer(bufferlist.next(view()->buffer()));
1098 case LFUN_PREVIOUSBUFFER:
1099 view()->setBuffer(bufferlist.previous(view()->buffer()));
1103 newFile(view(), argument);
1106 case LFUN_FILE_OPEN:
1110 case LFUN_DROP_LAYOUTS_CHOICE:
1111 owner->getToolbars().openLayoutList();
1114 case LFUN_MENU_OPEN_BY_NAME:
1115 owner->getMenubar().openByName(argument);
1118 // --- lyxserver commands ----------------------------
1120 setMessage(owner->buffer()->fileName());
1121 lyxerr[Debug::INFO] << "FNAME["
1122 << owner->buffer()->fileName()
1127 dispatch_buffer = keyseq.print();
1128 lyxserver->notifyClient(dispatch_buffer);
1131 case LFUN_GOTOFILEROW: {
1134 istringstream is(argument);
1135 is >> file_name >> row;
1136 if (prefixIs(file_name, package().temp_dir())) {
1137 // Needed by inverse dvi search. If it is a file
1138 // in tmpdir, call the apropriated function
1139 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1141 // Must replace extension of the file to be .lyx
1142 // and get full path
1143 string const s = changeExtension(file_name, ".lyx");
1144 // Either change buffer or load the file
1145 if (bufferlist.exists(s)) {
1146 view()->setBuffer(bufferlist.getBuffer(s));
1148 view()->loadLyXFile(s);
1152 view()->setCursorFromRow(row);
1155 // see BufferView_pimpl::center()
1156 view()->updateScrollbar();
1160 case LFUN_DIALOG_SHOW: {
1161 string const name = cmd.getArg(0);
1162 string data = trim(cmd.argument.substr(name.size()));
1164 if (name == "character") {
1165 data = freefont2string();
1167 owner->getDialogs().show("character", data);
1168 } else if (name == "latexlog") {
1169 pair<Buffer::LogType, string> const logfile =
1170 owner->buffer()->getLogName();
1171 switch (logfile.first) {
1172 case Buffer::latexlog:
1175 case Buffer::buildlog:
1179 data += logfile.second;
1180 owner->getDialogs().show("log", data);
1181 } else if (name == "vclog") {
1182 string const data = "vc " +
1183 owner->buffer()->lyxvc().getLogFile();
1184 owner->getDialogs().show("log", data);
1186 owner->getDialogs().show(name, data);
1190 case LFUN_DIALOG_SHOW_NEW_INSET: {
1191 string const name = cmd.getArg(0);
1192 string data = trim(cmd.argument.substr(name.size()));
1193 if (name == "bibitem" ||
1200 InsetCommandParams p(name);
1201 data = InsetCommandMailer::params2string(name, p);
1202 } else if (name == "include") {
1203 InsetCommandParams p(data);
1204 data = InsetIncludeMailer::params2string(p);
1205 } else if (name == "box") {
1206 // \c data == "Boxed" || "Frameless" etc
1207 InsetBoxParams p(data);
1208 data = InsetBoxMailer::params2string(p);
1209 } else if (name == "branch") {
1210 InsetBranchParams p;
1211 data = InsetBranchMailer::params2string(p);
1212 } else if (name == "citation") {
1213 InsetCommandParams p("cite");
1214 data = InsetCommandMailer::params2string(name, p);
1215 } else if (name == "ert") {
1216 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1217 } else if (name == "external") {
1218 InsetExternalParams p;
1219 Buffer const & buffer = *owner->buffer();
1220 data = InsetExternalMailer::params2string(p, buffer);
1221 } else if (name == "float") {
1223 data = InsetFloatMailer::params2string(p);
1224 } else if (name == "graphics") {
1225 InsetGraphicsParams p;
1226 Buffer const & buffer = *owner->buffer();
1227 data = InsetGraphicsMailer::params2string(p, buffer);
1228 } else if (name == "note") {
1230 data = InsetNoteMailer::params2string(p);
1231 } else if (name == "vspace") {
1233 data = InsetVSpaceMailer::params2string(space);
1234 } else if (name == "wrap") {
1236 data = InsetWrapMailer::params2string(p);
1238 owner->getDialogs().show(name, data, 0);
1242 case LFUN_DIALOG_SHOW_NEXT_INSET:
1245 case LFUN_DIALOG_UPDATE: {
1246 string const & name = argument;
1247 // Can only update a dialog connected to an existing inset
1248 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1250 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1251 inset->dispatch(view()->cursor(), fr);
1252 } else if (name == "paragraph") {
1253 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1254 } else if (name == "prefs") {
1255 owner->getDialogs().update(name, string());
1260 case LFUN_DIALOG_HIDE:
1261 Dialogs::hide(argument, 0);
1264 case LFUN_DIALOG_DISCONNECT_INSET:
1265 owner->getDialogs().disconnect(argument);
1269 case LFUN_INSERT_CITATION: {
1270 if (!argument.empty()) {
1271 // we can have one optional argument, delimited by '|'
1272 // citation-insert <key>|<text_before>
1273 // this should be enhanced to also support text_after
1274 // and citation style
1275 string arg = argument;
1277 if (contains(argument, "|")) {
1278 arg = token(argument, '|', 0);
1279 opt1 = '[' + token(argument, '|', 1) + ']';
1281 std::ostringstream os;
1282 os << "citation LatexCommand\n"
1283 << "\\cite" << opt1 << "{" << arg << "}\n"
1285 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1288 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1292 case LFUN_CHILDOPEN: {
1293 string const filename =
1294 makeAbsPath(argument, owner->buffer()->filePath());
1295 setMessage(N_("Opening child document ") +
1296 makeDisplayPath(filename) + "...");
1297 view()->savePosition(0);
1298 string const parentfilename = owner->buffer()->fileName();
1299 if (bufferlist.exists(filename))
1300 view()->setBuffer(bufferlist.getBuffer(filename));
1302 view()->loadLyXFile(filename);
1303 // Set the parent name of the child document.
1304 // This makes insertion of citations and references in the child work,
1305 // when the target is in the parent or another child document.
1306 owner->buffer()->setParentName(parentfilename);
1310 case LFUN_TOGGLECURSORFOLLOW:
1311 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1315 owner->getIntl().keyMapOn(false);
1318 case LFUN_KMAP_PRIM:
1319 owner->getIntl().keyMapPrim();
1323 owner->getIntl().keyMapSec();
1326 case LFUN_KMAP_TOGGLE:
1327 owner->getIntl().toggleKeyMap();
1333 string rest = split(argument, countstr, ' ');
1334 istringstream is(countstr);
1337 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1338 for (int i = 0; i < count; ++i)
1339 dispatch(lyxaction.lookupFunc(rest));
1343 case LFUN_SEQUENCE: {
1344 // argument contains ';'-terminated commands
1345 string arg = argument;
1346 while (!arg.empty()) {
1348 arg = split(arg, first, ';');
1349 FuncRequest func(lyxaction.lookupFunc(first));
1350 func.origin = cmd.origin;
1356 case LFUN_SAVEPREFERENCES: {
1357 Path p(package().user_support());
1358 lyxrc.write("preferences", false);
1362 case LFUN_SCREEN_FONT_UPDATE:
1363 // handle the screen font changes.
1364 lyxrc.set_font_norm_type();
1365 lyx_gui::update_fonts();
1366 // All visible buffers will need resize
1370 case LFUN_SET_COLOR: {
1372 string const x11_name = split(argument, lyx_name, ' ');
1373 if (lyx_name.empty() || x11_name.empty()) {
1374 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1379 bool const graphicsbg_changed =
1380 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1381 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1383 if (!lcolor.setColor(lyx_name, x11_name)) {
1385 bformat(_("Set-color \"%1$s\" failed "
1386 "- color is undefined or "
1387 "may not be redefined"), lyx_name));
1391 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1393 if (graphicsbg_changed) {
1394 #ifdef WITH_WARNINGS
1395 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1398 lyx::graphics::GCache::get().changeDisplay(true);
1405 owner->message(argument);
1408 case LFUN_TOOLTIPS_TOGGLE:
1409 owner->getDialogs().toggleTooltips();
1412 case LFUN_EXTERNAL_EDIT: {
1413 FuncRequest fr(action, argument);
1414 InsetExternal().dispatch(view()->cursor(), fr);
1418 case LFUN_GRAPHICS_EDIT: {
1419 FuncRequest fr(action, argument);
1420 InsetGraphics().dispatch(view()->cursor(), fr);
1424 case LFUN_INSET_APPLY: {
1425 string const name = cmd.getArg(0);
1426 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1428 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1429 inset->dispatch(view()->cursor(), fr);
1431 FuncRequest fr(LFUN_INSET_INSERT, argument);
1434 // ideally, the update flag should be set by the insets,
1435 // but this is not possible currently
1440 case LFUN_ALL_INSETS_TOGGLE: {
1442 string const name = split(argument, action, ' ');
1443 InsetBase::Code const inset_code =
1444 InsetBase::translate(name);
1446 LCursor & cur = view()->cursor();
1447 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1449 InsetBase & inset = owner->buffer()->inset();
1450 InsetIterator it = inset_iterator_begin(inset);
1451 InsetIterator const end = inset_iterator_end(inset);
1452 for (; it != end; ++it) {
1453 if (inset_code == InsetBase::NO_CODE
1454 || inset_code == it->lyxCode()) {
1455 LCursor tmpcur = cur;
1456 tmpcur.pushLeft(*it);
1457 it->dispatch(tmpcur, fr);
1464 case LFUN_LANGUAGE_BUFFER: {
1465 Buffer & buffer = *owner->buffer();
1466 Language const * oldL = buffer.params().language;
1467 Language const * newL = languages.getLanguage(argument);
1468 if (!newL || oldL == newL)
1471 if (oldL->rightToLeft() == newL->rightToLeft()
1472 && !buffer.isMultiLingual())
1473 buffer.changeLanguage(oldL, newL);
1475 buffer.updateDocLang(newL);
1479 case LFUN_SAVE_AS_DEFAULT: {
1480 string const fname =
1481 addName(addPath(package().user_support(), "templates/"),
1483 Buffer defaults(fname);
1485 istringstream ss(argument);
1488 int const unknown_tokens = defaults.readHeader(lex);
1490 if (unknown_tokens != 0) {
1491 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1492 << unknown_tokens << " unknown token"
1493 << (unknown_tokens == 1 ? "" : "s")
1497 if (defaults.writeFile(defaults.fileName()))
1498 setMessage(_("Document defaults saved in ")
1499 + makeDisplayPath(fname));
1501 setErrorMessage(_("Unable to save document defaults"));
1505 case LFUN_BUFFERPARAMS_APPLY: {
1506 biblio::CiteEngine const engine =
1507 owner->buffer()->params().cite_engine;
1509 istringstream ss(argument);
1512 int const unknown_tokens =
1513 owner->buffer()->readHeader(lex);
1515 if (unknown_tokens != 0) {
1516 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1517 << unknown_tokens << " unknown token"
1518 << (unknown_tokens == 1 ? "" : "s")
1521 if (engine == owner->buffer()->params().cite_engine)
1524 LCursor & cur = view()->cursor();
1525 FuncRequest fr(LFUN_INSET_REFRESH);
1527 InsetBase & inset = owner->buffer()->inset();
1528 InsetIterator it = inset_iterator_begin(inset);
1529 InsetIterator const end = inset_iterator_end(inset);
1530 for (; it != end; ++it)
1531 if (it->lyxCode() == InsetBase::CITE_CODE)
1532 it->dispatch(cur, fr);
1536 case LFUN_TEXTCLASS_APPLY: {
1537 Buffer * buffer = owner->buffer();
1539 lyx::textclass_type const old_class =
1540 buffer->params().textclass;
1542 loadTextclass(argument);
1544 std::pair<bool, lyx::textclass_type> const tc_pair =
1545 textclasslist.numberOfClass(argument);
1550 lyx::textclass_type const new_class = tc_pair.second;
1551 if (old_class == new_class)
1555 owner->message(_("Converting document to new document class..."));
1556 recordUndoFullDocument(view());
1557 buffer->params().textclass = new_class;
1558 StableDocIterator backcur(view()->cursor());
1560 lyx::cap::switchBetweenClasses(
1561 old_class, new_class,
1562 buffer->paragraphs(), el);
1564 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1565 bufferErrors(*buffer, el);
1566 view()->showErrorList(_("Class switch"));
1567 updateCounters(*buffer);
1572 case LFUN_TEXTCLASS_LOAD:
1573 loadTextclass(argument);
1576 case LFUN_LYXRC_APPLY: {
1577 LyXRC const lyxrc_orig = lyxrc;
1579 istringstream ss(argument);
1580 bool const success = lyxrc.read(ss) == 0;
1583 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1584 << "Unable to read lyxrc data"
1589 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1594 view()->cursor().dispatch(cmd);
1595 update |= view()->cursor().result().update();
1596 if (!view()->cursor().result().dispatched())
1597 update |= view()->dispatch(cmd);
1602 if (view()->available()) {
1603 // Redraw screen unless explicitly told otherwise.
1604 // This also initializes the position cache for all insets
1605 // in (at least partially) visible top-level paragraphs.
1607 view()->update(Update::FitCursor | Update::Force);
1609 view()->update(Update::FitCursor);
1611 // if we executed a mutating lfun, mark the buffer as dirty
1613 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1614 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1615 view()->buffer()->markDirty();
1618 if (view()->cursor().inTexted()) {
1619 view()->owner()->updateLayoutChoice();
1622 sendDispatchMessage(_(getMessage()), cmd);
1626 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1628 /* When an action did not originate from the UI/kbd, it makes
1629 * sense to avoid updating the GUI. It turns out that this
1630 * fixes bug 1941, for reasons that are described here:
1631 * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1633 if (cmd.origin != FuncRequest::INTERNAL) {
1634 owner->updateMenubar();
1635 owner->updateToolbars();
1638 const bool verbose = (cmd.origin == FuncRequest::UI
1639 || cmd.origin == FuncRequest::COMMANDBUFFER);
1641 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1642 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1644 owner->message(msg);
1648 string dispatch_msg = msg;
1649 if (!dispatch_msg.empty())
1650 dispatch_msg += ' ';
1652 string comname = lyxaction.getActionName(cmd.action);
1654 bool argsadded = false;
1656 if (!cmd.argument.empty()) {
1657 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1658 comname += ' ' + cmd.argument;
1663 string const shortcuts = toplevel_keymap->printbindings(cmd);
1665 if (!shortcuts.empty())
1666 comname += ": " + shortcuts;
1667 else if (!argsadded && !cmd.argument.empty())
1668 comname += ' ' + cmd.argument;
1670 if (!comname.empty()) {
1671 comname = rtrim(comname);
1672 dispatch_msg += '(' + rtrim(comname) + ')';
1675 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1676 if (!dispatch_msg.empty())
1677 owner->message(dispatch_msg);
1681 void LyXFunc::setupLocalKeymap()
1683 keyseq.stdmap = toplevel_keymap.get();
1684 keyseq.curmap = toplevel_keymap.get();
1685 cancel_meta_seq.stdmap = toplevel_keymap.get();
1686 cancel_meta_seq.curmap = toplevel_keymap.get();
1690 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1692 string initpath = lyxrc.document_path;
1693 string filename(name);
1695 if (view()->available()) {
1696 string const trypath = owner->buffer()->filePath();
1697 // If directory is writeable, use this as default.
1698 if (isDirWriteable(trypath))
1702 static int newfile_number;
1704 if (filename.empty()) {
1705 filename = addName(lyxrc.document_path,
1706 "newfile" + convert<string>(++newfile_number) + ".lyx");
1707 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1709 filename = addName(lyxrc.document_path,
1710 "newfile" + convert<string>(newfile_number) +
1715 // The template stuff
1718 FileDialog fileDlg(_("Select template file"),
1719 LFUN_SELECT_FILE_SYNC,
1720 make_pair(string(_("Documents|#o#O")),
1721 string(lyxrc.document_path)),
1722 make_pair(string(_("Templates|#T#t")),
1723 string(lyxrc.template_path)));
1725 FileDialog::Result result =
1726 fileDlg.open(lyxrc.template_path,
1727 FileFilterList(_("LyX Documents (*.lyx)")),
1730 if (result.first == FileDialog::Later)
1732 if (result.second.empty())
1734 templname = result.second;
1737 view()->newFile(filename, templname, !name.empty());
1741 void LyXFunc::open(string const & fname)
1743 string initpath = lyxrc.document_path;
1745 if (view()->available()) {
1746 string const trypath = owner->buffer()->filePath();
1747 // If directory is writeable, use this as default.
1748 if (isDirWriteable(trypath))
1754 if (fname.empty()) {
1755 FileDialog fileDlg(_("Select document to open"),
1757 make_pair(string(_("Documents|#o#O")),
1758 string(lyxrc.document_path)),
1759 make_pair(string(_("Examples|#E#e")),
1760 string(addPath(package().system_support(), "examples"))));
1762 FileDialog::Result result =
1763 fileDlg.open(initpath,
1764 FileFilterList(_("LyX Documents (*.lyx)")),
1767 if (result.first == FileDialog::Later)
1770 filename = result.second;
1772 // check selected filename
1773 if (filename.empty()) {
1774 owner->message(_("Canceled."));
1780 // get absolute path of file and add ".lyx" to the filename if
1782 string const fullpath = fileSearch(string(), filename, "lyx");
1783 if (!fullpath.empty()) {
1784 filename = fullpath;
1787 string const disp_fn(makeDisplayPath(filename));
1789 // if the file doesn't exist, let the user create one
1790 if (!fs::exists(filename)) {
1791 // the user specifically chose this name. Believe them.
1792 view()->newFile(filename, "", true);
1796 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1799 if (view()->loadLyXFile(filename)) {
1800 str2 = bformat(_("Document %1$s opened."), disp_fn);
1802 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1804 owner->message(str2);
1808 void LyXFunc::doImport(string const & argument)
1811 string filename = split(argument, format, ' ');
1813 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1814 << " file: " << filename << endl;
1816 // need user interaction
1817 if (filename.empty()) {
1818 string initpath = lyxrc.document_path;
1820 if (view()->available()) {
1821 string const trypath = owner->buffer()->filePath();
1822 // If directory is writeable, use this as default.
1823 if (isDirWriteable(trypath))
1827 string const text = bformat(_("Select %1$s file to import"),
1828 formats.prettyName(format));
1830 FileDialog fileDlg(text,
1832 make_pair(string(_("Documents|#o#O")),
1833 string(lyxrc.document_path)),
1834 make_pair(string(_("Examples|#E#e")),
1835 string(addPath(package().system_support(), "examples"))));
1837 string const filter = formats.prettyName(format)
1838 + " (*." + formats.extension(format) + ')';
1840 FileDialog::Result result =
1841 fileDlg.open(initpath,
1842 FileFilterList(filter),
1845 if (result.first == FileDialog::Later)
1848 filename = result.second;
1850 // check selected filename
1851 if (filename.empty())
1852 owner->message(_("Canceled."));
1855 if (filename.empty())
1858 // get absolute path of file
1859 filename = makeAbsPath(filename);
1861 string const lyxfile = changeExtension(filename, ".lyx");
1863 // Check if the document already is open
1864 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1865 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1866 owner->message(_("Canceled."));
1871 // if the file exists already, and we didn't do
1872 // -i lyx thefile.lyx, warn
1873 if (fs::exists(lyxfile) && filename != lyxfile) {
1874 string const file = makeDisplayPath(lyxfile, 30);
1876 string text = bformat(_("The document %1$s already exists.\n\n"
1877 "Do you want to over-write that document?"), file);
1878 int const ret = Alert::prompt(_("Over-write document?"),
1879 text, 0, 1, _("&Over-write"), _("&Cancel"));
1882 owner->message(_("Canceled."));
1887 Importer::Import(owner, filename, format);
1891 void LyXFunc::closeBuffer()
1893 // save current cursor position
1894 LyX::ref().session().saveFilePosition(owner->buffer()->fileName(),
1895 boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1896 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1897 if (bufferlist.empty()) {
1898 // need this otherwise SEGV may occur while
1899 // trying to set variables that don't exist
1900 // since there's no current buffer
1901 owner->getDialogs().hideBufferDependent();
1903 view()->setBuffer(bufferlist.first());
1909 // Each "owner" should have it's own message method. lyxview and
1910 // the minibuffer would use the minibuffer, but lyxserver would
1911 // send an ERROR signal to its client. Alejandro 970603
1912 // This function is bit problematic when it comes to NLS, to make the
1913 // lyx servers client be language indepenent we must not translate
1914 // strings sent to this func.
1915 void LyXFunc::setErrorMessage(string const & m) const
1917 dispatch_buffer = m;
1922 void LyXFunc::setMessage(string const & m) const
1924 dispatch_buffer = m;
1928 string const LyXFunc::viewStatusMessage()
1930 // When meta-fake key is pressed, show the key sequence so far + "M-".
1932 return keyseq.print() + "M-";
1934 // Else, when a non-complete key sequence is pressed,
1935 // show the available options.
1936 if (keyseq.length() > 0 && !keyseq.deleted())
1937 return keyseq.printOptions();
1939 if (!view()->available())
1940 return _("Welcome to LyX!");
1942 return view()->cursor().currentState();
1946 BufferView * LyXFunc::view() const
1948 BOOST_ASSERT(owner);
1949 return owner->view().get();
1953 bool LyXFunc::wasMetaKey() const
1955 return (meta_fake_bit != key_modifier::none);
1961 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1963 // Why the switch you might ask. It is a trick to ensure that all
1964 // the elements in the LyXRCTags enum is handled. As you can see
1965 // there are no breaks at all. So it is just a huge fall-through.
1966 // The nice thing is that we will get a warning from the compiler
1967 // if we forget an element.
1968 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1970 case LyXRC::RC_ACCEPT_COMPOUND:
1971 case LyXRC::RC_ALT_LANG:
1972 case LyXRC::RC_ASCIIROFF_COMMAND:
1973 case LyXRC::RC_ASCII_LINELEN:
1974 case LyXRC::RC_AUTOREGIONDELETE:
1975 case LyXRC::RC_AUTORESET_OPTIONS:
1976 case LyXRC::RC_AUTOSAVE:
1977 case LyXRC::RC_AUTO_NUMBER:
1978 case LyXRC::RC_BACKUPDIR_PATH:
1979 case LyXRC::RC_BIBTEX_COMMAND:
1980 case LyXRC::RC_BINDFILE:
1981 case LyXRC::RC_CHECKLASTFILES:
1982 case LyXRC::RC_USELASTFILEPOS:
1983 case LyXRC::RC_LOADSESSION:
1984 case LyXRC::RC_CHKTEX_COMMAND:
1985 case LyXRC::RC_CONVERTER:
1986 case LyXRC::RC_COPIER:
1987 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1988 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1989 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1990 case LyXRC::RC_CYGWIN_PATH_FIX:
1991 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1992 namespace os = lyx::support::os;
1993 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1995 case LyXRC::RC_DATE_INSERT_FORMAT:
1996 case LyXRC::RC_DEFAULT_LANGUAGE:
1997 case LyXRC::RC_DEFAULT_PAPERSIZE:
1998 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1999 case LyXRC::RC_DISPLAY_GRAPHICS:
2000 case LyXRC::RC_DOCUMENTPATH:
2001 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2002 if (fs::exists(lyxrc_new.document_path) &&
2003 fs::is_directory(lyxrc_new.document_path)) {
2004 using lyx::support::package;
2005 package().document_dir() = lyxrc.document_path;
2008 case LyXRC::RC_ESC_CHARS:
2009 case LyXRC::RC_FONT_ENCODING:
2010 case LyXRC::RC_FORMAT:
2011 case LyXRC::RC_INDEX_COMMAND:
2012 case LyXRC::RC_INPUT:
2013 case LyXRC::RC_KBMAP:
2014 case LyXRC::RC_KBMAP_PRIMARY:
2015 case LyXRC::RC_KBMAP_SECONDARY:
2016 case LyXRC::RC_LABEL_INIT_LENGTH:
2017 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2018 case LyXRC::RC_LANGUAGE_AUTO_END:
2019 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2020 case LyXRC::RC_LANGUAGE_COMMAND_END:
2021 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2022 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2023 case LyXRC::RC_LANGUAGE_PACKAGE:
2024 case LyXRC::RC_LANGUAGE_USE_BABEL:
2025 case LyXRC::RC_MAKE_BACKUP:
2026 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2027 case LyXRC::RC_NUMLASTFILES:
2028 case LyXRC::RC_PATH_PREFIX:
2029 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2030 using lyx::support::prependEnvPath;
2031 prependEnvPath("PATH", lyxrc.path_prefix);
2033 case LyXRC::RC_PERS_DICT:
2034 case LyXRC::RC_POPUP_BOLD_FONT:
2035 case LyXRC::RC_POPUP_FONT_ENCODING:
2036 case LyXRC::RC_POPUP_NORMAL_FONT:
2037 case LyXRC::RC_PREVIEW:
2038 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2039 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2040 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2041 case LyXRC::RC_PRINTCOPIESFLAG:
2042 case LyXRC::RC_PRINTER:
2043 case LyXRC::RC_PRINTEVENPAGEFLAG:
2044 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2045 case LyXRC::RC_PRINTFILEEXTENSION:
2046 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2047 case LyXRC::RC_PRINTODDPAGEFLAG:
2048 case LyXRC::RC_PRINTPAGERANGEFLAG:
2049 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2050 case LyXRC::RC_PRINTPAPERFLAG:
2051 case LyXRC::RC_PRINTREVERSEFLAG:
2052 case LyXRC::RC_PRINTSPOOL_COMMAND:
2053 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2054 case LyXRC::RC_PRINTTOFILE:
2055 case LyXRC::RC_PRINTTOPRINTER:
2056 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2057 case LyXRC::RC_PRINT_COMMAND:
2058 case LyXRC::RC_RTL_SUPPORT:
2059 case LyXRC::RC_SCREEN_DPI:
2060 case LyXRC::RC_SCREEN_FONT_ENCODING:
2061 case LyXRC::RC_SCREEN_FONT_ROMAN:
2062 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2063 case LyXRC::RC_SCREEN_FONT_SANS:
2064 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2065 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2066 case LyXRC::RC_SCREEN_FONT_SIZES:
2067 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2068 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2069 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2070 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2071 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2072 case LyXRC::RC_SCREEN_ZOOM:
2073 case LyXRC::RC_SERVERPIPE:
2074 case LyXRC::RC_SET_COLOR:
2075 case LyXRC::RC_SHOW_BANNER:
2076 case LyXRC::RC_SPELL_COMMAND:
2077 case LyXRC::RC_TEMPDIRPATH:
2078 case LyXRC::RC_TEMPLATEPATH:
2079 case LyXRC::RC_TEX_ALLOWS_SPACES:
2080 case LyXRC::RC_UIFILE:
2081 case LyXRC::RC_USER_EMAIL:
2082 case LyXRC::RC_USER_NAME:
2083 case LyXRC::RC_USETEMPDIR:
2084 case LyXRC::RC_USE_ALT_LANG:
2085 case LyXRC::RC_USE_ESC_CHARS:
2086 case LyXRC::RC_USE_INP_ENC:
2087 case LyXRC::RC_USE_PERS_DICT:
2088 case LyXRC::RC_USE_SPELL_LIB:
2089 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2090 case LyXRC::RC_VIEWER:
2091 case LyXRC::RC_WHEEL_JUMP:
2092 case LyXRC::RC_LAST: