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.
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
33 #include "Converter.h"
35 #include "CutAndPaste.h"
37 #include "DispatchResult.h"
39 #include "ErrorList.h"
41 #include "FuncRequest.h"
42 #include "FuncStatus.h"
44 #include "InsetIterator.h"
49 #include "LyXAction.h"
54 #include "Paragraph.h"
55 #include "ParagraphParameters.h"
56 #include "ParIterator.h"
60 #include "TextClassList.h"
61 #include "ToolbarBackend.h"
63 #include "insets/InsetBox.h"
64 #include "insets/InsetBranch.h"
65 #include "insets/InsetCommand.h"
66 #include "insets/InsetERT.h"
67 #include "insets/InsetExternal.h"
68 #include "insets/InsetFloat.h"
69 #include "insets/InsetListings.h"
70 #include "insets/InsetGraphics.h"
71 #include "insets/InsetInclude.h"
72 #include "insets/InsetNote.h"
73 #include "insets/InsetTabular.h"
74 #include "insets/InsetVSpace.h"
75 #include "insets/InsetWrap.h"
77 #include "frontends/alert.h"
78 #include "frontends/Application.h"
79 #include "frontends/FileDialog.h"
80 #include "frontends/FontLoader.h"
81 #include "frontends/KeySymbol.h"
82 #include "frontends/LyXView.h"
83 #include "frontends/Selection.h"
85 #include "support/environment.h"
86 #include "support/FileFilterList.h"
87 #include "support/FileName.h"
88 #include "support/filetools.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>
101 using std::make_pair;
104 using std::istringstream;
105 using std::ostringstream;
111 using frontend::LyXView;
113 using support::absolutePath;
114 using support::addName;
115 using support::addPath;
116 using support::bformat;
117 using support::changeExtension;
118 using support::contains;
119 using support::FileFilterList;
120 using support::FileName;
121 using support::fileSearch;
122 using support::i18nLibFileSearch;
123 using support::makeDisplayPath;
124 using support::makeAbsPath;
125 using support::package;
126 using support::quoteName;
127 using support::rtrim;
128 using support::split;
129 using support::subst;
130 using support::Systemcall;
131 using support::token;
133 using support::prefixIs;
136 namespace Alert = frontend::Alert;
138 extern bool quitting;
144 bool import(LyXView * lv, FileName const & filename,
145 string const & format, ErrorList & errorList)
147 docstring const displaypath = makeDisplayPath(filename.absFilename());
148 lv->message(bformat(_("Importing %1$s..."), displaypath));
150 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
152 string loader_format;
153 vector<string> loaders = theConverters().loaders();
154 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
155 for (vector<string>::const_iterator it = loaders.begin();
156 it != loaders.end(); ++it) {
157 if (theConverters().isReachable(format, *it)) {
158 string const tofile =
159 changeExtension(filename.absFilename(),
160 formats.extension(*it));
161 if (!theConverters().convert(0, filename, FileName(tofile),
162 filename, format, *it, errorList))
168 if (loader_format.empty()) {
169 frontend::Alert::error(_("Couldn't import file"),
170 bformat(_("No information for importing the format %1$s."),
171 formats.prettyName(format)));
175 loader_format = format;
179 if (loader_format == "lyx") {
180 Buffer * buf = theLyXFunc().loadAndViewFile(lyxfile);
183 lv->message(_("file not imported!"));
190 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
195 bool as_paragraphs = loader_format == "textparagraph";
196 string filename2 = (loader_format == format) ? filename.absFilename()
197 : changeExtension(filename.absFilename(),
198 formats.extension(loader_format));
199 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
200 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
204 lv->message(_("imported."));
210 // This function runs "configure" and then rereads lyx.defaults to
211 // reconfigure the automatic settings.
212 void reconfigure(LyXView & lv, string const & option)
214 // emit message signal.
215 lv.message(_("Running configure..."));
217 // Run configure in user lyx directory
218 support::PathChanger p(package().user_support());
219 string configure_command = package().configure_command();
220 configure_command += option;
222 int ret = one.startscript(Systemcall::Wait, configure_command);
224 // emit message signal.
225 lv.message(_("Reloading configuration..."));
226 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
227 // Re-read packages.lst
228 LaTeXFeatures::getAvailable();
231 Alert::information(_("System reconfiguration failed"),
232 _("The system reconfiguration has failed.\n"
233 "Default textclass is used but LyX may "
234 "not be able to work properly.\n"
235 "Please reconfigure again if needed."));
238 Alert::information(_("System reconfigured"),
239 _("The system has been reconfigured.\n"
240 "You need to restart LyX to make use of any\n"
241 "updated document class specifications."));
245 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
247 // Try to fix cursor in case it is broken.
248 cursor.fixIfBroken();
250 // This is, of course, a mess. Better create a new doc iterator and use
251 // this in Inset::getStatus. This might require an additional
252 // BufferView * arg, though (which should be avoided)
253 //Cursor safe = *this;
255 for ( ; cursor.depth(); cursor.pop()) {
256 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
257 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
258 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
259 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
261 // The inset's getStatus() will return 'true' if it made
262 // a definitive decision on whether it want to handle the
263 // request or not. The result of this decision is put into
264 // the 'status' parameter.
265 if (cursor.inset().getStatus(cursor, cmd, status)) {
274 /** Return the change status at cursor position, taking in account the
275 * status at each level of the document iterator (a table in a deleted
276 * footnote is deleted).
277 * When \param outer is true, the top slice is not looked at.
279 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
281 size_t const depth = dit.depth() - (outer ? 1 : 0);
283 for (size_t i = 0 ; i < depth ; ++i) {
284 CursorSlice const & slice = dit[i];
285 if (!slice.inset().inMathed()
286 && slice.pos() < slice.paragraph().size()) {
287 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
288 if (ch != Change::UNCHANGED)
292 return Change::UNCHANGED;
299 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
304 void LyXFunc::initKeySequences(KeyMap * kb)
306 keyseq = KeySequence(kb, kb);
307 cancel_meta_seq = KeySequence(kb, kb);
311 void LyXFunc::setLyXView(LyXView * lv)
313 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
314 // save current selection to the selection buffer to allow
315 // middle-button paste in another window
316 cap::saveSelection(lyx_view_->view()->cursor());
321 void LyXFunc::handleKeyFunc(kb_action action)
323 char_type c = encoded_last_key;
328 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
329 lyx_view_->view()->getIntl().getTransManager().deadkey(
330 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
331 // Need to clear, in case the minibuffer calls these
334 // copied verbatim from do_accent_char
335 view()->cursor().resetAnchor();
336 view()->processUpdateFlags(Update::FitCursor);
340 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
342 BOOST_ASSERT(lyx_view_);
343 if (!LyX::ref().session().bookmarks().isValid(idx))
345 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
346 BOOST_ASSERT(!bm.filename.empty());
347 string const file = bm.filename.absFilename();
348 // if the file is not opened, open it.
349 if (!theBufferList().exists(file)) {
351 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
355 // open may fail, so we need to test it again
356 if (!theBufferList().exists(file))
359 // if the current buffer is not that one, switch to it.
360 if (lyx_view_->buffer()->absFileName() != file) {
363 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
365 // moveToPosition try paragraph id first and then paragraph (pit, pos).
366 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
367 bm.top_id, bm.top_pos))
370 // Cursor jump succeeded!
371 Cursor const & cur = view()->cursor();
372 pit_type new_pit = cur.pit();
373 pos_type new_pos = cur.pos();
374 int new_id = cur.paragraph().id();
376 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
377 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
378 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
379 || bm.top_id != new_id) {
380 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
381 new_pit, new_pos, new_id);
386 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
388 LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
390 // Do nothing if we have nothing (JMarc)
391 if (!keysym.isOK()) {
392 LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
393 lyx_view_->restartCursor();
397 if (keysym.isModifier()) {
398 LYXERR(Debug::KEY, "isModifier true");
399 lyx_view_->restartCursor();
403 //Encoding const * encoding = view()->cursor().getEncoding();
404 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
405 // FIXME: encoded_last_key shadows the member variable of the same
406 // name. Is that intended?
407 char_type encoded_last_key = keysym.getUCSEncoded();
409 // Do a one-deep top-level lookup for
410 // cancel and meta-fake keys. RVDK_PATCH_5
411 cancel_meta_seq.reset();
413 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
414 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
415 << " action first set to [" << func.action << ']');
417 // When not cancel or meta-fake, do the normal lookup.
418 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
419 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
420 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
421 // remove Caps Lock and Mod2 as a modifiers
422 func = keyseq.addkey(keysym, (state | meta_fake_bit));
423 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
424 << "action now set to [" << func.action << ']');
427 // Dont remove this unless you know what you are doing.
428 meta_fake_bit = NoModifier;
430 // Can this happen now ?
431 if (func.action == LFUN_NOACTION)
432 func = FuncRequest(LFUN_COMMAND_PREFIX);
434 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
435 << " Key [action=" << func.action << "]["
436 << to_utf8(keyseq.print(KeySequence::Portable)) << ']');
438 // already here we know if it any point in going further
439 // why not return already here if action == -1 and
440 // num_bytes == 0? (Lgb)
442 if (keyseq.length() > 1)
443 lyx_view_->message(keyseq.print(KeySequence::ForGui));
446 // Maybe user can only reach the key via holding down shift.
447 // Let's see. But only if shift is the only modifier
448 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
449 LYXERR(Debug::KEY, "Trying without shift");
450 func = keyseq.addkey(keysym, NoModifier);
451 LYXERR(Debug::KEY, "Action now " << func.action);
454 if (func.action == LFUN_UNKNOWN_ACTION) {
455 // Hmm, we didn't match any of the keysequences. See
456 // if it's normal insertable text not already covered
458 if (keysym.isText() && keyseq.length() == 1) {
459 LYXERR(Debug::KEY, "isText() is true, inserting.");
460 func = FuncRequest(LFUN_SELF_INSERT,
461 FuncRequest::KEYBOARD);
463 LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
464 lyx_view_->message(_("Unknown function."));
465 lyx_view_->restartCursor();
470 if (func.action == LFUN_SELF_INSERT) {
471 if (encoded_last_key != 0) {
472 docstring const arg(1, encoded_last_key);
473 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
474 FuncRequest::KEYBOARD));
475 LYXERR(Debug::KEY, "SelfInsert arg[`" << to_utf8(arg) << "']");
481 lyx_view_->restartCursor();
485 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
487 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
490 /* In LyX/Mac, when a dialog is open, the menus of the
491 application can still be accessed without giving focus to
492 the main window. In this case, we want to disable the menu
493 entries that are buffer-related.
495 Note that this code is not perfect, as bug 1941 attests:
496 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
498 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
499 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
502 if (cmd.action == LFUN_NOACTION) {
503 flag.message(from_utf8(N_("Nothing to do")));
508 switch (cmd.action) {
509 case LFUN_UNKNOWN_ACTION:
510 #ifndef HAVE_LIBAIKSAURUS
511 case LFUN_THESAURUS_ENTRY:
521 if (flag.unknown()) {
522 flag.message(from_utf8(N_("Unknown action")));
526 if (!flag.enabled()) {
527 if (flag.message().empty())
528 flag.message(from_utf8(N_("Command disabled")));
532 // Check whether we need a buffer
533 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
535 flag.message(from_utf8(N_("Command not allowed with"
536 "out any document open")));
541 // I would really like to avoid having this switch and rather try to
542 // encode this in the function itself.
543 // -- And I'd rather let an inset decide which LFUNs it is willing
544 // to handle (Andre')
546 switch (cmd.action) {
548 case LFUN_DIALOG_TOGGLE:
549 case LFUN_DIALOG_SHOW:
550 case LFUN_DIALOG_UPDATE:
551 case LFUN_TOOLBAR_TOGGLE:
553 return lyx_view_->getStatus(cmd);
557 case LFUN_BUFFER_TOGGLE_READ_ONLY:
558 flag.setOnOff(buf->isReadonly());
561 case LFUN_BUFFER_SWITCH:
562 // toggle on the current buffer, but do not toggle off
563 // the other ones (is that a good idea?)
564 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
568 case LFUN_BUFFER_EXPORT:
569 enable = cmd.argument() == "custom"
570 || buf->isExportable(to_utf8(cmd.argument()));
573 case LFUN_BUFFER_CHKTEX:
574 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
577 case LFUN_BUILD_PROGRAM:
578 enable = buf->isExportable("program");
581 case LFUN_VC_REGISTER:
582 enable = !buf->lyxvc().inUse();
584 case LFUN_VC_CHECK_IN:
585 enable = buf->lyxvc().inUse() && !buf->isReadonly();
587 case LFUN_VC_CHECK_OUT:
588 enable = buf->lyxvc().inUse() && buf->isReadonly();
591 case LFUN_VC_UNDO_LAST:
592 enable = buf->lyxvc().inUse();
594 case LFUN_BUFFER_RELOAD:
595 enable = !buf->isUnnamed() && buf->fileName().exists()
596 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
599 case LFUN_INSET_APPLY: {
604 string const name = cmd.getArg(0);
605 Inset * inset = lyx_view_->getOpenInset(name);
607 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
609 if (!inset->getStatus(view()->cursor(), fr, fs)) {
610 // Every inset is supposed to handle this
615 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
616 flag |= getStatus(fr);
618 enable = flag.enabled();
622 case LFUN_CITATION_INSERT: {
623 FuncRequest fr(LFUN_INSET_INSERT, "citation");
624 enable = getStatus(fr).enabled();
628 case LFUN_BUFFER_WRITE: {
629 enable = lyx_view_->buffer()->isUnnamed()
630 || !lyx_view_->buffer()->isClean();
635 case LFUN_BUFFER_WRITE_ALL: {
636 // We enable the command only if there are some modified buffers
637 Buffer * first = theBufferList().first();
638 bool modified = false;
642 // We cannot use a for loop as the buffer list is a cycle.
648 b = theBufferList().next(b);
649 } while (b != first);
657 case LFUN_BOOKMARK_GOTO: {
658 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
659 enable = LyX::ref().session().bookmarks().isValid(num);
663 case LFUN_BOOKMARK_CLEAR:
664 enable = LyX::ref().session().bookmarks().size() > 0;
667 case LFUN_WINDOW_CLOSE:
668 enable = theApp()->viewCount() > 0;
671 // this one is difficult to get right. As a half-baked
672 // solution, we consider only the first action of the sequence
673 case LFUN_COMMAND_SEQUENCE: {
674 // argument contains ';'-terminated commands
675 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
676 FuncRequest func(lyxaction.lookupFunc(firstcmd));
677 func.origin = cmd.origin;
678 flag = getStatus(func);
684 std::string name = to_utf8(cmd.argument());
685 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
686 func.origin = cmd.origin;
687 flag = getStatus(func);
688 LyX::ref().topLevelCmdDef().release(name);
690 // catch recursion or unknown command definiton
691 // all operations until the recursion or unknown command
692 // definiton occures are performed, so set the state to enabled
698 case LFUN_BUFFER_NEW:
699 case LFUN_BUFFER_NEW_TEMPLATE:
700 case LFUN_WORD_FIND_FORWARD:
701 case LFUN_WORD_FIND_BACKWARD:
702 case LFUN_COMMAND_PREFIX:
703 case LFUN_COMMAND_EXECUTE:
705 case LFUN_META_PREFIX:
706 case LFUN_BUFFER_CLOSE:
707 case LFUN_BUFFER_WRITE_AS:
708 case LFUN_BUFFER_UPDATE:
709 case LFUN_BUFFER_VIEW:
710 case LFUN_MASTER_BUFFER_UPDATE:
711 case LFUN_MASTER_BUFFER_VIEW:
712 case LFUN_BUFFER_IMPORT:
713 case LFUN_BUFFER_AUTO_SAVE:
714 case LFUN_RECONFIGURE:
718 case LFUN_DROP_LAYOUTS_CHOICE:
720 case LFUN_SERVER_GET_NAME:
721 case LFUN_SERVER_NOTIFY:
722 case LFUN_SERVER_GOTO_FILE_ROW:
723 case LFUN_DIALOG_HIDE:
724 case LFUN_DIALOG_DISCONNECT_INSET:
725 case LFUN_BUFFER_CHILD_OPEN:
726 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
727 case LFUN_KEYMAP_OFF:
728 case LFUN_KEYMAP_PRIMARY:
729 case LFUN_KEYMAP_SECONDARY:
730 case LFUN_KEYMAP_TOGGLE:
732 case LFUN_BUFFER_EXPORT_CUSTOM:
733 case LFUN_BUFFER_PRINT:
734 case LFUN_PREFERENCES_SAVE:
735 case LFUN_SCREEN_FONT_UPDATE:
738 case LFUN_EXTERNAL_EDIT:
739 case LFUN_GRAPHICS_EDIT:
740 case LFUN_ALL_INSETS_TOGGLE:
741 case LFUN_BUFFER_LANGUAGE:
742 case LFUN_TEXTCLASS_APPLY:
743 case LFUN_TEXTCLASS_LOAD:
744 case LFUN_BUFFER_SAVE_AS_DEFAULT:
745 case LFUN_BUFFER_PARAMS_APPLY:
746 case LFUN_LAYOUT_MODULES_CLEAR:
747 case LFUN_LAYOUT_MODULE_ADD:
748 case LFUN_LAYOUT_RELOAD:
749 case LFUN_LYXRC_APPLY:
750 case LFUN_BUFFER_NEXT:
751 case LFUN_BUFFER_PREVIOUS:
752 case LFUN_WINDOW_NEW:
754 // these are handled in our dispatch()
762 if (!getLocalStatus(view()->cursor(), cmd, flag))
763 flag = view()->getStatus(cmd);
769 // Can we use a readonly buffer?
770 if (buf && buf->isReadonly()
771 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
772 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
773 flag.message(from_utf8(N_("Document is read-only")));
777 // Are we in a DELETED change-tracking region?
779 && lookupChangeType(view()->cursor(), true) == Change::DELETED
780 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
781 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
782 flag.message(from_utf8(N_("This portion of the document is deleted.")));
786 // the default error message if we disable the command
787 if (!flag.enabled() && flag.message().empty())
788 flag.message(from_utf8(N_("Command disabled")));
794 bool LyXFunc::ensureBufferClean(BufferView * bv)
796 Buffer & buf = bv->buffer();
800 docstring const file = buf.fileName().displayName(30);
801 docstring text = bformat(_("The document %1$s has unsaved "
802 "changes.\n\nDo you want to save "
803 "the document?"), file);
804 int const ret = Alert::prompt(_("Save changed document?"),
805 text, 0, 1, _("&Save"),
809 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
811 return buf.isClean();
817 void showPrintError(string const & name)
819 docstring str = bformat(_("Could not print the document %1$s.\n"
820 "Check that your printer is set up correctly."),
821 makeDisplayPath(name, 50));
822 Alert::error(_("Print document failed"), str);
826 void loadTextClass(string const & name)
828 std::pair<bool, textclass_type> const tc_pair =
829 textclasslist.numberOfClass(name);
831 if (!tc_pair.first) {
832 lyxerr << "Document class \"" << name
833 << "\" does not exist."
838 textclass_type const tc = tc_pair.second;
840 if (!textclasslist[tc].load()) {
841 docstring s = bformat(_("The document class %1$s."
842 "could not be loaded."),
843 from_utf8(textclasslist[tc].name()));
844 Alert::error(_("Could not load class"), s);
849 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
854 void LyXFunc::dispatch(FuncRequest const & cmd)
856 string const argument = to_utf8(cmd.argument());
857 kb_action const action = cmd.action;
859 LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
860 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
862 // we have not done anything wrong yet.
864 dispatch_buffer.erase();
866 // redraw the screen at the end (first of the two drawing steps).
867 //This is done unless explicitely requested otherwise
868 Update::flags updateFlags = Update::FitCursor;
870 FuncStatus const flag = getStatus(cmd);
871 if (!flag.enabled()) {
872 // We cannot use this function here
873 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
874 << lyxaction.getActionName(action)
875 << " [" << action << "] is disabled at this location");
876 setErrorMessage(flag.message());
879 // Let lyx_view_ dispatch its own actions.
880 case LFUN_COMMAND_EXECUTE:
881 case LFUN_DROP_LAYOUTS_CHOICE:
883 case LFUN_TOOLBAR_TOGGLE:
884 case LFUN_DIALOG_UPDATE:
885 case LFUN_DIALOG_TOGGLE:
886 case LFUN_DIALOG_DISCONNECT_INSET:
887 case LFUN_DIALOG_HIDE:
888 BOOST_ASSERT(lyx_view_);
889 lyx_view_->dispatch(cmd);
892 case LFUN_WORD_FIND_FORWARD:
893 case LFUN_WORD_FIND_BACKWARD: {
894 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
895 static docstring last_search;
896 docstring searched_string;
898 if (!cmd.argument().empty()) {
899 last_search = cmd.argument();
900 searched_string = cmd.argument();
902 searched_string = last_search;
905 if (searched_string.empty())
908 bool const fw = action == LFUN_WORD_FIND_FORWARD;
909 docstring const data =
910 find2string(searched_string, true, false, fw);
911 find(view(), FuncRequest(LFUN_WORD_FIND, data));
915 case LFUN_COMMAND_PREFIX:
916 BOOST_ASSERT(lyx_view_);
917 lyx_view_->message(keyseq.printOptions(true));
921 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
923 meta_fake_bit = NoModifier;
924 if (lyx_view_->buffer())
925 // cancel any selection
926 dispatch(FuncRequest(LFUN_MARK_OFF));
927 setMessage(from_ascii(N_("Cancel")));
930 case LFUN_META_PREFIX:
931 meta_fake_bit = AltModifier;
932 setMessage(keyseq.print(KeySequence::ForGui));
935 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
936 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
937 Buffer * buf = lyx_view_->buffer();
938 if (buf->lyxvc().inUse())
939 buf->lyxvc().toggleReadOnly();
941 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
945 // --- Menus -----------------------------------------------
946 case LFUN_BUFFER_NEW:
947 menuNew(argument, false);
948 updateFlags = Update::None;
951 case LFUN_BUFFER_NEW_TEMPLATE:
952 menuNew(argument, true);
953 updateFlags = Update::None;
956 case LFUN_BUFFER_CLOSE:
958 updateFlags = Update::None;
961 case LFUN_BUFFER_WRITE:
962 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
963 if (!lyx_view_->buffer()->isUnnamed()) {
964 docstring const str = bformat(_("Saving document %1$s..."),
965 makeDisplayPath(lyx_view_->buffer()->absFileName()));
966 lyx_view_->message(str);
967 lyx_view_->buffer()->menuWrite();
968 lyx_view_->message(str + _(" done."));
970 lyx_view_->buffer()->writeAs();
972 updateFlags = Update::None;
975 case LFUN_BUFFER_WRITE_AS:
976 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
977 lyx_view_->buffer()->writeAs(argument);
978 updateFlags = Update::None;
981 case LFUN_BUFFER_WRITE_ALL: {
982 Buffer * first = theBufferList().first();
985 lyx_view_->message(_("Saving all documents..."));
987 // We cannot use a for loop as the buffer list cycles.
990 if (!b->isUnnamed()) {
992 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
996 b = theBufferList().next(b);
997 } while (b != first);
998 lyx_view_->message(_("All documents saved."));
1001 updateFlags = Update::None;
1005 case LFUN_BUFFER_RELOAD: {
1006 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1007 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1008 docstring text = bformat(_("Any changes will be lost. Are you sure "
1009 "you want to revert to the saved version of the document %1$s?"), file);
1010 int const ret = Alert::prompt(_("Revert to saved document?"),
1011 text, 1, 1, _("&Revert"), _("&Cancel"));
1018 case LFUN_BUFFER_UPDATE:
1019 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1020 lyx_view_->buffer()->doExport(argument, true);
1023 case LFUN_BUFFER_VIEW:
1024 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1025 lyx_view_->buffer()->preview(argument);
1028 case LFUN_MASTER_BUFFER_UPDATE:
1029 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1030 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1033 case LFUN_MASTER_BUFFER_VIEW:
1034 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1035 lyx_view_->buffer()->masterBuffer()->preview(argument);
1038 case LFUN_BUILD_PROGRAM:
1039 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1040 lyx_view_->buffer()->doExport("program", true);
1043 case LFUN_BUFFER_CHKTEX:
1044 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1045 lyx_view_->buffer()->runChktex();
1048 case LFUN_BUFFER_EXPORT:
1049 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1050 if (argument == "custom")
1051 lyx_view_->showDialog("sendto", string());
1053 lyx_view_->buffer()->doExport(argument, false);
1056 case LFUN_BUFFER_EXPORT_CUSTOM: {
1057 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1059 string command = split(argument, format_name, ' ');
1060 Format const * format = formats.getFormat(format_name);
1062 lyxerr << "Format \"" << format_name
1063 << "\" not recognized!"
1068 Buffer * buffer = lyx_view_->buffer();
1070 // The name of the file created by the conversion process
1073 // Output to filename
1074 if (format->name() == "lyx") {
1075 string const latexname = buffer->latexName(false);
1076 filename = changeExtension(latexname,
1077 format->extension());
1078 filename = addName(buffer->temppath(), filename);
1080 if (!buffer->writeFile(FileName(filename)))
1084 buffer->doExport(format_name, true, filename);
1087 // Substitute $$FName for filename
1088 if (!contains(command, "$$FName"))
1089 command = "( " + command + " ) < $$FName";
1090 command = subst(command, "$$FName", filename);
1092 // Execute the command in the background
1094 call.startscript(Systemcall::DontWait, command);
1098 case LFUN_BUFFER_PRINT: {
1099 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1100 // FIXME: cmd.getArg() might fail if one of the arguments
1101 // contains double quotes
1102 string target = cmd.getArg(0);
1103 string target_name = cmd.getArg(1);
1104 string command = cmd.getArg(2);
1107 || target_name.empty()
1108 || command.empty()) {
1109 lyxerr << "Unable to parse \""
1110 << argument << '"' << endl;
1113 if (target != "printer" && target != "file") {
1114 lyxerr << "Unrecognized target \""
1115 << target << '"' << endl;
1119 Buffer * buffer = lyx_view_->buffer();
1121 if (!buffer->doExport("dvi", true)) {
1122 showPrintError(buffer->absFileName());
1126 // Push directory path.
1127 string const path = buffer->temppath();
1128 // Prevent the compiler from optimizing away p
1130 support::PathChanger p(pp);
1132 // there are three cases here:
1133 // 1. we print to a file
1134 // 2. we print directly to a printer
1135 // 3. we print using a spool command (print to file first)
1138 string const dviname =
1139 changeExtension(buffer->latexName(true), "dvi");
1141 if (target == "printer") {
1142 if (!lyxrc.print_spool_command.empty()) {
1143 // case 3: print using a spool
1144 string const psname =
1145 changeExtension(dviname,".ps");
1146 command += ' ' + lyxrc.print_to_file
1149 + quoteName(dviname);
1152 lyxrc.print_spool_command + ' ';
1153 if (target_name != "default") {
1154 command2 += lyxrc.print_spool_printerprefix
1158 command2 += quoteName(psname);
1160 // If successful, then spool command
1161 res = one.startscript(
1166 res = one.startscript(
1167 Systemcall::DontWait,
1170 // case 2: print directly to a printer
1171 if (target_name != "default")
1172 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1173 res = one.startscript(
1174 Systemcall::DontWait,
1175 command + quoteName(dviname));
1179 // case 1: print to a file
1180 FileName const filename(makeAbsPath(target_name,
1181 lyx_view_->buffer()->filePath()));
1182 FileName const dvifile(makeAbsPath(dviname, path));
1183 if (filename.exists()) {
1184 docstring text = bformat(
1185 _("The file %1$s already exists.\n\n"
1186 "Do you want to overwrite that file?"),
1187 makeDisplayPath(filename.absFilename()));
1188 if (Alert::prompt(_("Overwrite file?"),
1189 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1192 command += ' ' + lyxrc.print_to_file
1193 + quoteName(filename.toFilesystemEncoding())
1195 + quoteName(dvifile.toFilesystemEncoding());
1196 res = one.startscript(Systemcall::DontWait,
1201 showPrintError(buffer->absFileName());
1205 case LFUN_BUFFER_IMPORT:
1210 // quitting is triggered by the gui code
1211 // (leaving the event loop).
1212 lyx_view_->message(from_utf8(N_("Exiting.")));
1213 if (theBufferList().quitWriteAll())
1214 theApp()->closeAllViews();
1217 case LFUN_BUFFER_AUTO_SAVE:
1218 lyx_view_->buffer()->autoSave();
1221 case LFUN_RECONFIGURE:
1222 BOOST_ASSERT(lyx_view_);
1223 // argument is any additional parameter to the configure.py command
1224 reconfigure(*lyx_view_, argument);
1227 case LFUN_HELP_OPEN: {
1228 BOOST_ASSERT(lyx_view_);
1229 string const arg = argument;
1231 setErrorMessage(from_ascii(N_("Missing argument")));
1234 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1235 if (fname.empty()) {
1236 lyxerr << "LyX: unable to find documentation file `"
1237 << arg << "'. Bad installation?" << endl;
1240 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1241 makeDisplayPath(fname.absFilename())));
1242 Buffer * buf = loadAndViewFile(fname, false);
1245 lyx_view_->setBuffer(buf);
1246 lyx_view_->errors("Parse");
1248 updateFlags = Update::None;
1252 // --- version control -------------------------------
1253 case LFUN_VC_REGISTER:
1254 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1255 if (!ensureBufferClean(view()))
1257 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1258 lyx_view_->buffer()->lyxvc().registrer();
1261 updateFlags = Update::Force;
1264 case LFUN_VC_CHECK_IN:
1265 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1266 if (!ensureBufferClean(view()))
1268 if (lyx_view_->buffer()->lyxvc().inUse()
1269 && !lyx_view_->buffer()->isReadonly()) {
1270 lyx_view_->buffer()->lyxvc().checkIn();
1275 case LFUN_VC_CHECK_OUT:
1276 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1277 if (!ensureBufferClean(view()))
1279 if (lyx_view_->buffer()->lyxvc().inUse()
1280 && lyx_view_->buffer()->isReadonly()) {
1281 lyx_view_->buffer()->lyxvc().checkOut();
1286 case LFUN_VC_REVERT:
1287 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1288 lyx_view_->buffer()->lyxvc().revert();
1292 case LFUN_VC_UNDO_LAST:
1293 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1294 lyx_view_->buffer()->lyxvc().undoLast();
1298 // --- buffers ----------------------------------------
1299 case LFUN_BUFFER_SWITCH:
1300 BOOST_ASSERT(lyx_view_);
1301 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1302 updateFlags = Update::None;
1305 case LFUN_BUFFER_NEXT:
1306 BOOST_ASSERT(lyx_view_);
1307 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1308 updateFlags = Update::None;
1311 case LFUN_BUFFER_PREVIOUS:
1312 BOOST_ASSERT(lyx_view_);
1313 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1314 updateFlags = Update::None;
1317 case LFUN_FILE_NEW: {
1318 BOOST_ASSERT(lyx_view_);
1320 string tmpname = split(argument, name, ':'); // Split filename
1321 Buffer * const b = newFile(name, tmpname);
1323 lyx_view_->setBuffer(b);
1324 updateFlags = Update::None;
1328 case LFUN_FILE_OPEN:
1329 BOOST_ASSERT(lyx_view_);
1331 updateFlags = Update::None;
1334 // --- lyxserver commands ----------------------------
1335 case LFUN_SERVER_GET_NAME:
1336 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1337 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1338 LYXERR(Debug::INFO, "FNAME["
1339 << lyx_view_->buffer()->absFileName() << ']');
1342 case LFUN_SERVER_NOTIFY:
1343 dispatch_buffer = keyseq.print(KeySequence::Portable);
1344 theServer().notifyClient(to_utf8(dispatch_buffer));
1347 case LFUN_SERVER_GOTO_FILE_ROW: {
1348 BOOST_ASSERT(lyx_view_);
1351 istringstream is(argument);
1352 is >> file_name >> row;
1354 bool loaded = false;
1355 if (prefixIs(file_name, package().temp_dir().absFilename()))
1356 // Needed by inverse dvi search. If it is a file
1357 // in tmpdir, call the apropriated function
1358 buf = theBufferList().getBufferFromTmp(file_name);
1360 // Must replace extension of the file to be .lyx
1361 // and get full path
1362 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1363 // Either change buffer or load the file
1364 if (theBufferList().exists(s.absFilename()))
1365 buf = theBufferList().getBuffer(s.absFilename());
1367 buf = loadAndViewFile(s);
1373 updateFlags = Update::None;
1378 lyx_view_->setBuffer(buf);
1379 view()->setCursorFromRow(row);
1381 lyx_view_->errors("Parse");
1382 updateFlags = Update::FitCursor;
1387 case LFUN_DIALOG_SHOW_NEW_INSET: {
1388 BOOST_ASSERT(lyx_view_);
1389 string const name = cmd.getArg(0);
1390 InsetCode code = insetCode(name);
1391 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1392 bool insetCodeOK = true;
1401 case HYPERLINK_CODE: {
1402 InsetCommandParams p(code);
1403 data = InsetCommandMailer::params2string(name, p);
1406 case INCLUDE_CODE: {
1407 // data is the include type: one of "include",
1408 // "input", "verbatiminput" or "verbatiminput*"
1410 // default type is requested
1412 InsetCommandParams p(INCLUDE_CODE, data);
1413 data = InsetCommandMailer::params2string("include", p);
1417 // \c data == "Boxed" || "Frameless" etc
1418 InsetBoxParams p(data);
1419 data = InsetBoxMailer::params2string(p);
1423 InsetBranchParams p;
1424 data = InsetBranchMailer::params2string(p);
1428 InsetCommandParams p(CITE_CODE);
1429 data = InsetCommandMailer::params2string(name, p);
1433 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1436 case EXTERNAL_CODE: {
1437 InsetExternalParams p;
1438 Buffer const & buffer = *lyx_view_->buffer();
1439 data = InsetExternalMailer::params2string(p, buffer);
1444 data = InsetFloatMailer::params2string(p);
1447 case LISTINGS_CODE: {
1448 InsetListingsParams p;
1449 data = InsetListingsMailer::params2string(p);
1452 case GRAPHICS_CODE: {
1453 InsetGraphicsParams p;
1454 Buffer const & buffer = *lyx_view_->buffer();
1455 data = InsetGraphicsMailer::params2string(p, buffer);
1460 data = InsetNoteMailer::params2string(p);
1465 data = InsetVSpaceMailer::params2string(space);
1470 data = InsetWrapMailer::params2string(p);
1474 lyxerr << "Inset type '" << name <<
1475 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1476 insetCodeOK = false;
1478 } // end switch(code)
1480 lyx_view_->showDialog(name, data, 0);
1484 case LFUN_CITATION_INSERT: {
1485 BOOST_ASSERT(lyx_view_);
1486 if (!argument.empty()) {
1487 // we can have one optional argument, delimited by '|'
1488 // citation-insert <key>|<text_before>
1489 // this should be enhanced to also support text_after
1490 // and citation style
1491 string arg = argument;
1493 if (contains(argument, "|")) {
1494 arg = token(argument, '|', 0);
1495 opt1 = token(argument, '|', 1);
1497 InsetCommandParams icp(CITE_CODE);
1498 icp["key"] = from_utf8(arg);
1500 icp["before"] = from_utf8(opt1);
1501 string icstr = InsetCommandMailer::params2string("citation", icp);
1502 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1505 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1509 case LFUN_BUFFER_CHILD_OPEN: {
1510 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1511 Buffer * parent = lyx_view_->buffer();
1512 FileName filename = makeAbsPath(argument, parent->filePath());
1513 view()->saveBookmark(false);
1515 bool parsed = false;
1516 if (theBufferList().exists(filename.absFilename())) {
1517 child = theBufferList().getBuffer(filename.absFilename());
1519 setMessage(bformat(_("Opening child document %1$s..."),
1520 makeDisplayPath(filename.absFilename())));
1521 child = loadAndViewFile(filename, true);
1525 // Set the parent name of the child document.
1526 // This makes insertion of citations and references in the child work,
1527 // when the target is in the parent or another child document.
1528 child->setParentName(parent->absFileName());
1529 updateLabels(*child->masterBuffer());
1530 lyx_view_->setBuffer(child);
1532 lyx_view_->errors("Parse");
1535 // If a screen update is required (in case where auto_open is false),
1536 // setBuffer() would have taken care of it already. Otherwise we shall
1537 // reset the update flag because it can cause a circular problem.
1539 updateFlags = Update::None;
1543 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1544 BOOST_ASSERT(lyx_view_);
1545 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1548 case LFUN_KEYMAP_OFF:
1549 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1550 lyx_view_->view()->getIntl().keyMapOn(false);
1553 case LFUN_KEYMAP_PRIMARY:
1554 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1555 lyx_view_->view()->getIntl().keyMapPrim();
1558 case LFUN_KEYMAP_SECONDARY:
1559 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1560 lyx_view_->view()->getIntl().keyMapSec();
1563 case LFUN_KEYMAP_TOGGLE:
1564 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1565 lyx_view_->view()->getIntl().toggleKeyMap();
1571 string rest = split(argument, countstr, ' ');
1572 istringstream is(countstr);
1575 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1576 for (int i = 0; i < count; ++i)
1577 dispatch(lyxaction.lookupFunc(rest));
1581 case LFUN_COMMAND_SEQUENCE: {
1582 // argument contains ';'-terminated commands
1583 string arg = argument;
1584 while (!arg.empty()) {
1586 arg = split(arg, first, ';');
1587 FuncRequest func(lyxaction.lookupFunc(first));
1588 func.origin = cmd.origin;
1596 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1597 func.origin = cmd.origin;
1599 LyX::ref().topLevelCmdDef().release(argument);
1601 if (func.action == LFUN_UNKNOWN_ACTION) {
1602 // unknown command definition
1603 lyxerr << "Warning: unknown command definition `"
1607 // recursion detected
1608 lyxerr << "Warning: Recursion in the command definition `"
1609 << argument << "' detected"
1616 case LFUN_PREFERENCES_SAVE: {
1617 lyxrc.write(makeAbsPath("preferences",
1618 package().user_support().absFilename()),
1623 case LFUN_SCREEN_FONT_UPDATE:
1624 BOOST_ASSERT(lyx_view_);
1625 // handle the screen font changes.
1626 theFontLoader().update();
1627 /// FIXME: only the current view will be updated. the Gui
1628 /// class is able to furnish the list of views.
1629 updateFlags = Update::Force;
1632 case LFUN_SET_COLOR: {
1634 string const x11_name = split(argument, lyx_name, ' ');
1635 if (lyx_name.empty() || x11_name.empty()) {
1636 setErrorMessage(from_ascii(N_(
1637 "Syntax: set-color <lyx_name>"
1642 bool const graphicsbg_changed =
1643 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1644 x11_name != lcolor.getX11Name(Color_graphicsbg));
1646 if (!lcolor.setColor(lyx_name, x11_name)) {
1648 bformat(_("Set-color \"%1$s\" failed "
1649 "- color is undefined or "
1650 "may not be redefined"),
1651 from_utf8(lyx_name)));
1655 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1657 if (graphicsbg_changed) {
1658 // FIXME: The graphics cache no longer has a changeDisplay method.
1660 graphics::GCache::get().changeDisplay(true);
1667 BOOST_ASSERT(lyx_view_);
1668 lyx_view_->message(from_utf8(argument));
1671 case LFUN_EXTERNAL_EDIT: {
1672 BOOST_ASSERT(lyx_view_);
1673 FuncRequest fr(action, argument);
1674 InsetExternal().dispatch(view()->cursor(), fr);
1678 case LFUN_GRAPHICS_EDIT: {
1679 FuncRequest fr(action, argument);
1680 InsetGraphics().dispatch(view()->cursor(), fr);
1684 case LFUN_INSET_APPLY: {
1685 BOOST_ASSERT(lyx_view_);
1686 string const name = cmd.getArg(0);
1687 Inset * inset = lyx_view_->getOpenInset(name);
1689 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1690 inset->dispatch(view()->cursor(), fr);
1692 FuncRequest fr(LFUN_INSET_INSERT, argument);
1695 // ideally, the update flag should be set by the insets,
1696 // but this is not possible currently
1697 updateFlags = Update::Force | Update::FitCursor;
1701 case LFUN_ALL_INSETS_TOGGLE: {
1702 BOOST_ASSERT(lyx_view_);
1704 string const name = split(argument, action, ' ');
1705 InsetCode const inset_code = insetCode(name);
1707 Cursor & cur = view()->cursor();
1708 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1710 Inset & inset = lyx_view_->buffer()->inset();
1711 InsetIterator it = inset_iterator_begin(inset);
1712 InsetIterator const end = inset_iterator_end(inset);
1713 for (; it != end; ++it) {
1714 if (!it->asInsetMath()
1715 && (inset_code == NO_CODE
1716 || inset_code == it->lyxCode())) {
1717 Cursor tmpcur = cur;
1718 tmpcur.pushBackward(*it);
1719 it->dispatch(tmpcur, fr);
1722 updateFlags = Update::Force | Update::FitCursor;
1726 case LFUN_BUFFER_LANGUAGE: {
1727 BOOST_ASSERT(lyx_view_);
1728 Buffer & buffer = *lyx_view_->buffer();
1729 Language const * oldL = buffer.params().language;
1730 Language const * newL = languages.getLanguage(argument);
1731 if (!newL || oldL == newL)
1734 if (oldL->rightToLeft() == newL->rightToLeft()
1735 && !buffer.isMultiLingual())
1736 buffer.changeLanguage(oldL, newL);
1740 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1741 string const fname =
1742 addName(addPath(package().user_support().absFilename(), "templates/"),
1744 Buffer defaults(fname);
1746 istringstream ss(argument);
1749 int const unknown_tokens = defaults.readHeader(lex);
1751 if (unknown_tokens != 0) {
1752 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1753 << unknown_tokens << " unknown token"
1754 << (unknown_tokens == 1 ? "" : "s")
1758 if (defaults.writeFile(FileName(defaults.absFileName())))
1759 setMessage(bformat(_("Document defaults saved in %1$s"),
1760 makeDisplayPath(fname)));
1762 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1766 case LFUN_BUFFER_PARAMS_APPLY: {
1767 BOOST_ASSERT(lyx_view_);
1768 biblio::CiteEngine const oldEngine =
1769 lyx_view_->buffer()->params().getEngine();
1771 Buffer * buffer = lyx_view_->buffer();
1773 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1775 Cursor & cur = view()->cursor();
1776 cur.recordUndoFullDocument();
1778 istringstream ss(argument);
1781 int const unknown_tokens = buffer->readHeader(lex);
1783 if (unknown_tokens != 0) {
1784 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1785 << unknown_tokens << " unknown token"
1786 << (unknown_tokens == 1 ? "" : "s")
1790 updateLayout(oldClass, buffer);
1792 biblio::CiteEngine const newEngine =
1793 lyx_view_->buffer()->params().getEngine();
1795 if (oldEngine != newEngine) {
1796 FuncRequest fr(LFUN_INSET_REFRESH);
1798 Inset & inset = lyx_view_->buffer()->inset();
1799 InsetIterator it = inset_iterator_begin(inset);
1800 InsetIterator const end = inset_iterator_end(inset);
1801 for (; it != end; ++it)
1802 if (it->lyxCode() == CITE_CODE)
1803 it->dispatch(cur, fr);
1806 updateFlags = Update::Force | Update::FitCursor;
1810 case LFUN_LAYOUT_MODULES_CLEAR: {
1811 BOOST_ASSERT(lyx_view_);
1812 Buffer * buffer = lyx_view_->buffer();
1813 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1814 view()->cursor().recordUndoFullDocument();
1815 buffer->params().clearLayoutModules();
1816 updateLayout(oldClass, buffer);
1817 updateFlags = Update::Force | Update::FitCursor;
1821 case LFUN_LAYOUT_MODULE_ADD: {
1822 BOOST_ASSERT(lyx_view_);
1823 Buffer * buffer = lyx_view_->buffer();
1824 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1825 view()->cursor().recordUndoFullDocument();
1826 buffer->params().addLayoutModule(argument);
1827 updateLayout(oldClass, buffer);
1828 updateFlags = Update::Force | Update::FitCursor;
1832 case LFUN_TEXTCLASS_APPLY: {
1833 BOOST_ASSERT(lyx_view_);
1834 Buffer * buffer = lyx_view_->buffer();
1836 loadTextClass(argument);
1838 std::pair<bool, textclass_type> const tc_pair =
1839 textclasslist.numberOfClass(argument);
1844 textclass_type const old_class = buffer->params().getBaseClass();
1845 textclass_type const new_class = tc_pair.second;
1847 if (old_class == new_class)
1851 //Save the old, possibly modular, layout for use in conversion.
1852 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1853 view()->cursor().recordUndoFullDocument();
1854 buffer->params().setBaseClass(new_class);
1855 updateLayout(oldClass, buffer);
1856 updateFlags = Update::Force | Update::FitCursor;
1860 case LFUN_LAYOUT_RELOAD: {
1861 BOOST_ASSERT(lyx_view_);
1862 Buffer * buffer = lyx_view_->buffer();
1863 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1864 textclass_type const tc = buffer->params().getBaseClass();
1865 textclasslist.reset(tc);
1866 buffer->params().setBaseClass(tc);
1867 updateLayout(oldClass, buffer);
1868 updateFlags = Update::Force | Update::FitCursor;
1872 case LFUN_TEXTCLASS_LOAD:
1873 loadTextClass(argument);
1876 case LFUN_LYXRC_APPLY: {
1877 LyXRC const lyxrc_orig = lyxrc;
1879 istringstream ss(argument);
1880 bool const success = lyxrc.read(ss) == 0;
1883 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1884 << "Unable to read lyxrc data"
1889 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1891 if (lyx_view_ && lyx_view_->buffer())
1892 lyx_view_->updateLayoutChoice(true);
1894 /// We force the redraw in any case because there might be
1895 /// some screen font changes.
1896 /// FIXME: only the current view will be updated. the Gui
1897 /// class is able to furnish the list of views.
1898 updateFlags = Update::Force;
1902 case LFUN_WINDOW_NEW:
1903 LyX::ref().newLyXView();
1906 case LFUN_WINDOW_CLOSE:
1907 BOOST_ASSERT(lyx_view_);
1908 BOOST_ASSERT(theApp());
1909 // update bookmark pit of the current buffer before window close
1910 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1911 gotoBookmark(i+1, false, false);
1912 // ask the user for saving changes or cancel quit
1913 if (!theBufferList().quitWriteAll())
1918 case LFUN_BOOKMARK_GOTO:
1919 // go to bookmark, open unopened file and switch to buffer if necessary
1920 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1923 case LFUN_BOOKMARK_CLEAR:
1924 LyX::ref().session().bookmarks().clear();
1928 BOOST_ASSERT(lyx_view_);
1929 view()->cursor().dispatch(cmd);
1930 updateFlags = view()->cursor().result().update();
1931 if (!view()->cursor().result().dispatched())
1932 updateFlags = view()->dispatch(cmd);
1937 if (lyx_view_ && lyx_view_->buffer()) {
1938 // BufferView::update() updates the ViewMetricsInfo and
1939 // also initializes the position cache for all insets in
1940 // (at least partially) visible top-level paragraphs.
1941 // We will redraw the screen only if needed.
1942 view()->processUpdateFlags(updateFlags);
1943 lyx_view_->updateStatusBar();
1945 // if we executed a mutating lfun, mark the buffer as dirty
1947 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1948 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1949 lyx_view_->buffer()->markDirty();
1951 //Do we have a selection?
1952 theSelection().haveSelection(view()->cursor().selection());
1954 if (view()->cursor().inTexted()) {
1955 lyx_view_->updateLayoutChoice(false);
1959 if (!quitting && lyx_view_) {
1960 lyx_view_->updateToolbars();
1961 // Some messages may already be translated, so we cannot use _()
1962 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1967 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1969 const bool verbose = (cmd.origin == FuncRequest::MENU
1970 || cmd.origin == FuncRequest::TOOLBAR
1971 || cmd.origin == FuncRequest::COMMANDBUFFER);
1973 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1974 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
1976 lyx_view_->message(msg);
1980 docstring dispatch_msg = msg;
1981 if (!dispatch_msg.empty())
1982 dispatch_msg += ' ';
1984 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1986 bool argsadded = false;
1988 if (!cmd.argument().empty()) {
1989 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1990 comname += ' ' + cmd.argument();
1995 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
1997 if (!shortcuts.empty())
1998 comname += ": " + shortcuts;
1999 else if (!argsadded && !cmd.argument().empty())
2000 comname += ' ' + cmd.argument();
2002 if (!comname.empty()) {
2003 comname = rtrim(comname);
2004 dispatch_msg += '(' + rtrim(comname) + ')';
2007 LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
2008 if (!dispatch_msg.empty())
2009 lyx_view_->message(dispatch_msg);
2013 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2015 // FIXME: initpath is not used. What to do?
2016 string initpath = lyxrc.document_path;
2017 string filename(name);
2019 if (lyx_view_->buffer()) {
2020 string const trypath = lyx_view_->buffer()->filePath();
2021 // If directory is writeable, use this as default.
2022 if (FileName(trypath).isDirWritable())
2026 static int newfile_number;
2028 if (filename.empty()) {
2029 filename = addName(lyxrc.document_path,
2030 "newfile" + convert<string>(++newfile_number) + ".lyx");
2031 while (theBufferList().exists(filename) ||
2032 FileName(filename).isReadable()) {
2034 filename = addName(lyxrc.document_path,
2035 "newfile" + convert<string>(newfile_number) +
2040 // The template stuff
2043 FileDialog dlg(_("Select template file"));
2044 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2045 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2047 FileDialog::Result result =
2048 dlg.open(from_utf8(lyxrc.template_path),
2049 FileFilterList(_("LyX Documents (*.lyx)")),
2052 if (result.first == FileDialog::Later)
2054 if (result.second.empty())
2056 templname = to_utf8(result.second);
2059 Buffer * const b = newFile(filename, templname, !name.empty());
2061 lyx_view_->setBuffer(b);
2065 Buffer * LyXFunc::loadAndViewFile(FileName const & filename, bool tolastfiles)
2067 lyx_view_->setBusy(true);
2069 Buffer * newBuffer = checkAndLoadLyXFile(filename);
2072 lyx_view_->message(_("Document not loaded."));
2073 lyx_view_->updateStatusBar();
2074 lyx_view_->setBusy(false);
2078 lyx_view_->setBuffer(newBuffer);
2080 // scroll to the position when the file was last closed
2081 if (lyxrc.use_lastfilepos) {
2082 LastFilePosSection::FilePos filepos =
2083 LyX::ref().session().lastFilePos().load(filename);
2084 lyx_view_->view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
2088 LyX::ref().session().lastFiles().add(filename);
2090 lyx_view_->setBusy(false);
2095 void LyXFunc::open(string const & fname)
2097 string initpath = lyxrc.document_path;
2099 if (lyx_view_->buffer()) {
2100 string const trypath = lyx_view_->buffer()->filePath();
2101 // If directory is writeable, use this as default.
2102 if (FileName(trypath).isDirWritable())
2108 if (fname.empty()) {
2109 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2110 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2111 dlg.setButton2(_("Examples|#E#e"),
2112 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2114 FileDialog::Result result =
2115 dlg.open(from_utf8(initpath),
2116 FileFilterList(_("LyX Documents (*.lyx)")),
2119 if (result.first == FileDialog::Later)
2122 filename = to_utf8(result.second);
2124 // check selected filename
2125 if (filename.empty()) {
2126 lyx_view_->message(_("Canceled."));
2132 // get absolute path of file and add ".lyx" to the filename if
2134 FileName const fullname = fileSearch(string(), filename, "lyx");
2135 if (!fullname.empty())
2136 filename = fullname.absFilename();
2138 // if the file doesn't exist, let the user create one
2139 if (!fullname.exists()) {
2140 // the user specifically chose this name. Believe him.
2141 Buffer * const b = newFile(filename, string(), true);
2143 lyx_view_->setBuffer(b);
2147 docstring const disp_fn = makeDisplayPath(filename);
2148 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2151 Buffer * buf = loadAndViewFile(fullname);
2154 lyx_view_->setBuffer(buf);
2155 lyx_view_->errors("Parse");
2156 str2 = bformat(_("Document %1$s opened."), disp_fn);
2158 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2160 lyx_view_->message(str2);
2164 void LyXFunc::doImport(string const & argument)
2167 string filename = split(argument, format, ' ');
2169 LYXERR(Debug::INFO, "LyXFunc::doImport: " << format
2170 << " file: " << filename);
2172 // need user interaction
2173 if (filename.empty()) {
2174 string initpath = lyxrc.document_path;
2176 if (lyx_view_->buffer()) {
2177 string const trypath = lyx_view_->buffer()->filePath();
2178 // If directory is writeable, use this as default.
2179 if (FileName(trypath).isDirWritable())
2183 docstring const text = bformat(_("Select %1$s file to import"),
2184 formats.prettyName(format));
2186 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2187 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2188 dlg.setButton2(_("Examples|#E#e"),
2189 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2191 docstring filter = formats.prettyName(format);
2194 filter += from_utf8(formats.extension(format));
2197 FileDialog::Result result =
2198 dlg.open(from_utf8(initpath),
2199 FileFilterList(filter),
2202 if (result.first == FileDialog::Later)
2205 filename = to_utf8(result.second);
2207 // check selected filename
2208 if (filename.empty())
2209 lyx_view_->message(_("Canceled."));
2212 if (filename.empty())
2215 // get absolute path of file
2216 FileName const fullname(makeAbsPath(filename));
2218 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2220 // Check if the document already is open
2221 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2222 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2223 lyx_view_->message(_("Canceled."));
2228 // if the file exists already, and we didn't do
2229 // -i lyx thefile.lyx, warn
2230 if (lyxfile.exists() && fullname != lyxfile) {
2231 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2233 docstring text = bformat(_("The document %1$s already exists.\n\n"
2234 "Do you want to overwrite that document?"), file);
2235 int const ret = Alert::prompt(_("Overwrite document?"),
2236 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2239 lyx_view_->message(_("Canceled."));
2244 ErrorList errorList;
2245 import(lyx_view_, fullname, format, errorList);
2246 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2250 void LyXFunc::closeBuffer()
2252 // goto bookmark to update bookmark pit.
2253 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2254 gotoBookmark(i+1, false, false);
2256 theBufferList().close(lyx_view_->buffer(), true);
2260 void LyXFunc::reloadBuffer()
2262 FileName filename(lyx_view_->buffer()->absFileName());
2263 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2266 Buffer * buf = loadAndViewFile(filename);
2269 lyx_view_->setBuffer(buf);
2270 lyx_view_->errors("Parse");
2271 str = bformat(_("Document %1$s reloaded."), disp_fn);
2273 str = bformat(_("Could not reload document %1$s"), disp_fn);
2275 lyx_view_->message(str);
2278 // Each "lyx_view_" should have it's own message method. lyxview and
2279 // the minibuffer would use the minibuffer, but lyxserver would
2280 // send an ERROR signal to its client. Alejandro 970603
2281 // This function is bit problematic when it comes to NLS, to make the
2282 // lyx servers client be language indepenent we must not translate
2283 // strings sent to this func.
2284 void LyXFunc::setErrorMessage(docstring const & m) const
2286 dispatch_buffer = m;
2291 void LyXFunc::setMessage(docstring const & m) const
2293 dispatch_buffer = m;
2297 docstring const LyXFunc::viewStatusMessage()
2299 // When meta-fake key is pressed, show the key sequence so far + "M-".
2301 return keyseq.print(KeySequence::ForGui) + "M-";
2303 // Else, when a non-complete key sequence is pressed,
2304 // show the available options.
2305 if (keyseq.length() > 0 && !keyseq.deleted())
2306 return keyseq.printOptions(true);
2308 BOOST_ASSERT(lyx_view_);
2309 if (!lyx_view_->buffer())
2310 return _("Welcome to LyX!");
2312 return view()->cursor().currentState();
2316 BufferView * LyXFunc::view() const
2318 BOOST_ASSERT(lyx_view_);
2319 return lyx_view_->view();
2323 bool LyXFunc::wasMetaKey() const
2325 return (meta_fake_bit != NoModifier);
2329 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2332 lyx_view_->message(_("Converting document to new document class..."));
2334 StableDocIterator backcur(view()->cursor());
2335 ErrorList & el = buffer->errorList("Class Switch");
2336 cap::switchBetweenClasses(
2337 oldlayout, buffer->params().getTextClassPtr(),
2338 static_cast<InsetText &>(buffer->inset()), el);
2340 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2342 buffer->errors("Class Switch");
2343 updateLabels(*buffer);
2349 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2351 // Why the switch you might ask. It is a trick to ensure that all
2352 // the elements in the LyXRCTags enum is handled. As you can see
2353 // there are no breaks at all. So it is just a huge fall-through.
2354 // The nice thing is that we will get a warning from the compiler
2355 // if we forget an element.
2356 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2358 case LyXRC::RC_ACCEPT_COMPOUND:
2359 case LyXRC::RC_ALT_LANG:
2360 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2361 case LyXRC::RC_PLAINTEXT_LINELEN:
2362 case LyXRC::RC_AUTOREGIONDELETE:
2363 case LyXRC::RC_AUTORESET_OPTIONS:
2364 case LyXRC::RC_AUTOSAVE:
2365 case LyXRC::RC_AUTO_NUMBER:
2366 case LyXRC::RC_BACKUPDIR_PATH:
2367 case LyXRC::RC_BIBTEX_COMMAND:
2368 case LyXRC::RC_BINDFILE:
2369 case LyXRC::RC_CHECKLASTFILES:
2370 case LyXRC::RC_USELASTFILEPOS:
2371 case LyXRC::RC_LOADSESSION:
2372 case LyXRC::RC_CHKTEX_COMMAND:
2373 case LyXRC::RC_CONVERTER:
2374 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2375 case LyXRC::RC_COPIER:
2376 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2377 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2378 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2379 case LyXRC::RC_DATE_INSERT_FORMAT:
2380 case LyXRC::RC_DEFAULT_LANGUAGE:
2381 case LyXRC::RC_DEFAULT_PAPERSIZE:
2382 case LyXRC::RC_DEFFILE:
2383 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2384 case LyXRC::RC_DISPLAY_GRAPHICS:
2385 case LyXRC::RC_DOCUMENTPATH:
2386 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2387 FileName path(lyxrc_new.document_path);
2388 if (path.exists() && path.isDirectory())
2389 support::package().document_dir() = FileName(lyxrc.document_path);
2391 case LyXRC::RC_ESC_CHARS:
2392 case LyXRC::RC_FONT_ENCODING:
2393 case LyXRC::RC_FORMAT:
2394 case LyXRC::RC_INDEX_COMMAND:
2395 case LyXRC::RC_INPUT:
2396 case LyXRC::RC_KBMAP:
2397 case LyXRC::RC_KBMAP_PRIMARY:
2398 case LyXRC::RC_KBMAP_SECONDARY:
2399 case LyXRC::RC_LABEL_INIT_LENGTH:
2400 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2401 case LyXRC::RC_LANGUAGE_AUTO_END:
2402 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2403 case LyXRC::RC_LANGUAGE_COMMAND_END:
2404 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2405 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2406 case LyXRC::RC_LANGUAGE_PACKAGE:
2407 case LyXRC::RC_LANGUAGE_USE_BABEL:
2408 case LyXRC::RC_MAKE_BACKUP:
2409 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2410 case LyXRC::RC_NUMLASTFILES:
2411 case LyXRC::RC_PATH_PREFIX:
2412 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2413 support::prependEnvPath("PATH", lyxrc.path_prefix);
2415 case LyXRC::RC_PERS_DICT:
2416 case LyXRC::RC_PREVIEW:
2417 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2418 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2419 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2420 case LyXRC::RC_PRINTCOPIESFLAG:
2421 case LyXRC::RC_PRINTER:
2422 case LyXRC::RC_PRINTEVENPAGEFLAG:
2423 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2424 case LyXRC::RC_PRINTFILEEXTENSION:
2425 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2426 case LyXRC::RC_PRINTODDPAGEFLAG:
2427 case LyXRC::RC_PRINTPAGERANGEFLAG:
2428 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2429 case LyXRC::RC_PRINTPAPERFLAG:
2430 case LyXRC::RC_PRINTREVERSEFLAG:
2431 case LyXRC::RC_PRINTSPOOL_COMMAND:
2432 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2433 case LyXRC::RC_PRINTTOFILE:
2434 case LyXRC::RC_PRINTTOPRINTER:
2435 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2436 case LyXRC::RC_PRINT_COMMAND:
2437 case LyXRC::RC_RTL_SUPPORT:
2438 case LyXRC::RC_SCREEN_DPI:
2439 case LyXRC::RC_SCREEN_FONT_ROMAN:
2440 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2441 case LyXRC::RC_SCREEN_FONT_SANS:
2442 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2443 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2444 case LyXRC::RC_SCREEN_FONT_SIZES:
2445 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2446 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2447 case LyXRC::RC_GEOMETRY_SESSION:
2448 case LyXRC::RC_SCREEN_ZOOM:
2449 case LyXRC::RC_SERVERPIPE:
2450 case LyXRC::RC_SET_COLOR:
2451 case LyXRC::RC_SHOW_BANNER:
2452 case LyXRC::RC_SPELL_COMMAND:
2453 case LyXRC::RC_TEMPDIRPATH:
2454 case LyXRC::RC_TEMPLATEPATH:
2455 case LyXRC::RC_TEX_ALLOWS_SPACES:
2456 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2457 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2458 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2460 case LyXRC::RC_UIFILE:
2461 case LyXRC::RC_USER_EMAIL:
2462 case LyXRC::RC_USER_NAME:
2463 case LyXRC::RC_USETEMPDIR:
2464 case LyXRC::RC_USE_ALT_LANG:
2465 case LyXRC::RC_USE_CONVERTER_CACHE:
2466 case LyXRC::RC_USE_ESC_CHARS:
2467 case LyXRC::RC_USE_INP_ENC:
2468 case LyXRC::RC_USE_PERS_DICT:
2469 case LyXRC::RC_USE_PIXMAP_CACHE:
2470 case LyXRC::RC_USE_SPELL_LIB:
2471 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2472 case LyXRC::RC_SORT_LAYOUTS:
2473 case LyXRC::RC_VIEWER:
2474 case LyXRC::RC_LAST: