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"
27 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
31 #include "bufferview_funcs.h"
33 #include "CutAndPaste.h"
35 #include "DispatchResult.h"
37 #include "ErrorList.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
44 #include "InsetIterator.h"
52 #include "LyXAction.h"
58 #include "TextClassList.h"
60 #include "Paragraph.h"
61 #include "ParIterator.h"
62 #include "ParagraphParameters.h"
65 #include "insets/InsetBox.h"
66 #include "insets/InsetBranch.h"
67 #include "insets/InsetCommand.h"
68 #include "insets/InsetERT.h"
69 #include "insets/InsetExternal.h"
70 #include "insets/InsetFloat.h"
71 #include "insets/InsetListings.h"
72 #include "insets/InsetGraphics.h"
73 #include "insets/InsetInclude.h"
74 #include "insets/InsetNote.h"
75 #include "insets/InsetTabular.h"
76 #include "insets/InsetVSpace.h"
77 #include "insets/InsetWrap.h"
79 #include "frontends/Application.h"
80 #include "frontends/alert.h"
81 #include "frontends/Dialogs.h"
82 #include "frontends/FileDialog.h"
83 #include "frontends/FontLoader.h"
84 #include "frontends/Gui.h"
85 #include "frontends/KeySymbol.h"
86 #include "frontends/LyXView.h"
87 #include "frontends/Menubar.h"
88 #include "frontends/Selection.h"
89 #include "frontends/Toolbars.h"
90 #include "frontends/WorkArea.h"
92 #include "support/environment.h"
93 #include "support/FileFilterList.h"
94 #include "support/filetools.h"
95 #include "support/ForkedcallsController.h"
96 #include "support/fs_extras.h"
97 #include "support/lstrings.h"
98 #include "support/Path.h"
99 #include "support/Package.h"
100 #include "support/Systemcall.h"
101 #include "support/convert.h"
102 #include "support/os.h"
104 #include <boost/current_function.hpp>
105 #include <boost/filesystem/operations.hpp>
110 using std::make_pair;
113 using std::istringstream;
114 using std::ostringstream;
116 namespace fs = boost::filesystem;
120 using bv_funcs::freefont2string;
122 using frontend::LyXView;
124 using support::absolutePath;
125 using support::addName;
126 using support::addPath;
127 using support::bformat;
128 using support::changeExtension;
129 using support::contains;
130 using support::FileFilterList;
131 using support::FileName;
132 using support::fileSearch;
133 using support::ForkedcallsController;
134 using support::i18nLibFileSearch;
135 using support::isDirWriteable;
136 using support::isFileReadable;
137 using support::isStrInt;
138 using support::makeAbsPath;
139 using support::makeDisplayPath;
140 using support::package;
141 using support::quoteName;
142 using support::rtrim;
143 using support::split;
144 using support::subst;
145 using support::Systemcall;
146 using support::token;
148 using support::prefixIs;
150 namespace Alert = frontend::Alert;
155 bool getLocalStatus(Cursor cursor,
156 FuncRequest const & cmd, FuncStatus & status)
158 // Try to fix cursor in case it is broken.
159 cursor.fixIfBroken();
161 // This is, of course, a mess. Better create a new doc iterator and use
162 // this in Inset::getStatus. This might require an additional
163 // BufferView * arg, though (which should be avoided)
164 //Cursor safe = *this;
166 for ( ; cursor.depth(); cursor.pop()) {
167 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
168 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
169 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
170 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
172 // The inset's getStatus() will return 'true' if it made
173 // a definitive decision on whether it want to handle the
174 // request or not. The result of this decision is put into
175 // the 'status' parameter.
176 if (cursor.inset().getStatus(cursor, cmd, status)) {
185 /** Return the change status at cursor position, taking in account the
186 * status at each level of the document iterator (a table in a deleted
187 * footnote is deleted).
188 * When \param outer is true, the top slice is not looked at.
190 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
192 size_t const depth = dit.depth() - (outer ? 1 : 0);
194 for (size_t i = 0 ; i < depth ; ++i) {
195 CursorSlice const & slice = dit[i];
196 if (!slice.inset().inMathed()
197 && slice.pos() < slice.paragraph().size()) {
198 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
199 if (ch != Change::UNCHANGED)
203 return Change::UNCHANGED;
211 meta_fake_bit(key_modifier::none)
216 void LyXFunc::initKeySequences(KeyMap * kb)
218 keyseq.reset(new KeySequence(kb, kb));
219 cancel_meta_seq.reset(new KeySequence(kb, kb));
223 void LyXFunc::setLyXView(LyXView * lv)
225 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
226 // save current selection to the selection buffer to allow
227 // middle-button paste in another window
228 cap::saveSelection(lyx_view_->view()->cursor());
233 void LyXFunc::handleKeyFunc(kb_action action)
235 char_type c = encoded_last_key;
237 if (keyseq->length())
240 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
241 lyx_view_->view()->getIntl().getTransManager().deadkey(
242 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
243 // Need to clear, in case the minibuffer calls these
246 // copied verbatim from do_accent_char
247 view()->cursor().resetAnchor();
252 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
254 BOOST_ASSERT(lyx_view_);
255 if (!LyX::ref().session().bookmarks().isValid(idx))
257 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
258 BOOST_ASSERT(!bm.filename.empty());
259 string const file = bm.filename.absFilename();
260 // if the file is not opened, open it.
261 if (!theBufferList().exists(file)) {
263 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
267 // open may fail, so we need to test it again
268 if (theBufferList().exists(file)) {
269 // if the current buffer is not that one, switch to it.
270 if (lyx_view_->buffer()->fileName() != file) {
272 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
276 // moveToPosition try paragraph id first and then paragraph (pit, pos).
277 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
278 bm.top_id, bm.top_pos))
281 // Cursor jump succeeded!
282 Cursor const & cur = view()->cursor();
283 pit_type new_pit = cur.pit();
284 pos_type new_pos = cur.pos();
285 int new_id = cur.paragraph().id();
287 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
288 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
289 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos || bm.top_id != new_id )
290 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(new_pit, new_pos, new_id);
295 void LyXFunc::processKeySym(KeySymbolPtr keysym, key_modifier::state state)
297 LYXERR(Debug::KEY) << "KeySym is " << keysym->getSymbolName() << endl;
299 // Do nothing if we have nothing (JMarc)
300 if (!keysym->isOK()) {
301 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
306 if (keysym->isModifier()) {
307 LYXERR(Debug::KEY) << "isModifier true" << endl;
311 //Encoding const * encoding = view()->cursor().getEncoding();
312 //encoded_last_key = keysym->getISOEncoded(encoding ? encoding->name() : "");
313 // FIXME: encoded_last_key shadows the member variable of the same
314 // name. Is that intended?
315 char_type encoded_last_key = keysym->getUCSEncoded();
317 // Do a one-deep top-level lookup for
318 // cancel and meta-fake keys. RVDK_PATCH_5
319 cancel_meta_seq->reset();
321 FuncRequest func = cancel_meta_seq->addkey(keysym, state);
322 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
323 << " action first set to [" << func.action << ']'
326 // When not cancel or meta-fake, do the normal lookup.
327 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
328 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
329 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
330 // remove Caps Lock and Mod2 as a modifiers
331 func = keyseq->addkey(keysym, (state | meta_fake_bit));
332 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
333 << "action now set to ["
334 << func.action << ']' << endl;
337 // Dont remove this unless you know what you are doing.
338 meta_fake_bit = key_modifier::none;
340 // Can this happen now ?
341 if (func.action == LFUN_NOACTION) {
342 func = FuncRequest(LFUN_COMMAND_PREFIX);
345 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
347 << func.action << "]["
348 << to_utf8(keyseq->print(false)) << ']'
351 // already here we know if it any point in going further
352 // why not return already here if action == -1 and
353 // num_bytes == 0? (Lgb)
355 if (keyseq->length() > 1) {
356 lyx_view_->message(keyseq->print(true));
360 // Maybe user can only reach the key via holding down shift.
361 // Let's see. But only if shift is the only modifier
362 if (func.action == LFUN_UNKNOWN_ACTION &&
363 state == key_modifier::shift) {
364 LYXERR(Debug::KEY) << "Trying without shift" << endl;
365 func = keyseq->addkey(keysym, key_modifier::none);
366 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
369 if (func.action == LFUN_UNKNOWN_ACTION) {
370 // Hmm, we didn't match any of the keysequences. See
371 // if it's normal insertable text not already covered
373 if (keysym->isText() && keyseq->length() == 1) {
374 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
375 func = FuncRequest(LFUN_SELF_INSERT,
376 FuncRequest::KEYBOARD);
378 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
379 lyx_view_->message(_("Unknown function."));
384 if (func.action == LFUN_SELF_INSERT) {
385 if (encoded_last_key != 0) {
386 docstring const arg(1, encoded_last_key);
387 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
388 FuncRequest::KEYBOARD));
390 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
396 /* When we move around, or type, it's nice to be able to see
397 * the cursor immediately after the keypress.
399 if (lyx_view_ && lyx_view_->currentWorkArea())
400 lyx_view_->currentWorkArea()->startBlinkingCursor();
404 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
406 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
409 Cursor & cur = view()->cursor();
411 /* In LyX/Mac, when a dialog is open, the menus of the
412 application can still be accessed without giving focus to
413 the main window. In this case, we want to disable the menu
414 entries that are buffer-related.
416 Note that this code is not perfect, as bug 1941 attests:
417 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
419 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
420 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
423 if (cmd.action == LFUN_NOACTION) {
424 flag.message(from_utf8(N_("Nothing to do")));
429 switch (cmd.action) {
430 case LFUN_UNKNOWN_ACTION:
431 #ifndef HAVE_LIBAIKSAURUS
432 case LFUN_THESAURUS_ENTRY:
442 if (flag.unknown()) {
443 flag.message(from_utf8(N_("Unknown action")));
447 if (!flag.enabled()) {
448 if (flag.message().empty())
449 flag.message(from_utf8(N_("Command disabled")));
453 // Check whether we need a buffer
454 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
456 flag.message(from_utf8(N_("Command not allowed with"
457 "out any document open")));
462 // I would really like to avoid having this switch and rather try to
463 // encode this in the function itself.
464 // -- And I'd rather let an inset decide which LFUNs it is willing
465 // to handle (Andre')
467 switch (cmd.action) {
468 case LFUN_BUFFER_TOGGLE_READ_ONLY:
469 flag.setOnOff(buf->isReadonly());
472 case LFUN_BUFFER_SWITCH:
473 // toggle on the current buffer, but do not toggle off
474 // the other ones (is that a good idea?)
475 if (buf && to_utf8(cmd.argument()) == buf->fileName())
479 case LFUN_BUFFER_EXPORT:
480 enable = cmd.argument() == "custom"
481 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
484 case LFUN_BUFFER_CHKTEX:
485 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
488 case LFUN_BUILD_PROGRAM:
489 enable = Exporter::isExportable(*buf, "program");
492 case LFUN_LAYOUT_TABULAR:
493 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
497 case LFUN_LAYOUT_PARAGRAPH:
498 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
501 case LFUN_VC_REGISTER:
502 enable = !buf->lyxvc().inUse();
504 case LFUN_VC_CHECK_IN:
505 enable = buf->lyxvc().inUse() && !buf->isReadonly();
507 case LFUN_VC_CHECK_OUT:
508 enable = buf->lyxvc().inUse() && buf->isReadonly();
511 case LFUN_VC_UNDO_LAST:
512 enable = buf->lyxvc().inUse();
514 case LFUN_BUFFER_RELOAD:
515 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
516 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
519 case LFUN_INSET_SETTINGS: {
523 Inset::Code code = cur.inset().lyxCode();
525 case Inset::TABULAR_CODE:
526 enable = cmd.argument() == "tabular";
528 case Inset::ERT_CODE:
529 enable = cmd.argument() == "ert";
531 case Inset::FLOAT_CODE:
532 enable = cmd.argument() == "float";
534 case Inset::WRAP_CODE:
535 enable = cmd.argument() == "wrap";
537 case Inset::NOTE_CODE:
538 enable = cmd.argument() == "note";
540 case Inset::BRANCH_CODE:
541 enable = cmd.argument() == "branch";
543 case Inset::BOX_CODE:
544 enable = cmd.argument() == "box";
546 case Inset::LISTINGS_CODE:
547 enable = cmd.argument() == "listings";
555 case LFUN_INSET_APPLY: {
556 string const name = cmd.getArg(0);
557 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
559 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
561 if (!inset->getStatus(cur, fr, fs)) {
562 // Every inset is supposed to handle this
567 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
568 flag |= getStatus(fr);
570 enable = flag.enabled();
574 case LFUN_DIALOG_TOGGLE:
575 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
576 // fall through to set "enable"
577 case LFUN_DIALOG_SHOW: {
578 string const name = cmd.getArg(0);
580 enable = name == "aboutlyx"
581 || name == "file" //FIXME: should be removed.
583 || name == "texinfo";
584 else if (name == "print")
585 enable = Exporter::isExportable(*buf, "dvi")
586 && lyxrc.print_command != "none";
587 else if (name == "character")
588 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
589 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
590 else if (name == "latexlog")
591 enable = isFileReadable(FileName(buf->getLogName().second));
592 else if (name == "spellchecker")
593 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
594 enable = !buf->isReadonly();
598 else if (name == "vclog")
599 enable = buf->lyxvc().inUse();
603 case LFUN_DIALOG_SHOW_NEW_INSET:
604 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
605 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
606 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
608 if (cur.inset().getStatus(cur, cmd, flag))
613 case LFUN_DIALOG_UPDATE: {
614 string const name = cmd.getArg(0);
616 enable = name == "prefs";
620 case LFUN_CITATION_INSERT: {
621 FuncRequest fr(LFUN_INSET_INSERT, "citation");
622 enable = getStatus(fr).enabled();
626 case LFUN_BUFFER_WRITE: {
627 enable = lyx_view_->buffer()->isUnnamed()
628 || !lyx_view_->buffer()->isClean();
633 case LFUN_BUFFER_WRITE_ALL: {
634 // We enable the command only if there are some modified buffers
635 Buffer * first = theBufferList().first();
636 bool modified = false;
640 // We cannot use a for loop as the buffer list is a cycle.
646 b = theBufferList().next(b);
647 } while (b != first);
655 case LFUN_BOOKMARK_GOTO: {
656 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
657 enable = LyX::ref().session().bookmarks().isValid(num);
661 case LFUN_BOOKMARK_CLEAR:
662 enable = LyX::ref().session().bookmarks().size() > 0;
665 case LFUN_TOOLBAR_TOGGLE: {
666 bool const current = lyx_view_->getToolbars().visible(cmd.getArg(0));
667 flag.setOnOff(current);
670 case LFUN_WINDOW_CLOSE: {
671 enable = (theApp()->gui().viewIds().size() > 1);
675 // this one is difficult to get right. As a half-baked
676 // solution, we consider only the first action of the sequence
677 case LFUN_COMMAND_SEQUENCE: {
678 // argument contains ';'-terminated commands
679 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
680 FuncRequest func(lyxaction.lookupFunc(firstcmd));
681 func.origin = cmd.origin;
682 flag = getStatus(func);
685 case LFUN_BUFFER_NEW:
686 case LFUN_BUFFER_NEW_TEMPLATE:
687 case LFUN_WORD_FIND_FORWARD:
688 case LFUN_WORD_FIND_BACKWARD:
689 case LFUN_COMMAND_PREFIX:
690 case LFUN_COMMAND_EXECUTE:
692 case LFUN_META_PREFIX:
693 case LFUN_BUFFER_CLOSE:
694 case LFUN_BUFFER_WRITE_AS:
695 case LFUN_BUFFER_UPDATE:
696 case LFUN_BUFFER_VIEW:
697 case LFUN_BUFFER_IMPORT:
698 case LFUN_BUFFER_AUTO_SAVE:
699 case LFUN_RECONFIGURE:
703 case LFUN_DROP_LAYOUTS_CHOICE:
705 case LFUN_SERVER_GET_NAME:
706 case LFUN_SERVER_NOTIFY:
707 case LFUN_SERVER_GOTO_FILE_ROW:
708 case LFUN_DIALOG_HIDE:
709 case LFUN_DIALOG_DISCONNECT_INSET:
710 case LFUN_BUFFER_CHILD_OPEN:
711 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
712 case LFUN_KEYMAP_OFF:
713 case LFUN_KEYMAP_PRIMARY:
714 case LFUN_KEYMAP_SECONDARY:
715 case LFUN_KEYMAP_TOGGLE:
717 case LFUN_BUFFER_EXPORT_CUSTOM:
718 case LFUN_BUFFER_PRINT:
719 case LFUN_PREFERENCES_SAVE:
720 case LFUN_SCREEN_FONT_UPDATE:
723 case LFUN_EXTERNAL_EDIT:
724 case LFUN_GRAPHICS_EDIT:
725 case LFUN_ALL_INSETS_TOGGLE:
726 case LFUN_BUFFER_LANGUAGE:
727 case LFUN_TEXTCLASS_APPLY:
728 case LFUN_TEXTCLASS_LOAD:
729 case LFUN_BUFFER_SAVE_AS_DEFAULT:
730 case LFUN_BUFFER_PARAMS_APPLY:
731 case LFUN_LYXRC_APPLY:
732 case LFUN_BUFFER_NEXT:
733 case LFUN_BUFFER_PREVIOUS:
734 case LFUN_WINDOW_NEW:
736 // these are handled in our dispatch()
740 if (!getLocalStatus(cur, cmd, flag))
741 flag = view()->getStatus(cmd);
747 // Can we use a readonly buffer?
748 if (buf && buf->isReadonly()
749 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
750 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
751 flag.message(from_utf8(N_("Document is read-only")));
755 // Are we in a DELETED change-tracking region?
756 if (buf && lookupChangeType(cur, true) == Change::DELETED
757 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
758 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
759 flag.message(from_utf8(N_("This portion of the document is deleted.")));
763 // the default error message if we disable the command
764 if (!flag.enabled() && flag.message().empty())
765 flag.message(from_utf8(N_("Command disabled")));
771 bool LyXFunc::ensureBufferClean(BufferView * bv)
773 Buffer & buf = bv->buffer();
777 docstring const file = makeDisplayPath(buf.fileName(), 30);
778 docstring text = bformat(_("The document %1$s has unsaved "
779 "changes.\n\nDo you want to save "
780 "the document?"), file);
781 int const ret = Alert::prompt(_("Save changed document?"),
782 text, 0, 1, _("&Save"),
786 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
788 return buf.isClean();
794 void showPrintError(string const & name)
796 docstring str = bformat(_("Could not print the document %1$s.\n"
797 "Check that your printer is set up correctly."),
798 makeDisplayPath(name, 50));
799 Alert::error(_("Print document failed"), str);
803 void loadTextclass(string const & name)
805 std::pair<bool, textclass_type> const tc_pair =
806 textclasslist.numberOfClass(name);
808 if (!tc_pair.first) {
809 lyxerr << "Document class \"" << name
810 << "\" does not exist."
815 textclass_type const tc = tc_pair.second;
817 if (!textclasslist[tc].load()) {
818 docstring s = bformat(_("The document could not be converted\n"
819 "into the document class %1$s."),
820 from_utf8(textclasslist[tc].name()));
821 Alert::error(_("Could not change class"), s);
826 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
831 void LyXFunc::dispatch(FuncRequest const & cmd)
833 string const argument = to_utf8(cmd.argument());
834 kb_action const action = cmd.action;
836 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
837 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
839 // we have not done anything wrong yet.
841 dispatch_buffer.erase();
843 // redraw the screen at the end (first of the two drawing steps).
844 //This is done unless explicitely requested otherwise
845 Update::flags updateFlags = Update::FitCursor;
847 FuncStatus const flag = getStatus(cmd);
848 if (!flag.enabled()) {
849 // We cannot use this function here
850 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
851 << lyxaction.getActionName(action)
852 << " [" << action << "] is disabled at this location"
854 setErrorMessage(flag.message());
858 case LFUN_WORD_FIND_FORWARD:
859 case LFUN_WORD_FIND_BACKWARD: {
860 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
861 static docstring last_search;
862 docstring searched_string;
864 if (!cmd.argument().empty()) {
865 last_search = cmd.argument();
866 searched_string = cmd.argument();
868 searched_string = last_search;
871 if (searched_string.empty())
874 bool const fw = action == LFUN_WORD_FIND_FORWARD;
875 docstring const data =
876 find2string(searched_string, true, false, fw);
877 find(view(), FuncRequest(LFUN_WORD_FIND, data));
881 case LFUN_COMMAND_PREFIX:
882 BOOST_ASSERT(lyx_view_);
883 lyx_view_->message(keyseq->printOptions(true));
886 case LFUN_COMMAND_EXECUTE:
887 BOOST_ASSERT(lyx_view_);
888 lyx_view_->getToolbars().display("minibuffer", true);
889 lyx_view_->focus_command_buffer();
893 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
895 meta_fake_bit = key_modifier::none;
896 if (lyx_view_->buffer())
897 // cancel any selection
898 dispatch(FuncRequest(LFUN_MARK_OFF));
899 setMessage(from_ascii(N_("Cancel")));
902 case LFUN_META_PREFIX:
903 meta_fake_bit = key_modifier::alt;
904 setMessage(keyseq->print(true));
907 case LFUN_BUFFER_TOGGLE_READ_ONLY:
908 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
909 if (lyx_view_->buffer()->lyxvc().inUse())
910 lyx_view_->buffer()->lyxvc().toggleReadOnly();
912 lyx_view_->buffer()->setReadonly(
913 !lyx_view_->buffer()->isReadonly());
916 // --- Menus -----------------------------------------------
917 case LFUN_BUFFER_NEW:
918 menuNew(argument, false);
919 updateFlags = Update::None;
922 case LFUN_BUFFER_NEW_TEMPLATE:
923 menuNew(argument, true);
924 updateFlags = Update::None;
927 case LFUN_BUFFER_CLOSE:
929 updateFlags = Update::None;
932 case LFUN_BUFFER_WRITE:
933 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
934 if (!lyx_view_->buffer()->isUnnamed()) {
935 docstring const str = bformat(_("Saving document %1$s..."),
936 makeDisplayPath(lyx_view_->buffer()->fileName()));
937 lyx_view_->message(str);
938 menuWrite(lyx_view_->buffer());
939 lyx_view_->message(str + _(" done."));
941 writeAs(lyx_view_->buffer());
943 updateFlags = Update::None;
946 case LFUN_BUFFER_WRITE_AS:
947 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
948 writeAs(lyx_view_->buffer(), argument);
949 updateFlags = Update::None;
952 case LFUN_BUFFER_WRITE_ALL: {
953 Buffer * first = theBufferList().first();
956 lyx_view_->message(_("Saving all documents..."));
958 // We cannot use a for loop as the buffer list cycles.
961 if (!b->isUnnamed()) {
963 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
967 b = theBufferList().next(b);
968 } while (b != first);
969 lyx_view_->message(_("All documents saved."));
972 updateFlags = Update::None;
976 case LFUN_BUFFER_RELOAD: {
977 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
978 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
979 docstring text = bformat(_("Any changes will be lost. Are you sure "
980 "you want to revert to the saved version of the document %1$s?"), file);
981 int const ret = Alert::prompt(_("Revert to saved document?"),
982 text, 1, 1, _("&Revert"), _("&Cancel"));
989 case LFUN_BUFFER_UPDATE:
990 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
991 Exporter::Export(lyx_view_->buffer(), argument, true);
994 case LFUN_BUFFER_VIEW:
995 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
996 Exporter::preview(lyx_view_->buffer(), argument);
999 case LFUN_BUILD_PROGRAM:
1000 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1001 Exporter::Export(lyx_view_->buffer(), "program", true);
1004 case LFUN_BUFFER_CHKTEX:
1005 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1006 lyx_view_->buffer()->runChktex();
1009 case LFUN_BUFFER_EXPORT:
1010 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1011 if (argument == "custom")
1012 lyx_view_->getDialogs().show("sendto");
1014 Exporter::Export(lyx_view_->buffer(), argument, false);
1018 case LFUN_BUFFER_EXPORT_CUSTOM: {
1019 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1021 string command = split(argument, format_name, ' ');
1022 Format const * format = formats.getFormat(format_name);
1024 lyxerr << "Format \"" << format_name
1025 << "\" not recognized!"
1030 Buffer * buffer = lyx_view_->buffer();
1032 // The name of the file created by the conversion process
1035 // Output to filename
1036 if (format->name() == "lyx") {
1037 string const latexname =
1038 buffer->getLatexName(false);
1039 filename = changeExtension(latexname,
1040 format->extension());
1041 filename = addName(buffer->temppath(), filename);
1043 if (!buffer->writeFile(FileName(filename)))
1047 Exporter::Export(buffer, format_name, true, filename);
1050 // Substitute $$FName for filename
1051 if (!contains(command, "$$FName"))
1052 command = "( " + command + " ) < $$FName";
1053 command = subst(command, "$$FName", filename);
1055 // Execute the command in the background
1057 call.startscript(Systemcall::DontWait, command);
1061 case LFUN_BUFFER_PRINT: {
1062 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1063 // FIXME: cmd.getArg() might fail if one of the arguments
1064 // contains double quotes
1065 string target = cmd.getArg(0);
1066 string target_name = cmd.getArg(1);
1067 string command = cmd.getArg(2);
1070 || target_name.empty()
1071 || command.empty()) {
1072 lyxerr << "Unable to parse \""
1073 << argument << '"' << endl;
1076 if (target != "printer" && target != "file") {
1077 lyxerr << "Unrecognized target \""
1078 << target << '"' << endl;
1082 Buffer * buffer = lyx_view_->buffer();
1084 if (!Exporter::Export(buffer, "dvi", true)) {
1085 showPrintError(buffer->fileName());
1089 // Push directory path.
1090 string const path(buffer->temppath());
1091 // Prevent the compiler from optimizing away p
1093 support::Path p(pp);
1095 // there are three cases here:
1096 // 1. we print to a file
1097 // 2. we print directly to a printer
1098 // 3. we print using a spool command (print to file first)
1101 string const dviname =
1102 changeExtension(buffer->getLatexName(true),
1105 if (target == "printer") {
1106 if (!lyxrc.print_spool_command.empty()) {
1107 // case 3: print using a spool
1108 string const psname =
1109 changeExtension(dviname,".ps");
1110 command += ' ' + lyxrc.print_to_file
1113 + quoteName(dviname);
1116 lyxrc.print_spool_command + ' ';
1117 if (target_name != "default") {
1118 command2 += lyxrc.print_spool_printerprefix
1122 command2 += quoteName(psname);
1124 // If successful, then spool command
1125 res = one.startscript(
1130 res = one.startscript(
1131 Systemcall::DontWait,
1134 // case 2: print directly to a printer
1135 if (target_name != "default")
1136 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1137 res = one.startscript(
1138 Systemcall::DontWait,
1139 command + quoteName(dviname));
1143 // case 1: print to a file
1144 FileName const filename(makeAbsPath(target_name,
1145 lyx_view_->buffer()->filePath()));
1146 FileName const dvifile(makeAbsPath(dviname, path));
1147 if (fs::exists(filename.toFilesystemEncoding())) {
1148 docstring text = bformat(
1149 _("The file %1$s already exists.\n\n"
1150 "Do you want to overwrite that file?"),
1151 makeDisplayPath(filename.absFilename()));
1152 if (Alert::prompt(_("Overwrite file?"),
1153 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1156 command += ' ' + lyxrc.print_to_file
1157 + quoteName(filename.toFilesystemEncoding())
1159 + quoteName(dvifile.toFilesystemEncoding());
1160 res = one.startscript(Systemcall::DontWait,
1165 showPrintError(buffer->fileName());
1169 case LFUN_BUFFER_IMPORT:
1174 // quitting is triggered by the gui code
1175 // (leaving the event loop).
1176 lyx_view_->message(from_utf8(N_("Exiting.")));
1177 if (theBufferList().quitWriteAll())
1178 theApp()->gui().closeAllViews();
1181 case LFUN_BUFFER_AUTO_SAVE:
1185 case LFUN_RECONFIGURE:
1186 BOOST_ASSERT(lyx_view_);
1187 reconfigure(*lyx_view_);
1190 case LFUN_HELP_OPEN: {
1191 BOOST_ASSERT(lyx_view_);
1192 string const arg = argument;
1194 setErrorMessage(from_ascii(N_("Missing argument")));
1197 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1198 if (fname.empty()) {
1199 lyxerr << "LyX: unable to find documentation file `"
1200 << arg << "'. Bad installation?" << endl;
1203 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1204 makeDisplayPath(fname.absFilename())));
1205 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1208 lyx_view_->setBuffer(buf);
1209 lyx_view_->showErrorList("Parse");
1211 updateFlags = Update::None;
1215 // --- version control -------------------------------
1216 case LFUN_VC_REGISTER:
1217 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1218 if (!ensureBufferClean(view()))
1220 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1221 lyx_view_->buffer()->lyxvc().registrer();
1224 updateFlags = Update::Force;
1227 case LFUN_VC_CHECK_IN:
1228 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1229 if (!ensureBufferClean(view()))
1231 if (lyx_view_->buffer()->lyxvc().inUse()
1232 && !lyx_view_->buffer()->isReadonly()) {
1233 lyx_view_->buffer()->lyxvc().checkIn();
1238 case LFUN_VC_CHECK_OUT:
1239 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1240 if (!ensureBufferClean(view()))
1242 if (lyx_view_->buffer()->lyxvc().inUse()
1243 && lyx_view_->buffer()->isReadonly()) {
1244 lyx_view_->buffer()->lyxvc().checkOut();
1249 case LFUN_VC_REVERT:
1250 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1251 lyx_view_->buffer()->lyxvc().revert();
1255 case LFUN_VC_UNDO_LAST:
1256 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1257 lyx_view_->buffer()->lyxvc().undoLast();
1261 // --- buffers ----------------------------------------
1262 case LFUN_BUFFER_SWITCH:
1263 BOOST_ASSERT(lyx_view_);
1264 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1265 updateFlags = Update::None;
1268 case LFUN_BUFFER_NEXT:
1269 BOOST_ASSERT(lyx_view_);
1270 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1271 updateFlags = Update::None;
1274 case LFUN_BUFFER_PREVIOUS:
1275 BOOST_ASSERT(lyx_view_);
1276 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1277 updateFlags = Update::None;
1281 BOOST_ASSERT(lyx_view_);
1282 newFile(*lyx_view_, argument);
1283 updateFlags = Update::None;
1286 case LFUN_FILE_OPEN:
1287 BOOST_ASSERT(lyx_view_);
1289 updateFlags = Update::None;
1292 case LFUN_DROP_LAYOUTS_CHOICE:
1293 BOOST_ASSERT(lyx_view_);
1294 lyx_view_->getToolbars().openLayoutList();
1297 case LFUN_MENU_OPEN:
1298 BOOST_ASSERT(lyx_view_);
1299 lyx_view_->getMenubar().openByName(from_utf8(argument));
1302 // --- lyxserver commands ----------------------------
1303 case LFUN_SERVER_GET_NAME:
1304 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1305 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1306 LYXERR(Debug::INFO) << "FNAME["
1307 << lyx_view_->buffer()->fileName()
1311 case LFUN_SERVER_NOTIFY:
1312 dispatch_buffer = keyseq->print(false);
1313 theServer().notifyClient(to_utf8(dispatch_buffer));
1316 case LFUN_SERVER_GOTO_FILE_ROW: {
1317 BOOST_ASSERT(lyx_view_);
1320 istringstream is(argument);
1321 is >> file_name >> row;
1323 bool loaded = false;
1324 if (prefixIs(file_name, package().temp_dir().absFilename()))
1325 // Needed by inverse dvi search. If it is a file
1326 // in tmpdir, call the apropriated function
1327 buf = theBufferList().getBufferFromTmp(file_name);
1329 // Must replace extension of the file to be .lyx
1330 // and get full path
1331 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1332 // Either change buffer or load the file
1333 if (theBufferList().exists(s.absFilename()))
1334 buf = theBufferList().getBuffer(s.absFilename());
1336 buf = lyx_view_->loadLyXFile(s);
1342 updateFlags = Update::None;
1347 lyx_view_->setBuffer(buf);
1348 view()->setCursorFromRow(row);
1350 lyx_view_->showErrorList("Parse");
1351 updateFlags = Update::FitCursor;
1355 case LFUN_DIALOG_SHOW: {
1356 BOOST_ASSERT(lyx_view_);
1357 string const name = cmd.getArg(0);
1358 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1360 if (name == "character") {
1361 data = freefont2string();
1363 lyx_view_->getDialogs().show("character", data);
1364 } else if (name == "latexlog") {
1365 pair<Buffer::LogType, string> const logfile =
1366 lyx_view_->buffer()->getLogName();
1367 switch (logfile.first) {
1368 case Buffer::latexlog:
1371 case Buffer::buildlog:
1375 data += Lexer::quoteString(logfile.second);
1376 lyx_view_->getDialogs().show("log", data);
1377 } else if (name == "vclog") {
1378 string const data = "vc " +
1379 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1380 lyx_view_->getDialogs().show("log", data);
1382 lyx_view_->getDialogs().show(name, data);
1386 case LFUN_DIALOG_SHOW_NEW_INSET: {
1387 BOOST_ASSERT(lyx_view_);
1388 string const name = cmd.getArg(0);
1389 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1390 if (name == "bibitem" ||
1394 name == "nomenclature" ||
1398 InsetCommandParams p(name);
1399 data = InsetCommandMailer::params2string(name, p);
1400 } else if (name == "include") {
1401 // data is the include type: one of "include",
1402 // "input", "verbatiminput" or "verbatiminput*"
1404 // default type is requested
1406 InsetCommandParams p(data);
1407 data = InsetIncludeMailer::params2string(p);
1408 } else if (name == "box") {
1409 // \c data == "Boxed" || "Frameless" etc
1410 InsetBoxParams p(data);
1411 data = InsetBoxMailer::params2string(p);
1412 } else if (name == "branch") {
1413 InsetBranchParams p;
1414 data = InsetBranchMailer::params2string(p);
1415 } else if (name == "citation") {
1416 InsetCommandParams p("cite");
1417 data = InsetCommandMailer::params2string(name, p);
1418 } else if (name == "ert") {
1419 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1420 } else if (name == "external") {
1421 InsetExternalParams p;
1422 Buffer const & buffer = *lyx_view_->buffer();
1423 data = InsetExternalMailer::params2string(p, buffer);
1424 } else if (name == "float") {
1426 data = InsetFloatMailer::params2string(p);
1427 } else if (name == "listings") {
1428 InsetListingsParams p;
1429 data = InsetListingsMailer::params2string(p);
1430 } else if (name == "graphics") {
1431 InsetGraphicsParams p;
1432 Buffer const & buffer = *lyx_view_->buffer();
1433 data = InsetGraphicsMailer::params2string(p, buffer);
1434 } else if (name == "note") {
1436 data = InsetNoteMailer::params2string(p);
1437 } else if (name == "vspace") {
1439 data = InsetVSpaceMailer::params2string(space);
1440 } else if (name == "wrap") {
1442 data = InsetWrapMailer::params2string(p);
1444 lyx_view_->getDialogs().show(name, data, 0);
1448 case LFUN_DIALOG_UPDATE: {
1449 BOOST_ASSERT(lyx_view_);
1450 string const & name = argument;
1451 // Can only update a dialog connected to an existing inset
1452 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1454 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1455 inset->dispatch(view()->cursor(), fr);
1456 } else if (name == "paragraph") {
1457 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1458 } else if (name == "prefs") {
1459 lyx_view_->getDialogs().update(name, string());
1464 case LFUN_DIALOG_HIDE:
1465 LyX::cref().hideDialogs(argument, 0);
1468 case LFUN_DIALOG_TOGGLE: {
1469 BOOST_ASSERT(lyx_view_);
1470 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1471 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1473 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1477 case LFUN_DIALOG_DISCONNECT_INSET:
1478 BOOST_ASSERT(lyx_view_);
1479 lyx_view_->getDialogs().disconnect(argument);
1483 case LFUN_CITATION_INSERT: {
1484 BOOST_ASSERT(lyx_view_);
1485 if (!argument.empty()) {
1486 // we can have one optional argument, delimited by '|'
1487 // citation-insert <key>|<text_before>
1488 // this should be enhanced to also support text_after
1489 // and citation style
1490 string arg = argument;
1492 if (contains(argument, "|")) {
1493 arg = token(argument, '|', 0);
1494 opt1 = token(argument, '|', 1);
1496 InsetCommandParams icp("cite");
1497 icp["key"] = from_utf8(arg);
1499 icp["before"] = from_utf8(opt1);
1500 string icstr = InsetCommandMailer::params2string("citation", icp);
1501 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1504 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1508 case LFUN_BUFFER_CHILD_OPEN: {
1509 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1510 Buffer * parent = lyx_view_->buffer();
1511 FileName filename = makeAbsPath(argument, parent->filePath());
1512 view()->saveBookmark(false);
1514 bool parsed = false;
1515 if (theBufferList().exists(filename.absFilename())) {
1516 child = theBufferList().getBuffer(filename.absFilename());
1518 setMessage(bformat(_("Opening child document %1$s..."),
1519 makeDisplayPath(filename.absFilename())));
1520 child = lyx_view_->loadLyXFile(filename, true);
1524 // Set the parent name of the child document.
1525 // This makes insertion of citations and references in the child work,
1526 // when the target is in the parent or another child document.
1527 child->setParentName(parent->fileName());
1528 updateLabels(*child->getMasterBuffer());
1529 lyx_view_->setBuffer(child);
1531 lyx_view_->showErrorList("Parse");
1534 // If a screen update is required (in case where auto_open is false),
1535 // setBuffer() would have taken care of it already. Otherwise we shall
1536 // reset the update flag because it can cause a circular problem.
1538 updateFlags = Update::None;
1542 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1543 BOOST_ASSERT(lyx_view_);
1544 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1547 case LFUN_KEYMAP_OFF:
1548 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1549 lyx_view_->view()->getIntl().keyMapOn(false);
1552 case LFUN_KEYMAP_PRIMARY:
1553 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1554 lyx_view_->view()->getIntl().keyMapPrim();
1557 case LFUN_KEYMAP_SECONDARY:
1558 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1559 lyx_view_->view()->getIntl().keyMapSec();
1562 case LFUN_KEYMAP_TOGGLE:
1563 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1564 lyx_view_->view()->getIntl().toggleKeyMap();
1570 string rest = split(argument, countstr, ' ');
1571 istringstream is(countstr);
1574 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1575 for (int i = 0; i < count; ++i)
1576 dispatch(lyxaction.lookupFunc(rest));
1580 case LFUN_COMMAND_SEQUENCE: {
1581 // argument contains ';'-terminated commands
1582 string arg = argument;
1583 while (!arg.empty()) {
1585 arg = split(arg, first, ';');
1586 FuncRequest func(lyxaction.lookupFunc(first));
1587 func.origin = cmd.origin;
1593 case LFUN_PREFERENCES_SAVE: {
1594 lyxrc.write(makeAbsPath("preferences",
1595 package().user_support().absFilename()),
1600 case LFUN_SCREEN_FONT_UPDATE:
1601 BOOST_ASSERT(lyx_view_);
1602 // handle the screen font changes.
1603 theFontLoader().update();
1604 /// FIXME: only the current view will be updated. the Gui
1605 /// class is able to furnish the list of views.
1606 updateFlags = Update::Force;
1609 case LFUN_SET_COLOR: {
1611 string const x11_name = split(argument, lyx_name, ' ');
1612 if (lyx_name.empty() || x11_name.empty()) {
1613 setErrorMessage(from_ascii(N_(
1614 "Syntax: set-color <lyx_name>"
1619 bool const graphicsbg_changed =
1620 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1621 x11_name != lcolor.getX11Name(Color::graphicsbg));
1623 if (!lcolor.setColor(lyx_name, x11_name)) {
1625 bformat(_("Set-color \"%1$s\" failed "
1626 "- color is undefined or "
1627 "may not be redefined"),
1628 from_utf8(lyx_name)));
1632 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1634 if (graphicsbg_changed) {
1635 // FIXME: The graphics cache no longer has a changeDisplay method.
1637 graphics::GCache::get().changeDisplay(true);
1644 BOOST_ASSERT(lyx_view_);
1645 lyx_view_->message(from_utf8(argument));
1648 case LFUN_EXTERNAL_EDIT: {
1649 BOOST_ASSERT(lyx_view_);
1650 FuncRequest fr(action, argument);
1651 InsetExternal().dispatch(view()->cursor(), fr);
1655 case LFUN_GRAPHICS_EDIT: {
1656 FuncRequest fr(action, argument);
1657 InsetGraphics().dispatch(view()->cursor(), fr);
1661 case LFUN_INSET_APPLY: {
1662 BOOST_ASSERT(lyx_view_);
1663 string const name = cmd.getArg(0);
1664 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1666 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1667 inset->dispatch(view()->cursor(), fr);
1669 FuncRequest fr(LFUN_INSET_INSERT, argument);
1672 // ideally, the update flag should be set by the insets,
1673 // but this is not possible currently
1674 updateFlags = Update::Force | Update::FitCursor;
1678 case LFUN_ALL_INSETS_TOGGLE: {
1679 BOOST_ASSERT(lyx_view_);
1681 string const name = split(argument, action, ' ');
1682 Inset::Code const inset_code =
1683 Inset::translate(name);
1685 Cursor & cur = view()->cursor();
1686 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1688 Inset & inset = lyx_view_->buffer()->inset();
1689 InsetIterator it = inset_iterator_begin(inset);
1690 InsetIterator const end = inset_iterator_end(inset);
1691 for (; it != end; ++it) {
1692 if (!it->asInsetMath()
1693 && (inset_code == Inset::NO_CODE
1694 || inset_code == it->lyxCode())) {
1695 Cursor tmpcur = cur;
1696 tmpcur.pushLeft(*it);
1697 it->dispatch(tmpcur, fr);
1700 updateFlags = Update::Force | Update::FitCursor;
1704 case LFUN_BUFFER_LANGUAGE: {
1705 BOOST_ASSERT(lyx_view_);
1706 Buffer & buffer = *lyx_view_->buffer();
1707 Language const * oldL = buffer.params().language;
1708 Language const * newL = languages.getLanguage(argument);
1709 if (!newL || oldL == newL)
1712 if (oldL->rightToLeft() == newL->rightToLeft()
1713 && !buffer.isMultiLingual())
1714 buffer.changeLanguage(oldL, newL);
1718 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1719 string const fname =
1720 addName(addPath(package().user_support().absFilename(), "templates/"),
1722 Buffer defaults(fname);
1724 istringstream ss(argument);
1727 int const unknown_tokens = defaults.readHeader(lex);
1729 if (unknown_tokens != 0) {
1730 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1731 << unknown_tokens << " unknown token"
1732 << (unknown_tokens == 1 ? "" : "s")
1736 if (defaults.writeFile(FileName(defaults.fileName())))
1737 setMessage(bformat(_("Document defaults saved in %1$s"),
1738 makeDisplayPath(fname)));
1740 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1744 case LFUN_BUFFER_PARAMS_APPLY: {
1745 BOOST_ASSERT(lyx_view_);
1746 biblio::CiteEngine const engine =
1747 lyx_view_->buffer()->params().getEngine();
1749 istringstream ss(argument);
1752 int const unknown_tokens =
1753 lyx_view_->buffer()->readHeader(lex);
1755 if (unknown_tokens != 0) {
1756 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1757 << unknown_tokens << " unknown token"
1758 << (unknown_tokens == 1 ? "" : "s")
1761 if (engine == lyx_view_->buffer()->params().getEngine())
1764 Cursor & cur = view()->cursor();
1765 FuncRequest fr(LFUN_INSET_REFRESH);
1767 Inset & inset = lyx_view_->buffer()->inset();
1768 InsetIterator it = inset_iterator_begin(inset);
1769 InsetIterator const end = inset_iterator_end(inset);
1770 for (; it != end; ++it)
1771 if (it->lyxCode() == Inset::CITE_CODE)
1772 it->dispatch(cur, fr);
1776 case LFUN_TEXTCLASS_APPLY: {
1777 BOOST_ASSERT(lyx_view_);
1778 Buffer * buffer = lyx_view_->buffer();
1780 textclass_type const old_class =
1781 buffer->params().textclass;
1783 loadTextclass(argument);
1785 std::pair<bool, textclass_type> const tc_pair =
1786 textclasslist.numberOfClass(argument);
1791 textclass_type const new_class = tc_pair.second;
1792 if (old_class == new_class)
1796 lyx_view_->message(_("Converting document to new document class..."));
1797 recordUndoFullDocument(view());
1798 buffer->params().textclass = new_class;
1799 StableDocIterator backcur(view()->cursor());
1800 ErrorList & el = buffer->errorList("Class Switch");
1801 cap::switchBetweenClasses(
1802 old_class, new_class,
1803 static_cast<InsetText &>(buffer->inset()), el);
1805 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1807 buffer->errors("Class Switch");
1808 updateLabels(*buffer);
1809 updateFlags = Update::Force | Update::FitCursor;
1813 case LFUN_TEXTCLASS_LOAD:
1814 loadTextclass(argument);
1817 case LFUN_LYXRC_APPLY: {
1818 LyXRC const lyxrc_orig = lyxrc;
1820 istringstream ss(argument);
1821 bool const success = lyxrc.read(ss) == 0;
1824 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1825 << "Unable to read lyxrc data"
1830 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1832 /// We force the redraw in any case because there might be
1833 /// some screen font changes.
1834 /// FIXME: only the current view will be updated. the Gui
1835 /// class is able to furnish the list of views.
1836 updateFlags = Update::Force;
1840 case LFUN_WINDOW_NEW:
1841 LyX::ref().newLyXView();
1844 case LFUN_WINDOW_CLOSE:
1845 BOOST_ASSERT(lyx_view_);
1846 BOOST_ASSERT(theApp());
1847 // update bookmark pit of the current buffer before window close
1848 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1849 gotoBookmark(i+1, false, false);
1850 // ask the user for saving changes or cancel quit
1851 if (!theBufferList().quitWriteAll())
1856 case LFUN_BOOKMARK_GOTO:
1857 // go to bookmark, open unopened file and switch to buffer if necessary
1858 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1861 case LFUN_BOOKMARK_CLEAR:
1862 LyX::ref().session().bookmarks().clear();
1865 case LFUN_TOOLBAR_TOGGLE: {
1866 BOOST_ASSERT(lyx_view_);
1867 string const name = cmd.getArg(0);
1868 bool const allowauto = cmd.getArg(1) == "allowauto";
1869 lyx_view_->toggleToolbarState(name, allowauto);
1870 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1872 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1877 if (tbi->flags & ToolbarInfo::ON)
1879 else if (tbi->flags & ToolbarInfo::OFF)
1881 else if (tbi->flags & ToolbarInfo::AUTO)
1884 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1885 _(tbi->gui_name), state));
1890 BOOST_ASSERT(lyx_view_);
1891 view()->cursor().dispatch(cmd);
1892 updateFlags = view()->cursor().result().update();
1893 if (!view()->cursor().result().dispatched())
1894 updateFlags = view()->dispatch(cmd);
1899 if (lyx_view_ && lyx_view_->buffer()) {
1900 // BufferView::update() updates the ViewMetricsInfo and
1901 // also initializes the position cache for all insets in
1902 // (at least partially) visible top-level paragraphs.
1903 // We will redraw the screen only if needed.
1904 if (view()->update(updateFlags)) {
1905 // Buffer::changed() signals that a repaint is needed.
1906 // The frontend (WorkArea) knows which area to repaint
1907 // thanks to the ViewMetricsInfo updated above.
1908 lyx_view_->buffer()->changed();
1911 lyx_view_->updateStatusBar();
1913 // if we executed a mutating lfun, mark the buffer as dirty
1915 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1916 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1917 lyx_view_->buffer()->markDirty();
1919 //Do we have a selection?
1920 theSelection().haveSelection(view()->cursor().selection());
1922 if (view()->cursor().inTexted()) {
1923 lyx_view_->updateLayoutChoice();
1927 if (!quitting && lyx_view_) {
1928 lyx_view_->updateMenubar();
1929 lyx_view_->updateToolbars();
1930 // Some messages may already be translated, so we cannot use _()
1931 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1936 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1938 const bool verbose = (cmd.origin == FuncRequest::MENU
1939 || cmd.origin == FuncRequest::TOOLBAR
1940 || cmd.origin == FuncRequest::COMMANDBUFFER);
1942 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1943 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1945 lyx_view_->message(msg);
1949 docstring dispatch_msg = msg;
1950 if (!dispatch_msg.empty())
1951 dispatch_msg += ' ';
1953 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1955 bool argsadded = false;
1957 if (!cmd.argument().empty()) {
1958 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1959 comname += ' ' + cmd.argument();
1964 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
1966 if (!shortcuts.empty())
1967 comname += ": " + shortcuts;
1968 else if (!argsadded && !cmd.argument().empty())
1969 comname += ' ' + cmd.argument();
1971 if (!comname.empty()) {
1972 comname = rtrim(comname);
1973 dispatch_msg += '(' + rtrim(comname) + ')';
1976 LYXERR(Debug::ACTION) << "verbose dispatch msg "
1977 << to_utf8(dispatch_msg) << endl;
1978 if (!dispatch_msg.empty())
1979 lyx_view_->message(dispatch_msg);
1983 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1985 // FIXME: initpath is not used. What to do?
1986 string initpath = lyxrc.document_path;
1987 string filename(name);
1989 if (lyx_view_->buffer()) {
1990 string const trypath = lyx_view_->buffer()->filePath();
1991 // If directory is writeable, use this as default.
1992 if (isDirWriteable(FileName(trypath)))
1996 static int newfile_number;
1998 if (filename.empty()) {
1999 filename = addName(lyxrc.document_path,
2000 "newfile" + convert<string>(++newfile_number) + ".lyx");
2001 while (theBufferList().exists(filename) ||
2002 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2004 filename = addName(lyxrc.document_path,
2005 "newfile" + convert<string>(newfile_number) +
2010 // The template stuff
2013 FileDialog fileDlg(_("Select template file"),
2014 LFUN_SELECT_FILE_SYNC,
2015 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2016 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2018 FileDialog::Result result =
2019 fileDlg.open(from_utf8(lyxrc.template_path),
2020 FileFilterList(_("LyX Documents (*.lyx)")),
2023 if (result.first == FileDialog::Later)
2025 if (result.second.empty())
2027 templname = to_utf8(result.second);
2030 Buffer * const b = newFile(filename, templname, !name.empty());
2032 lyx_view_->setBuffer(b);
2036 void LyXFunc::open(string const & fname)
2038 string initpath = lyxrc.document_path;
2040 if (lyx_view_->buffer()) {
2041 string const trypath = lyx_view_->buffer()->filePath();
2042 // If directory is writeable, use this as default.
2043 if (isDirWriteable(FileName(trypath)))
2049 if (fname.empty()) {
2050 FileDialog fileDlg(_("Select document to open"),
2052 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2053 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2055 FileDialog::Result result =
2056 fileDlg.open(from_utf8(initpath),
2057 FileFilterList(_("LyX Documents (*.lyx)")),
2060 if (result.first == FileDialog::Later)
2063 filename = to_utf8(result.second);
2065 // check selected filename
2066 if (filename.empty()) {
2067 lyx_view_->message(_("Canceled."));
2073 // get absolute path of file and add ".lyx" to the filename if
2075 FileName const fullname = fileSearch(string(), filename, "lyx");
2076 if (!fullname.empty())
2077 filename = fullname.absFilename();
2079 // if the file doesn't exist, let the user create one
2080 if (!fs::exists(fullname.toFilesystemEncoding())) {
2081 // the user specifically chose this name. Believe him.
2082 Buffer * const b = newFile(filename, string(), true);
2084 lyx_view_->setBuffer(b);
2088 docstring const disp_fn = makeDisplayPath(filename);
2089 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2092 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2095 lyx_view_->setBuffer(buf);
2096 lyx_view_->showErrorList("Parse");
2097 str2 = bformat(_("Document %1$s opened."), disp_fn);
2099 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2101 lyx_view_->message(str2);
2105 void LyXFunc::doImport(string const & argument)
2108 string filename = split(argument, format, ' ');
2110 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2111 << " file: " << filename << endl;
2113 // need user interaction
2114 if (filename.empty()) {
2115 string initpath = lyxrc.document_path;
2117 if (lyx_view_->buffer()) {
2118 string const trypath = lyx_view_->buffer()->filePath();
2119 // If directory is writeable, use this as default.
2120 if (isDirWriteable(FileName(trypath)))
2124 docstring const text = bformat(_("Select %1$s file to import"),
2125 formats.prettyName(format));
2127 FileDialog fileDlg(text,
2129 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2130 make_pair(_("Examples|#E#e"),
2131 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2133 docstring filter = formats.prettyName(format);
2136 filter += from_utf8(formats.extension(format));
2139 FileDialog::Result result =
2140 fileDlg.open(from_utf8(initpath),
2141 FileFilterList(filter),
2144 if (result.first == FileDialog::Later)
2147 filename = to_utf8(result.second);
2149 // check selected filename
2150 if (filename.empty())
2151 lyx_view_->message(_("Canceled."));
2154 if (filename.empty())
2157 // get absolute path of file
2158 FileName const fullname(makeAbsPath(filename));
2160 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2162 // Check if the document already is open
2163 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2164 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2165 lyx_view_->message(_("Canceled."));
2170 // if the file exists already, and we didn't do
2171 // -i lyx thefile.lyx, warn
2172 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2173 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2175 docstring text = bformat(_("The document %1$s already exists.\n\n"
2176 "Do you want to overwrite that document?"), file);
2177 int const ret = Alert::prompt(_("Overwrite document?"),
2178 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2181 lyx_view_->message(_("Canceled."));
2186 ErrorList errorList;
2187 Importer::Import(lyx_view_, fullname, format, errorList);
2188 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2192 void LyXFunc::closeBuffer()
2194 // goto bookmark to update bookmark pit.
2195 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2196 gotoBookmark(i+1, false, false);
2198 theBufferList().close(lyx_view_->buffer(), true);
2202 void LyXFunc::reloadBuffer()
2204 FileName filename(lyx_view_->buffer()->fileName());
2205 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2208 Buffer * buf = lyx_view_->loadLyXFile(filename);
2211 lyx_view_->setBuffer(buf);
2212 lyx_view_->showErrorList("Parse");
2213 str = bformat(_("Document %1$s reloaded."), disp_fn);
2215 str = bformat(_("Could not reload document %1$s"), disp_fn);
2217 lyx_view_->message(str);
2220 // Each "lyx_view_" should have it's own message method. lyxview and
2221 // the minibuffer would use the minibuffer, but lyxserver would
2222 // send an ERROR signal to its client. Alejandro 970603
2223 // This function is bit problematic when it comes to NLS, to make the
2224 // lyx servers client be language indepenent we must not translate
2225 // strings sent to this func.
2226 void LyXFunc::setErrorMessage(docstring const & m) const
2228 dispatch_buffer = m;
2233 void LyXFunc::setMessage(docstring const & m) const
2235 dispatch_buffer = m;
2239 docstring const LyXFunc::viewStatusMessage()
2241 // When meta-fake key is pressed, show the key sequence so far + "M-".
2243 return keyseq->print(true) + "M-";
2245 // Else, when a non-complete key sequence is pressed,
2246 // show the available options.
2247 if (keyseq->length() > 0 && !keyseq->deleted())
2248 return keyseq->printOptions(true);
2250 BOOST_ASSERT(lyx_view_);
2251 if (!lyx_view_->buffer())
2252 return _("Welcome to LyX!");
2254 return view()->cursor().currentState();
2258 BufferView * LyXFunc::view() const
2260 BOOST_ASSERT(lyx_view_);
2261 return lyx_view_->view();
2265 bool LyXFunc::wasMetaKey() const
2267 return (meta_fake_bit != key_modifier::none);
2273 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2275 // Why the switch you might ask. It is a trick to ensure that all
2276 // the elements in the LyXRCTags enum is handled. As you can see
2277 // there are no breaks at all. So it is just a huge fall-through.
2278 // The nice thing is that we will get a warning from the compiler
2279 // if we forget an element.
2280 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2282 case LyXRC::RC_ACCEPT_COMPOUND:
2283 case LyXRC::RC_ALT_LANG:
2284 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2285 case LyXRC::RC_PLAINTEXT_LINELEN:
2286 case LyXRC::RC_AUTOREGIONDELETE:
2287 case LyXRC::RC_AUTORESET_OPTIONS:
2288 case LyXRC::RC_AUTOSAVE:
2289 case LyXRC::RC_AUTO_NUMBER:
2290 case LyXRC::RC_BACKUPDIR_PATH:
2291 case LyXRC::RC_BIBTEX_COMMAND:
2292 case LyXRC::RC_BINDFILE:
2293 case LyXRC::RC_CHECKLASTFILES:
2294 case LyXRC::RC_USELASTFILEPOS:
2295 case LyXRC::RC_LOADSESSION:
2296 case LyXRC::RC_CHKTEX_COMMAND:
2297 case LyXRC::RC_CONVERTER:
2298 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2299 case LyXRC::RC_COPIER:
2300 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2301 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2302 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2303 case LyXRC::RC_DATE_INSERT_FORMAT:
2304 case LyXRC::RC_DEFAULT_LANGUAGE:
2305 case LyXRC::RC_DEFAULT_PAPERSIZE:
2306 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2307 case LyXRC::RC_DISPLAY_GRAPHICS:
2308 case LyXRC::RC_DOCUMENTPATH:
2309 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2310 string const encoded = FileName(
2311 lyxrc_new.document_path).toFilesystemEncoding();
2312 if (fs::exists(encoded) && fs::is_directory(encoded))
2313 support::package().document_dir() = FileName(lyxrc.document_path);
2315 case LyXRC::RC_ESC_CHARS:
2316 case LyXRC::RC_FONT_ENCODING:
2317 case LyXRC::RC_FORMAT:
2318 case LyXRC::RC_INDEX_COMMAND:
2319 case LyXRC::RC_INPUT:
2320 case LyXRC::RC_KBMAP:
2321 case LyXRC::RC_KBMAP_PRIMARY:
2322 case LyXRC::RC_KBMAP_SECONDARY:
2323 case LyXRC::RC_LABEL_INIT_LENGTH:
2324 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2325 case LyXRC::RC_LANGUAGE_AUTO_END:
2326 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2327 case LyXRC::RC_LANGUAGE_COMMAND_END:
2328 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2329 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2330 case LyXRC::RC_LANGUAGE_PACKAGE:
2331 case LyXRC::RC_LANGUAGE_USE_BABEL:
2332 case LyXRC::RC_MAKE_BACKUP:
2333 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2334 case LyXRC::RC_NUMLASTFILES:
2335 case LyXRC::RC_PATH_PREFIX:
2336 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2337 support::prependEnvPath("PATH", lyxrc.path_prefix);
2339 case LyXRC::RC_PERS_DICT:
2340 case LyXRC::RC_PREVIEW:
2341 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2342 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2343 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2344 case LyXRC::RC_PRINTCOPIESFLAG:
2345 case LyXRC::RC_PRINTER:
2346 case LyXRC::RC_PRINTEVENPAGEFLAG:
2347 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2348 case LyXRC::RC_PRINTFILEEXTENSION:
2349 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2350 case LyXRC::RC_PRINTODDPAGEFLAG:
2351 case LyXRC::RC_PRINTPAGERANGEFLAG:
2352 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2353 case LyXRC::RC_PRINTPAPERFLAG:
2354 case LyXRC::RC_PRINTREVERSEFLAG:
2355 case LyXRC::RC_PRINTSPOOL_COMMAND:
2356 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2357 case LyXRC::RC_PRINTTOFILE:
2358 case LyXRC::RC_PRINTTOPRINTER:
2359 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2360 case LyXRC::RC_PRINT_COMMAND:
2361 case LyXRC::RC_RTL_SUPPORT:
2362 case LyXRC::RC_SCREEN_DPI:
2363 case LyXRC::RC_SCREEN_FONT_ROMAN:
2364 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2365 case LyXRC::RC_SCREEN_FONT_SANS:
2366 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2367 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2368 case LyXRC::RC_SCREEN_FONT_SIZES:
2369 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2370 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2371 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2372 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2373 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2374 case LyXRC::RC_SCREEN_ZOOM:
2375 case LyXRC::RC_SERVERPIPE:
2376 case LyXRC::RC_SET_COLOR:
2377 case LyXRC::RC_SHOW_BANNER:
2378 case LyXRC::RC_SPELL_COMMAND:
2379 case LyXRC::RC_TEMPDIRPATH:
2380 case LyXRC::RC_TEMPLATEPATH:
2381 case LyXRC::RC_TEX_ALLOWS_SPACES:
2382 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2383 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2384 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2386 case LyXRC::RC_UIFILE:
2387 case LyXRC::RC_USER_EMAIL:
2388 case LyXRC::RC_USER_NAME:
2389 case LyXRC::RC_USETEMPDIR:
2390 case LyXRC::RC_USE_ALT_LANG:
2391 case LyXRC::RC_USE_CONVERTER_CACHE:
2392 case LyXRC::RC_USE_ESC_CHARS:
2393 case LyXRC::RC_USE_INP_ENC:
2394 case LyXRC::RC_USE_PERS_DICT:
2395 case LyXRC::RC_USE_SPELL_LIB:
2396 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2397 case LyXRC::RC_VIEWER:
2398 case LyXRC::RC_LAST: