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;
135 namespace biblio = lyx::biblio;
136 namespace fs = boost::filesystem;
139 extern BufferList bufferlist;
140 extern LyXServer * lyxserver;
142 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
145 extern tex_accent_struct get_accent(kb_action action);
150 bool getStatus(LCursor cursor,
151 FuncRequest const & cmd, FuncStatus & status)
153 // Try to fix cursor in case it is broken.
154 cursor.fixIfBroken();
156 // This is, of course, a mess. Better create a new doc iterator and use
157 // this in Inset::getStatus. This might require an additional
158 // BufferView * arg, though (which should be avoided)
159 //LCursor safe = *this;
161 for ( ; cursor.depth(); cursor.pop()) {
162 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
163 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
164 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
165 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
167 // The inset's getStatus() will return 'true' if it made
168 // a definitive decision on whether it want to handle the
169 // request or not. The result of this decision is put into
170 // the 'status' parameter.
171 if (cursor.inset().getStatus(cursor, cmd, status)) {
180 /** Return the change status at cursor position, taking in account the
181 * status at each level of the document iterator (a table in a deleted
182 * footnote is deleted).
183 * When \param outer is true, the top slice is not looked at.
185 Change::Type lookupChange(DocIterator const & dit, bool outer = false)
187 size_t const depth = dit.depth() - (outer ? 1 : 0);
189 for (size_t i = 0 ; i < depth ; ++i) {
190 CursorSlice const & slice = dit[i];
191 if (!slice.inset().inMathed()
192 && slice.pos() < slice.paragraph().size()) {
193 Change::Type const ch = slice.paragraph().lookupChange(slice.pos());
194 if (ch != Change::UNCHANGED)
198 return Change::UNCHANGED;
203 LyXFunc::LyXFunc(LyXView * lv)
206 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
207 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
208 meta_fake_bit(key_modifier::none)
213 void LyXFunc::handleKeyFunc(kb_action action)
215 char c = encoded_last_key;
217 if (keyseq.length()) {
221 owner->getIntl().getTransManager()
222 .deadkey(c, get_accent(action).accent, view()->getLyXText());
223 // Need to clear, in case the minibuffer calls these
226 // copied verbatim from do_accent_char
227 view()->cursor().resetAnchor();
232 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
234 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
236 // Do nothing if we have nothing (JMarc)
237 if (!keysym->isOK()) {
238 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
243 if (keysym->isModifier()) {
244 lyxerr[Debug::KEY] << "isModifier true" << endl;
248 Encoding const * encoding = view()->cursor().getEncoding();
250 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->name() : "");
252 // Do a one-deep top-level lookup for
253 // cancel and meta-fake keys. RVDK_PATCH_5
254 cancel_meta_seq.reset();
256 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
257 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
258 << " action first set to [" << func.action << ']'
261 // When not cancel or meta-fake, do the normal lookup.
262 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
263 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
264 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
265 // remove Caps Lock and Mod2 as a modifiers
266 func = keyseq.addkey(keysym, (state | meta_fake_bit));
267 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
268 << "action now set to ["
269 << func.action << ']' << endl;
272 // Dont remove this unless you know what you are doing.
273 meta_fake_bit = key_modifier::none;
275 // Can this happen now ?
276 if (func.action == LFUN_NOACTION) {
277 func = FuncRequest(LFUN_PREFIX);
280 if (lyxerr.debugging(Debug::KEY)) {
281 lyxerr << BOOST_CURRENT_FUNCTION
283 << func.action << "]["
284 << keyseq.print() << ']'
288 // already here we know if it any point in going further
289 // why not return already here if action == -1 and
290 // num_bytes == 0? (Lgb)
292 if (keyseq.length() > 1) {
293 owner->message(keyseq.print());
297 // Maybe user can only reach the key via holding down shift.
298 // Let's see. But only if shift is the only modifier
299 if (func.action == LFUN_UNKNOWN_ACTION &&
300 state == key_modifier::shift) {
301 lyxerr[Debug::KEY] << "Trying without shift" << endl;
302 func = keyseq.addkey(keysym, key_modifier::none);
303 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
306 if (func.action == LFUN_UNKNOWN_ACTION) {
307 // Hmm, we didn't match any of the keysequences. See
308 // if it's normal insertable text not already covered
310 if (keysym->isText() && keyseq.length() == 1) {
311 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
312 func = FuncRequest(LFUN_SELFINSERT,
313 FuncRequest::KEYBOARD);
315 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
316 owner->message(_("Unknown function."));
321 if (func.action == LFUN_SELFINSERT) {
322 if (encoded_last_key != 0) {
323 string const arg(1, encoded_last_key);
324 dispatch(FuncRequest(LFUN_SELFINSERT, arg,
325 FuncRequest::KEYBOARD));
327 << "SelfInsert arg[`" << arg << "']" << endl;
335 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
337 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
339 LCursor & cur = view()->cursor();
341 /* In LyX/Mac, when a dialog is open, the menus of the
342 application can still be accessed without giving focus to
343 the main window. In this case, we want to disable the menu
344 entries that are buffer-related.
346 Note that this code is not perfect, as bug 1941 attests:
347 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
350 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
353 buf = owner->buffer();
355 if (cmd.action == LFUN_NOACTION) {
356 flag.message(N_("Nothing to do"));
361 switch (cmd.action) {
362 case LFUN_UNKNOWN_ACTION:
363 #ifndef HAVE_LIBAIKSAURUS
364 case LFUN_THESAURUS_ENTRY:
370 flag |= lyx_gui::getStatus(cmd);
373 if (flag.unknown()) {
374 flag.message(N_("Unknown action"));
378 if (!flag.enabled()) {
379 if (flag.message().empty())
380 flag.message(N_("Command disabled"));
384 // Check whether we need a buffer
385 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
387 flag.message(N_("Command not allowed with"
388 "out any document open"));
393 // I would really like to avoid having this switch and rather try to
394 // encode this in the function itself.
395 // -- And I'd rather let an inset decide which LFUNs it is willing
396 // to handle (Andre')
398 switch (cmd.action) {
399 case LFUN_TOOLTIPS_TOGGLE:
400 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
403 case LFUN_READ_ONLY_TOGGLE:
404 flag.setOnOff(buf->isReadonly());
407 case LFUN_SWITCHBUFFER:
408 // toggle on the current buffer, but do not toggle off
409 // the other ones (is that a good idea?)
410 if (cmd.argument == buf->fileName())
415 enable = cmd.argument == "custom"
416 || Exporter::isExportable(*buf, cmd.argument);
420 enable = buf->isLatex() && lyxrc.chktex_command != "none";
424 enable = Exporter::isExportable(*buf, "program");
427 case LFUN_LAYOUT_TABULAR:
428 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
432 case LFUN_LAYOUT_PARAGRAPH:
433 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
436 case LFUN_VC_REGISTER:
437 enable = !buf->lyxvc().inUse();
439 case LFUN_VC_CHECKIN:
440 enable = buf->lyxvc().inUse() && !buf->isReadonly();
442 case LFUN_VC_CHECKOUT:
443 enable = buf->lyxvc().inUse() && buf->isReadonly();
447 enable = buf->lyxvc().inUse();
449 case LFUN_MENURELOAD:
450 enable = !buf->isUnnamed() && !buf->isClean();
453 case LFUN_INSET_SETTINGS: {
457 InsetBase::Code code = cur.inset().lyxCode();
459 case InsetBase::TABULAR_CODE:
460 enable = cmd.argument == "tabular";
462 case InsetBase::ERT_CODE:
463 enable = cmd.argument == "ert";
465 case InsetBase::FLOAT_CODE:
466 enable = cmd.argument == "float";
468 case InsetBase::WRAP_CODE:
469 enable = cmd.argument == "wrap";
471 case InsetBase::NOTE_CODE:
472 enable = cmd.argument == "note";
474 case InsetBase::BRANCH_CODE:
475 enable = cmd.argument == "branch";
477 case InsetBase::BOX_CODE:
478 enable = cmd.argument == "box";
486 case LFUN_INSET_APPLY: {
487 string const name = cmd.getArg(0);
488 InsetBase * inset = owner->getDialogs().getOpenInset(name);
490 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
492 bool const success = inset->getStatus(cur, fr, fs);
493 // Every inset is supposed to handle this
494 BOOST_ASSERT(success);
497 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
498 flag |= getStatus(fr);
500 enable = flag.enabled();
504 case LFUN_DIALOG_SHOW: {
505 string const name = cmd.getArg(0);
507 enable = name == "aboutlyx"
511 || name == "texinfo";
512 else if (name == "print")
513 enable = Exporter::isExportable(*buf, "dvi")
514 && lyxrc.print_command != "none";
515 else if (name == "character" || name == "mathpanel")
516 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
517 else if (name == "latexlog")
518 enable = isFileReadable(buf->getLogName().second);
519 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
520 else if (name == "spellchecker")
523 else if (name == "vclog")
524 enable = buf->lyxvc().inUse();
528 case LFUN_DIALOG_SHOW_NEW_INSET:
529 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
532 case LFUN_DIALOG_UPDATE: {
533 string const name = cmd.getArg(0);
535 enable = name == "prefs";
539 case LFUN_INSERT_CITATION: {
540 FuncRequest fr(LFUN_INSET_INSERT, "citation");
541 enable = getStatus(fr).enabled();
545 case LFUN_MENUWRITE: {
546 enable = view()->buffer()->isUnnamed()
547 || !view()->buffer()->isClean();
551 // this one is difficult to get right. As a half-baked
552 // solution, we consider only the first action of the sequence
553 case LFUN_SEQUENCE: {
554 // argument contains ';'-terminated commands
555 string const firstcmd = token(cmd.argument, ';', 0);
556 FuncRequest func(lyxaction.lookupFunc(firstcmd));
557 func.origin = cmd.origin;
558 flag = getStatus(func);
562 case LFUN_MENUNEWTMPLT:
563 case LFUN_WORDFINDFORWARD:
564 case LFUN_WORDFINDBACKWARD:
566 case LFUN_EXEC_COMMAND:
569 case LFUN_CLOSEBUFFER:
577 case LFUN_RECONFIGURE:
581 case LFUN_DROP_LAYOUTS_CHOICE:
582 case LFUN_MENU_OPEN_BY_NAME:
585 case LFUN_GOTOFILEROW:
586 case LFUN_DIALOG_SHOW_NEXT_INSET:
587 case LFUN_DIALOG_HIDE:
588 case LFUN_DIALOG_DISCONNECT_INSET:
590 case LFUN_TOGGLECURSORFOLLOW:
594 case LFUN_KMAP_TOGGLE:
596 case LFUN_EXPORT_CUSTOM:
598 case LFUN_SAVEPREFERENCES:
599 case LFUN_SCREEN_FONT_UPDATE:
602 case LFUN_EXTERNAL_EDIT:
603 case LFUN_GRAPHICS_EDIT:
604 case LFUN_ALL_INSETS_TOGGLE:
605 case LFUN_LANGUAGE_BUFFER:
606 case LFUN_TEXTCLASS_APPLY:
607 case LFUN_TEXTCLASS_LOAD:
608 case LFUN_SAVE_AS_DEFAULT:
609 case LFUN_BUFFERPARAMS_APPLY:
610 case LFUN_LYXRC_APPLY:
611 case LFUN_NEXTBUFFER:
612 case LFUN_PREVIOUSBUFFER:
613 // these are handled in our dispatch()
618 if (!::getStatus(cur, cmd, flag))
619 flag = view()->getStatus(cmd);
625 // Can we use a readonly buffer?
626 if (buf && buf->isReadonly()
627 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
628 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
629 flag.message(N_("Document is read-only"));
633 // Are we in a DELETED change-tracking region?
634 if (buf && buf->params().tracking_changes
635 && lookupChange(cur, true) == Change::DELETED
636 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
637 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
638 flag.message(N_("This portion of the document is deleted."));
642 // the default error message if we disable the command
643 if (!flag.enabled() && flag.message().empty())
644 flag.message(N_("Command disabled"));
652 bool ensureBufferClean(BufferView * bv)
654 Buffer & buf = *bv->buffer();
658 string const file = makeDisplayPath(buf.fileName(), 30);
659 string text = bformat(_("The document %1$s has unsaved "
660 "changes.\n\nDo you want to save "
661 "the document?"), file);
662 int const ret = Alert::prompt(_("Save changed document?"),
663 text, 0, 1, _("&Save"),
667 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
669 return buf.isClean();
673 void showPrintError(string const & name)
675 string str = bformat(_("Could not print the document %1$s.\n"
676 "Check that your printer is set up correctly."),
677 makeDisplayPath(name, 50));
678 Alert::error(_("Print document failed"), str);
682 void loadTextclass(string const & name)
684 std::pair<bool, lyx::textclass_type> const tc_pair =
685 textclasslist.numberOfClass(name);
687 if (!tc_pair.first) {
688 lyxerr << "Document class \"" << name
689 << "\" does not exist."
694 lyx::textclass_type const tc = tc_pair.second;
696 if (!textclasslist[tc].load()) {
697 string s = bformat(_("The document could not be converted\n"
698 "into the document class %1$s."),
699 textclasslist[tc].name());
700 Alert::error(_("Could not change class"), s);
705 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
710 void LyXFunc::dispatch(FuncRequest const & cmd)
712 BOOST_ASSERT(view());
713 string const argument = cmd.argument;
714 kb_action const action = cmd.action;
716 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
717 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
719 // we have not done anything wrong yet.
721 dispatch_buffer.erase();
725 FuncStatus const flag = getStatus(cmd);
726 if (!flag.enabled()) {
727 // We cannot use this function here
728 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
729 << lyxaction.getActionName(action)
730 << " [" << action << "] is disabled at this location"
732 setErrorMessage(flag.message());
735 if (view()->available())
736 view()->hideCursor();
740 case LFUN_WORDFINDFORWARD:
741 case LFUN_WORDFINDBACKWARD: {
742 static string last_search;
743 string searched_string;
745 if (!argument.empty()) {
746 last_search = argument;
747 searched_string = argument;
749 searched_string = last_search;
752 if (searched_string.empty())
755 bool const fw = action == LFUN_WORDFINDFORWARD;
757 lyx::find::find2string(searched_string, true, false, fw);
758 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
763 owner->message(keyseq.printOptions());
766 case LFUN_EXEC_COMMAND:
767 owner->getToolbars().display("minibuffer", true);
768 owner->focus_command_buffer();
773 meta_fake_bit = key_modifier::none;
774 if (view()->available())
775 // cancel any selection
776 dispatch(FuncRequest(LFUN_MARK_OFF));
777 setMessage(N_("Cancel"));
781 meta_fake_bit = key_modifier::alt;
782 setMessage(keyseq.print());
785 case LFUN_READ_ONLY_TOGGLE:
786 if (owner->buffer()->lyxvc().inUse())
787 owner->buffer()->lyxvc().toggleReadOnly();
789 owner->buffer()->setReadonly(
790 !owner->buffer()->isReadonly());
793 // --- Menus -----------------------------------------------
795 menuNew(argument, false);
798 case LFUN_MENUNEWTMPLT:
799 menuNew(argument, true);
802 case LFUN_CLOSEBUFFER:
807 if (!owner->buffer()->isUnnamed()) {
808 string const str = bformat(_("Saving document %1$s..."),
809 makeDisplayPath(owner->buffer()->fileName()));
811 menuWrite(owner->buffer());
812 owner->message(str + _(" done."));
814 writeAs(owner->buffer());
818 writeAs(owner->buffer(), argument);
821 case LFUN_MENURELOAD: {
822 string const file = makeDisplayPath(view()->buffer()->fileName(), 20);
823 string text = bformat(_("Any changes will be lost. Are you sure "
824 "you want to revert to the saved version of the document %1$s?"), file);
825 int const ret = Alert::prompt(_("Revert to saved document?"),
826 text, 0, 1, _("&Revert"), _("&Cancel"));
834 Exporter::Export(owner->buffer(), argument, true);
835 view()->showErrorList(bufferFormat(*owner->buffer()));
839 Exporter::preview(owner->buffer(), argument);
840 view()->showErrorList(bufferFormat(*owner->buffer()));
844 Exporter::Export(owner->buffer(), "program", true);
845 view()->showErrorList(_("Build"));
849 owner->buffer()->runChktex();
850 view()->showErrorList(_("ChkTeX"));
854 if (argument == "custom")
855 owner->getDialogs().show("sendto");
857 Exporter::Export(owner->buffer(), argument, false);
858 view()->showErrorList(bufferFormat(*owner->buffer()));
862 case LFUN_EXPORT_CUSTOM: {
864 string command = split(argument, format_name, ' ');
865 Format const * format = formats.getFormat(format_name);
867 lyxerr << "Format \"" << format_name
868 << "\" not recognized!"
873 Buffer * buffer = owner->buffer();
875 // The name of the file created by the conversion process
878 // Output to filename
879 if (format->name() == "lyx") {
880 string const latexname =
881 buffer->getLatexName(false);
882 filename = changeExtension(latexname,
883 format->extension());
884 filename = addName(buffer->temppath(), filename);
886 if (!buffer->writeFile(filename))
890 Exporter::Export(buffer, format_name, true,
894 // Substitute $$FName for filename
895 if (!contains(command, "$$FName"))
896 command = "( " + command + " ) < $$FName";
897 command = subst(command, "$$FName", filename);
899 // Execute the command in the background
901 call.startscript(Systemcall::DontWait, command);
908 string command = split(split(argument, target, ' '),
912 || target_name.empty()
913 || command.empty()) {
914 lyxerr << "Unable to parse \""
915 << argument << '"' << std::endl;
918 if (target != "printer" && target != "file") {
919 lyxerr << "Unrecognized target \""
920 << target << '"' << std::endl;
924 Buffer * buffer = owner->buffer();
926 if (!Exporter::Export(buffer, "dvi", true)) {
927 showPrintError(buffer->fileName());
931 // Push directory path.
932 string const path = buffer->temppath();
935 // there are three cases here:
936 // 1. we print to a file
937 // 2. we print directly to a printer
938 // 3. we print using a spool command (print to file first)
941 string const dviname =
942 changeExtension(buffer->getLatexName(true),
945 if (target == "printer") {
946 if (!lyxrc.print_spool_command.empty()) {
947 // case 3: print using a spool
948 string const psname =
949 changeExtension(dviname,".ps");
950 command += lyxrc.print_to_file
953 + quoteName(dviname);
956 lyxrc.print_spool_command +' ';
957 if (target_name != "default") {
958 command2 += lyxrc.print_spool_printerprefix
962 command2 += quoteName(psname);
964 // If successful, then spool command
965 res = one.startscript(
970 res = one.startscript(
971 Systemcall::DontWait,
974 // case 2: print directly to a printer
975 res = one.startscript(
976 Systemcall::DontWait,
977 command + quoteName(dviname));
981 // case 1: print to a file
982 command += lyxrc.print_to_file
983 + quoteName(makeAbsPath(target_name,
986 + quoteName(dviname);
987 res = one.startscript(Systemcall::DontWait,
992 showPrintError(buffer->fileName());
1001 if (view()->available()) {
1002 // save cursor Position for opened files to .lyx/session
1003 LyX::ref().session().saveFilePosition(owner->buffer()->fileName(),
1004 boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1005 // save opened file name to .lyx/session
1006 LyX::ref().session().setLastOpenedFiles( bufferlist.getFileNames());
1007 // save bookmarks to .lyx/session
1008 view()->saveSavedPositions();
1010 quitLyX(argument == "force");
1013 case LFUN_TOCVIEW: {
1014 InsetCommandParams p("tableofcontents");
1015 string const data = InsetCommandMailer::params2string("toc", p);
1016 owner->getDialogs().show("toc", data, 0);
1024 case LFUN_RECONFIGURE:
1025 reconfigure(view());
1028 case LFUN_HELP_OPEN: {
1029 string const arg = argument;
1031 setErrorMessage(N_("Missing argument"));
1034 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1035 if (fname.empty()) {
1036 lyxerr << "LyX: unable to find documentation file `"
1037 << arg << "'. Bad installation?" << endl;
1040 owner->message(bformat(_("Opening help file %1$s..."),
1041 makeDisplayPath(fname)));
1042 view()->loadLyXFile(fname, false);
1046 // --- version control -------------------------------
1047 case LFUN_VC_REGISTER:
1048 if (!ensureBufferClean(view()))
1050 if (!owner->buffer()->lyxvc().inUse()) {
1051 owner->buffer()->lyxvc().registrer();
1056 case LFUN_VC_CHECKIN:
1057 if (!ensureBufferClean(view()))
1059 if (owner->buffer()->lyxvc().inUse()
1060 && !owner->buffer()->isReadonly()) {
1061 owner->buffer()->lyxvc().checkIn();
1066 case LFUN_VC_CHECKOUT:
1067 if (!ensureBufferClean(view()))
1069 if (owner->buffer()->lyxvc().inUse()
1070 && owner->buffer()->isReadonly()) {
1071 owner->buffer()->lyxvc().checkOut();
1076 case LFUN_VC_REVERT:
1077 owner->buffer()->lyxvc().revert();
1082 owner->buffer()->lyxvc().undoLast();
1086 // --- buffers ----------------------------------------
1087 case LFUN_SWITCHBUFFER:
1088 view()->setBuffer(bufferlist.getBuffer(argument));
1091 case LFUN_NEXTBUFFER:
1092 view()->setBuffer(bufferlist.next(view()->buffer()));
1095 case LFUN_PREVIOUSBUFFER:
1096 view()->setBuffer(bufferlist.previous(view()->buffer()));
1100 newFile(view(), argument);
1103 case LFUN_FILE_OPEN:
1107 case LFUN_DROP_LAYOUTS_CHOICE:
1108 owner->getToolbars().openLayoutList();
1111 case LFUN_MENU_OPEN_BY_NAME:
1112 owner->getMenubar().openByName(argument);
1115 // --- lyxserver commands ----------------------------
1117 setMessage(owner->buffer()->fileName());
1118 lyxerr[Debug::INFO] << "FNAME["
1119 << owner->buffer()->fileName()
1124 dispatch_buffer = keyseq.print();
1125 lyxserver->notifyClient(dispatch_buffer);
1128 case LFUN_GOTOFILEROW: {
1131 istringstream is(argument);
1132 is >> file_name >> row;
1133 if (prefixIs(file_name, package().temp_dir())) {
1134 // Needed by inverse dvi search. If it is a file
1135 // in tmpdir, call the apropriated function
1136 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1138 // Must replace extension of the file to be .lyx
1139 // and get full path
1140 string const s = changeExtension(file_name, ".lyx");
1141 // Either change buffer or load the file
1142 if (bufferlist.exists(s)) {
1143 view()->setBuffer(bufferlist.getBuffer(s));
1145 view()->loadLyXFile(s);
1149 view()->setCursorFromRow(row);
1152 // see BufferView_pimpl::center()
1153 view()->updateScrollbar();
1157 case LFUN_DIALOG_SHOW: {
1158 string const name = cmd.getArg(0);
1159 string data = trim(cmd.argument.substr(name.size()));
1161 if (name == "character") {
1162 data = freefont2string();
1164 owner->getDialogs().show("character", data);
1167 else if (name == "latexlog") {
1168 pair<Buffer::LogType, string> const logfile =
1169 owner->buffer()->getLogName();
1170 switch (logfile.first) {
1171 case Buffer::latexlog:
1174 case Buffer::buildlog:
1178 data += logfile.second;
1179 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);
1187 owner->getDialogs().show(name, data);
1191 case LFUN_DIALOG_SHOW_NEW_INSET: {
1192 string const name = cmd.getArg(0);
1193 string data = trim(cmd.argument.substr(name.size()));
1194 if (name == "bibitem" ||
1201 InsetCommandParams p(name);
1202 data = InsetCommandMailer::params2string(name, p);
1203 } else if (name == "include") {
1204 InsetCommandParams p(data);
1205 data = InsetIncludeMailer::params2string(p);
1206 } else if (name == "box") {
1207 // \c data == "Boxed" || "Frameless" etc
1208 InsetBoxParams p(data);
1209 data = InsetBoxMailer::params2string(p);
1210 } else if (name == "branch") {
1211 InsetBranchParams p;
1212 data = InsetBranchMailer::params2string(p);
1213 } else if (name == "citation") {
1214 InsetCommandParams p("cite");
1215 data = InsetCommandMailer::params2string(name, p);
1216 } else if (name == "ert") {
1217 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1218 } else if (name == "external") {
1219 InsetExternalParams p;
1220 Buffer const & buffer = *owner->buffer();
1221 data = InsetExternalMailer::params2string(p, buffer);
1222 } else if (name == "float") {
1224 data = InsetFloatMailer::params2string(p);
1225 } else if (name == "graphics") {
1226 InsetGraphicsParams p;
1227 Buffer const & buffer = *owner->buffer();
1228 data = InsetGraphicsMailer::params2string(p, buffer);
1229 } else if (name == "note") {
1231 data = InsetNoteMailer::params2string(p);
1232 } else if (name == "vspace") {
1234 data = InsetVSpaceMailer::params2string(space);
1235 } else if (name == "wrap") {
1237 data = InsetWrapMailer::params2string(p);
1239 owner->getDialogs().show(name, data, 0);
1243 case LFUN_DIALOG_SHOW_NEXT_INSET:
1246 case LFUN_DIALOG_UPDATE: {
1247 string const & name = argument;
1248 // Can only update a dialog connected to an existing inset
1249 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1251 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1252 inset->dispatch(view()->cursor(), fr);
1253 } else if (name == "paragraph") {
1254 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1255 } else if (name == "prefs") {
1256 owner->getDialogs().update(name, string());
1261 case LFUN_DIALOG_HIDE:
1262 Dialogs::hide(argument, 0);
1265 case LFUN_DIALOG_DISCONNECT_INSET:
1266 owner->getDialogs().disconnect(argument);
1270 case LFUN_INSERT_CITATION: {
1271 if (!argument.empty()) {
1272 // we can have one optional argument, delimited by '|'
1273 // citation-insert <key>|<text_before>
1274 // this should be enhanced to also support text_after
1275 // and citation style
1276 string arg = argument;
1278 if (contains(argument, "|")) {
1279 arg = token(argument, '|', 0);
1280 opt1 = '[' + token(argument, '|', 1) + ']';
1282 std::ostringstream os;
1283 os << "citation LatexCommand\n"
1284 << "\\cite" << opt1 << "{" << arg << "}\n"
1286 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1289 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1293 case LFUN_CHILDOPEN: {
1294 string const filename =
1295 makeAbsPath(argument, owner->buffer()->filePath());
1296 setMessage(N_("Opening child document ") +
1297 makeDisplayPath(filename) + "...");
1298 view()->savePosition(0);
1299 string const parentfilename = owner->buffer()->fileName();
1300 if (bufferlist.exists(filename))
1301 view()->setBuffer(bufferlist.getBuffer(filename));
1303 view()->loadLyXFile(filename);
1304 // Set the parent name of the child document.
1305 // This makes insertion of citations and references in the child work,
1306 // when the target is in the parent or another child document.
1307 owner->buffer()->setParentName(parentfilename);
1311 case LFUN_TOGGLECURSORFOLLOW:
1312 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1316 owner->getIntl().keyMapOn(false);
1319 case LFUN_KMAP_PRIM:
1320 owner->getIntl().keyMapPrim();
1324 owner->getIntl().keyMapSec();
1327 case LFUN_KMAP_TOGGLE:
1328 owner->getIntl().toggleKeyMap();
1334 string rest = split(argument, countstr, ' ');
1335 istringstream is(countstr);
1338 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1339 for (int i = 0; i < count; ++i)
1340 dispatch(lyxaction.lookupFunc(rest));
1344 case LFUN_SEQUENCE: {
1345 // argument contains ';'-terminated commands
1346 string arg = argument;
1347 while (!arg.empty()) {
1349 arg = split(arg, first, ';');
1350 FuncRequest func(lyxaction.lookupFunc(first));
1351 func.origin = cmd.origin;
1357 case LFUN_SAVEPREFERENCES: {
1358 Path p(package().user_support());
1359 lyxrc.write("preferences", false);
1363 case LFUN_SCREEN_FONT_UPDATE:
1364 // handle the screen font changes.
1365 lyxrc.set_font_norm_type();
1366 lyx_gui::update_fonts();
1367 // All visible buffers will need resize
1371 case LFUN_SET_COLOR: {
1373 string const x11_name = split(argument, lyx_name, ' ');
1374 if (lyx_name.empty() || x11_name.empty()) {
1375 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1380 bool const graphicsbg_changed =
1381 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1382 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1384 if (!lcolor.setColor(lyx_name, x11_name)) {
1386 bformat(_("Set-color \"%1$s\" failed "
1387 "- color is undefined or "
1388 "may not be redefined"), lyx_name));
1392 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1394 if (graphicsbg_changed) {
1395 #ifdef WITH_WARNINGS
1396 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1399 lyx::graphics::GCache::get().changeDisplay(true);
1406 owner->message(argument);
1409 case LFUN_TOOLTIPS_TOGGLE:
1410 owner->getDialogs().toggleTooltips();
1413 case LFUN_EXTERNAL_EDIT: {
1414 FuncRequest fr(action, argument);
1415 InsetExternal().dispatch(view()->cursor(), fr);
1419 case LFUN_GRAPHICS_EDIT: {
1420 FuncRequest fr(action, argument);
1421 InsetGraphics().dispatch(view()->cursor(), fr);
1425 case LFUN_INSET_APPLY: {
1426 string const name = cmd.getArg(0);
1427 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1429 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1430 inset->dispatch(view()->cursor(), fr);
1432 FuncRequest fr(LFUN_INSET_INSERT, argument);
1435 // ideally, the update flag should be set by the insets,
1436 // but this is not possible currently
1441 case LFUN_ALL_INSETS_TOGGLE: {
1443 string const name = split(argument, action, ' ');
1444 InsetBase::Code const inset_code =
1445 InsetBase::translate(name);
1447 LCursor & cur = view()->cursor();
1448 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1450 InsetBase & inset = owner->buffer()->inset();
1451 InsetIterator it = inset_iterator_begin(inset);
1452 InsetIterator const end = inset_iterator_end(inset);
1453 for (; it != end; ++it) {
1454 if (inset_code == InsetBase::NO_CODE
1455 || inset_code == it->lyxCode()) {
1456 LCursor tmpcur = cur;
1457 tmpcur.pushLeft(*it);
1458 it->dispatch(tmpcur, fr);
1465 case LFUN_LANGUAGE_BUFFER: {
1466 Buffer & buffer = *owner->buffer();
1467 Language const * oldL = buffer.params().language;
1468 Language const * newL = languages.getLanguage(argument);
1469 if (!newL || oldL == newL)
1472 if (oldL->rightToLeft() == newL->rightToLeft()
1473 && !buffer.isMultiLingual())
1474 buffer.changeLanguage(oldL, newL);
1476 buffer.updateDocLang(newL);
1480 case LFUN_SAVE_AS_DEFAULT: {
1481 string const fname =
1482 addName(addPath(package().user_support(), "templates/"),
1484 Buffer defaults(fname);
1486 istringstream ss(argument);
1489 int const unknown_tokens = defaults.readHeader(lex);
1491 if (unknown_tokens != 0) {
1492 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1493 << unknown_tokens << " unknown token"
1494 << (unknown_tokens == 1 ? "" : "s")
1498 if (defaults.writeFile(defaults.fileName()))
1499 setMessage(_("Document defaults saved in ")
1500 + makeDisplayPath(fname));
1502 setErrorMessage(_("Unable to save document defaults"));
1506 case LFUN_BUFFERPARAMS_APPLY: {
1507 biblio::CiteEngine const engine =
1508 owner->buffer()->params().cite_engine;
1510 istringstream ss(argument);
1513 int const unknown_tokens =
1514 owner->buffer()->readHeader(lex);
1516 if (unknown_tokens != 0) {
1517 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1518 << unknown_tokens << " unknown token"
1519 << (unknown_tokens == 1 ? "" : "s")
1522 if (engine == owner->buffer()->params().cite_engine)
1525 LCursor & cur = view()->cursor();
1526 FuncRequest fr(LFUN_INSET_REFRESH);
1528 InsetBase & inset = owner->buffer()->inset();
1529 InsetIterator it = inset_iterator_begin(inset);
1530 InsetIterator const end = inset_iterator_end(inset);
1531 for (; it != end; ++it)
1532 if (it->lyxCode() == InsetBase::CITE_CODE)
1533 it->dispatch(cur, fr);
1537 case LFUN_TEXTCLASS_APPLY: {
1538 Buffer * buffer = owner->buffer();
1540 lyx::textclass_type const old_class =
1541 buffer->params().textclass;
1543 loadTextclass(argument);
1545 std::pair<bool, lyx::textclass_type> const tc_pair =
1546 textclasslist.numberOfClass(argument);
1551 lyx::textclass_type const new_class = tc_pair.second;
1552 if (old_class == new_class)
1556 owner->message(_("Converting document to new document class..."));
1557 recordUndoFullDocument(view());
1558 buffer->params().textclass = new_class;
1559 StableDocIterator backcur(view()->cursor());
1561 lyx::cap::switchBetweenClasses(
1562 old_class, new_class,
1563 buffer->paragraphs(), el);
1565 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1566 bufferErrors(*buffer, el);
1567 view()->showErrorList(_("Class switch"));
1568 updateCounters(*buffer);
1573 case LFUN_TEXTCLASS_LOAD:
1574 loadTextclass(argument);
1577 case LFUN_LYXRC_APPLY: {
1578 LyXRC const lyxrc_orig = lyxrc;
1580 istringstream ss(argument);
1581 bool const success = lyxrc.read(ss) == 0;
1584 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1585 << "Unable to read lyxrc data"
1590 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1595 view()->cursor().dispatch(cmd);
1596 update |= view()->cursor().result().update();
1597 if (!view()->cursor().result().dispatched())
1598 update |= view()->dispatch(cmd);
1603 if (view()->available()) {
1604 // Redraw screen unless explicitly told otherwise.
1605 // This also initializes the position cache for all insets
1606 // in (at least partially) visible top-level paragraphs.
1608 view()->update(Update::FitCursor | Update::Force);
1610 view()->update(Update::FitCursor);
1612 // if we executed a mutating lfun, mark the buffer as dirty
1614 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1615 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1616 view()->buffer()->markDirty();
1619 if (view()->cursor().inTexted()) {
1620 view()->owner()->updateLayoutChoice();
1623 sendDispatchMessage(_(getMessage()), cmd);
1627 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1629 /* When an action did not originate from the UI/kbd, it makes
1630 * sense to avoid updating the GUI. It turns out that this
1631 * fixes bug 1941, for reasons that are described here:
1632 * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1634 if (cmd.origin != FuncRequest::INTERNAL) {
1635 owner->updateMenubar();
1636 owner->updateToolbars();
1639 const bool verbose = (cmd.origin == FuncRequest::UI
1640 || cmd.origin == FuncRequest::COMMANDBUFFER);
1642 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1643 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1645 owner->message(msg);
1649 string dispatch_msg = msg;
1650 if (!dispatch_msg.empty())
1651 dispatch_msg += ' ';
1653 string comname = lyxaction.getActionName(cmd.action);
1655 bool argsadded = false;
1657 if (!cmd.argument.empty()) {
1658 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1659 comname += ' ' + cmd.argument;
1664 string const shortcuts = toplevel_keymap->printbindings(cmd);
1666 if (!shortcuts.empty())
1667 comname += ": " + shortcuts;
1668 else if (!argsadded && !cmd.argument.empty())
1669 comname += ' ' + cmd.argument;
1671 if (!comname.empty()) {
1672 comname = rtrim(comname);
1673 dispatch_msg += '(' + rtrim(comname) + ')';
1676 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1677 if (!dispatch_msg.empty())
1678 owner->message(dispatch_msg);
1682 void LyXFunc::setupLocalKeymap()
1684 keyseq.stdmap = toplevel_keymap.get();
1685 keyseq.curmap = toplevel_keymap.get();
1686 cancel_meta_seq.stdmap = toplevel_keymap.get();
1687 cancel_meta_seq.curmap = toplevel_keymap.get();
1691 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1693 string initpath = lyxrc.document_path;
1694 string filename(name);
1696 if (view()->available()) {
1697 string const trypath = owner->buffer()->filePath();
1698 // If directory is writeable, use this as default.
1699 if (isDirWriteable(trypath))
1703 static int newfile_number;
1705 if (filename.empty()) {
1706 filename = addName(lyxrc.document_path,
1707 "newfile" + convert<string>(++newfile_number) + ".lyx");
1708 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1710 filename = addName(lyxrc.document_path,
1711 "newfile" + convert<string>(newfile_number) +
1716 // The template stuff
1719 FileDialog fileDlg(_("Select template file"),
1720 LFUN_SELECT_FILE_SYNC,
1721 make_pair(string(_("Documents|#o#O")),
1722 string(lyxrc.document_path)),
1723 make_pair(string(_("Templates|#T#t")),
1724 string(lyxrc.template_path)));
1726 FileDialog::Result result =
1727 fileDlg.open(lyxrc.template_path,
1728 FileFilterList(_("LyX Documents (*.lyx)")),
1731 if (result.first == FileDialog::Later)
1733 if (result.second.empty())
1735 templname = result.second;
1738 view()->newFile(filename, templname, !name.empty());
1742 void LyXFunc::open(string const & fname)
1744 string initpath = lyxrc.document_path;
1746 if (view()->available()) {
1747 string const trypath = owner->buffer()->filePath();
1748 // If directory is writeable, use this as default.
1749 if (isDirWriteable(trypath))
1755 if (fname.empty()) {
1756 FileDialog fileDlg(_("Select document to open"),
1758 make_pair(string(_("Documents|#o#O")),
1759 string(lyxrc.document_path)),
1760 make_pair(string(_("Examples|#E#e")),
1761 string(addPath(package().system_support(), "examples"))));
1763 FileDialog::Result result =
1764 fileDlg.open(initpath,
1765 FileFilterList(_("LyX Documents (*.lyx)")),
1768 if (result.first == FileDialog::Later)
1771 filename = result.second;
1773 // check selected filename
1774 if (filename.empty()) {
1775 owner->message(_("Canceled."));
1781 // get absolute path of file and add ".lyx" to the filename if
1783 string const fullpath = fileSearch(string(), filename, "lyx");
1784 if (!fullpath.empty()) {
1785 filename = fullpath;
1788 string const disp_fn(makeDisplayPath(filename));
1790 // if the file doesn't exist, let the user create one
1791 if (!fs::exists(filename)) {
1792 // the user specifically chose this name. Believe them.
1793 view()->newFile(filename, "", true);
1797 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1800 if (view()->loadLyXFile(filename)) {
1801 str2 = bformat(_("Document %1$s opened."), disp_fn);
1803 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1805 owner->message(str2);
1809 void LyXFunc::doImport(string const & argument)
1812 string filename = split(argument, format, ' ');
1814 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1815 << " file: " << filename << endl;
1817 // need user interaction
1818 if (filename.empty()) {
1819 string initpath = lyxrc.document_path;
1821 if (view()->available()) {
1822 string const trypath = owner->buffer()->filePath();
1823 // If directory is writeable, use this as default.
1824 if (isDirWriteable(trypath))
1828 string const text = bformat(_("Select %1$s file to import"),
1829 formats.prettyName(format));
1831 FileDialog fileDlg(text,
1833 make_pair(string(_("Documents|#o#O")),
1834 string(lyxrc.document_path)),
1835 make_pair(string(_("Examples|#E#e")),
1836 string(addPath(package().system_support(), "examples"))));
1838 string const filter = formats.prettyName(format)
1839 + " (*." + formats.extension(format) + ')';
1841 FileDialog::Result result =
1842 fileDlg.open(initpath,
1843 FileFilterList(filter),
1846 if (result.first == FileDialog::Later)
1849 filename = result.second;
1851 // check selected filename
1852 if (filename.empty())
1853 owner->message(_("Canceled."));
1856 if (filename.empty())
1859 // get absolute path of file
1860 filename = makeAbsPath(filename);
1862 string const lyxfile = changeExtension(filename, ".lyx");
1864 // Check if the document already is open
1865 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1866 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1867 owner->message(_("Canceled."));
1872 // if the file exists already, and we didn't do
1873 // -i lyx thefile.lyx, warn
1874 if (fs::exists(lyxfile) && filename != lyxfile) {
1875 string const file = makeDisplayPath(lyxfile, 30);
1877 string text = bformat(_("The document %1$s already exists.\n\n"
1878 "Do you want to over-write that document?"), file);
1879 int const ret = Alert::prompt(_("Over-write document?"),
1880 text, 0, 1, _("&Over-write"), _("&Cancel"));
1883 owner->message(_("Canceled."));
1888 Importer::Import(owner, filename, format);
1892 void LyXFunc::closeBuffer()
1894 // save current cursor position
1895 LyX::ref().session().saveFilePosition(owner->buffer()->fileName(),
1896 boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1897 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1898 if (bufferlist.empty()) {
1899 // need this otherwise SEGV may occur while
1900 // trying to set variables that don't exist
1901 // since there's no current buffer
1902 owner->getDialogs().hideBufferDependent();
1904 view()->setBuffer(bufferlist.first());
1910 // Each "owner" should have it's own message method. lyxview and
1911 // the minibuffer would use the minibuffer, but lyxserver would
1912 // send an ERROR signal to its client. Alejandro 970603
1913 // This function is bit problematic when it comes to NLS, to make the
1914 // lyx servers client be language indepenent we must not translate
1915 // strings sent to this func.
1916 void LyXFunc::setErrorMessage(string const & m) const
1918 dispatch_buffer = m;
1923 void LyXFunc::setMessage(string const & m) const
1925 dispatch_buffer = m;
1929 string const LyXFunc::viewStatusMessage()
1931 // When meta-fake key is pressed, show the key sequence so far + "M-".
1933 return keyseq.print() + "M-";
1935 // Else, when a non-complete key sequence is pressed,
1936 // show the available options.
1937 if (keyseq.length() > 0 && !keyseq.deleted())
1938 return keyseq.printOptions();
1940 if (!view()->available())
1941 return _("Welcome to LyX!");
1943 return view()->cursor().currentState();
1947 BufferView * LyXFunc::view() const
1949 BOOST_ASSERT(owner);
1950 return owner->view().get();
1954 bool LyXFunc::wasMetaKey() const
1956 return (meta_fake_bit != key_modifier::none);
1962 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1964 // Why the switch you might ask. It is a trick to ensure that all
1965 // the elements in the LyXRCTags enum is handled. As you can see
1966 // there are no breaks at all. So it is just a huge fall-through.
1967 // The nice thing is that we will get a warning from the compiler
1968 // if we forget an element.
1969 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1971 case LyXRC::RC_ACCEPT_COMPOUND:
1972 case LyXRC::RC_ALT_LANG:
1973 case LyXRC::RC_ASCIIROFF_COMMAND:
1974 case LyXRC::RC_ASCII_LINELEN:
1975 case LyXRC::RC_AUTOREGIONDELETE:
1976 case LyXRC::RC_AUTORESET_OPTIONS:
1977 case LyXRC::RC_AUTOSAVE:
1978 case LyXRC::RC_AUTO_NUMBER:
1979 case LyXRC::RC_BACKUPDIR_PATH:
1980 case LyXRC::RC_BIBTEX_COMMAND:
1981 case LyXRC::RC_BINDFILE:
1982 case LyXRC::RC_CHECKLASTFILES:
1983 case LyXRC::RC_USELASTFILEPOS:
1984 case LyXRC::RC_LOADSESSION:
1985 case LyXRC::RC_CHKTEX_COMMAND:
1986 case LyXRC::RC_CONVERTER:
1987 case LyXRC::RC_COPIER:
1988 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1989 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1990 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1991 case LyXRC::RC_CYGWIN_PATH_FIX:
1992 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1993 namespace os = lyx::support::os;
1994 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1996 case LyXRC::RC_DATE_INSERT_FORMAT:
1997 case LyXRC::RC_DEFAULT_LANGUAGE:
1998 case LyXRC::RC_DEFAULT_PAPERSIZE:
1999 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2000 case LyXRC::RC_DISPLAY_GRAPHICS:
2001 case LyXRC::RC_DOCUMENTPATH:
2002 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2003 if (fs::exists(lyxrc_new.document_path) &&
2004 fs::is_directory(lyxrc_new.document_path)) {
2005 using lyx::support::package;
2006 package().document_dir() = lyxrc.document_path;
2009 case LyXRC::RC_ESC_CHARS:
2010 case LyXRC::RC_FONT_ENCODING:
2011 case LyXRC::RC_FORMAT:
2012 case LyXRC::RC_INDEX_COMMAND:
2013 case LyXRC::RC_INPUT:
2014 case LyXRC::RC_KBMAP:
2015 case LyXRC::RC_KBMAP_PRIMARY:
2016 case LyXRC::RC_KBMAP_SECONDARY:
2017 case LyXRC::RC_LABEL_INIT_LENGTH:
2018 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2019 case LyXRC::RC_LANGUAGE_AUTO_END:
2020 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2021 case LyXRC::RC_LANGUAGE_COMMAND_END:
2022 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2023 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2024 case LyXRC::RC_LANGUAGE_PACKAGE:
2025 case LyXRC::RC_LANGUAGE_USE_BABEL:
2026 case LyXRC::RC_MAKE_BACKUP:
2027 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2028 case LyXRC::RC_NUMLASTFILES:
2029 case LyXRC::RC_PATH_PREFIX:
2030 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2031 using lyx::support::prependEnvPath;
2032 prependEnvPath("PATH", lyxrc.path_prefix);
2034 case LyXRC::RC_PERS_DICT:
2035 case LyXRC::RC_POPUP_BOLD_FONT:
2036 case LyXRC::RC_POPUP_FONT_ENCODING:
2037 case LyXRC::RC_POPUP_NORMAL_FONT:
2038 case LyXRC::RC_PREVIEW:
2039 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2040 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2041 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2042 case LyXRC::RC_PRINTCOPIESFLAG:
2043 case LyXRC::RC_PRINTER:
2044 case LyXRC::RC_PRINTEVENPAGEFLAG:
2045 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2046 case LyXRC::RC_PRINTFILEEXTENSION:
2047 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2048 case LyXRC::RC_PRINTODDPAGEFLAG:
2049 case LyXRC::RC_PRINTPAGERANGEFLAG:
2050 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2051 case LyXRC::RC_PRINTPAPERFLAG:
2052 case LyXRC::RC_PRINTREVERSEFLAG:
2053 case LyXRC::RC_PRINTSPOOL_COMMAND:
2054 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2055 case LyXRC::RC_PRINTTOFILE:
2056 case LyXRC::RC_PRINTTOPRINTER:
2057 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2058 case LyXRC::RC_PRINT_COMMAND:
2059 case LyXRC::RC_RTL_SUPPORT:
2060 case LyXRC::RC_SCREEN_DPI:
2061 case LyXRC::RC_SCREEN_FONT_ENCODING:
2062 case LyXRC::RC_SCREEN_FONT_ROMAN:
2063 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2064 case LyXRC::RC_SCREEN_FONT_SANS:
2065 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2066 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2067 case LyXRC::RC_SCREEN_FONT_SIZES:
2068 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2069 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2070 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2071 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2072 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2073 case LyXRC::RC_SCREEN_ZOOM:
2074 case LyXRC::RC_SERVERPIPE:
2075 case LyXRC::RC_SET_COLOR:
2076 case LyXRC::RC_SHOW_BANNER:
2077 case LyXRC::RC_SPELL_COMMAND:
2078 case LyXRC::RC_TEMPDIRPATH:
2079 case LyXRC::RC_TEMPLATEPATH:
2080 case LyXRC::RC_TEX_ALLOWS_SPACES:
2081 case LyXRC::RC_UIFILE:
2082 case LyXRC::RC_USER_EMAIL:
2083 case LyXRC::RC_USER_NAME:
2084 case LyXRC::RC_USETEMPDIR:
2085 case LyXRC::RC_USE_ALT_LANG:
2086 case LyXRC::RC_USE_ESC_CHARS:
2087 case LyXRC::RC_USE_INP_ENC:
2088 case LyXRC::RC_USE_PERS_DICT:
2089 case LyXRC::RC_USE_SPELL_LIB:
2090 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2091 case LyXRC::RC_VIEWER:
2092 case LyXRC::RC_WHEEL_JUMP:
2093 case LyXRC::RC_LAST: