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/Selection.h"
88 #include "frontends/WorkArea.h"
90 #include "support/environment.h"
91 #include "support/FileFilterList.h"
92 #include "support/filetools.h"
93 #include "support/ForkedcallsController.h"
94 #include "support/fs_extras.h"
95 #include "support/lstrings.h"
96 #include "support/Path.h"
97 #include "support/Package.h"
98 #include "support/Systemcall.h"
99 #include "support/convert.h"
100 #include "support/os.h"
102 #include <boost/current_function.hpp>
103 #include <boost/filesystem/operations.hpp>
108 using std::make_pair;
111 using std::istringstream;
112 using std::ostringstream;
114 namespace fs = boost::filesystem;
118 using bv_funcs::freefont2string;
120 using frontend::LyXView;
122 using support::absolutePath;
123 using support::addName;
124 using support::addPath;
125 using support::bformat;
126 using support::changeExtension;
127 using support::contains;
128 using support::FileFilterList;
129 using support::FileName;
130 using support::fileSearch;
131 using support::ForkedcallsController;
132 using support::i18nLibFileSearch;
133 using support::isDirWriteable;
134 using support::isFileReadable;
135 using support::isStrInt;
136 using support::makeAbsPath;
137 using support::makeDisplayPath;
138 using support::package;
139 using support::quoteName;
140 using support::rtrim;
141 using support::split;
142 using support::subst;
143 using support::Systemcall;
144 using support::token;
146 using support::prefixIs;
148 namespace Alert = frontend::Alert;
153 bool getLocalStatus(Cursor cursor,
154 FuncRequest const & cmd, FuncStatus & status)
156 // Try to fix cursor in case it is broken.
157 cursor.fixIfBroken();
159 // This is, of course, a mess. Better create a new doc iterator and use
160 // this in Inset::getStatus. This might require an additional
161 // BufferView * arg, though (which should be avoided)
162 //Cursor safe = *this;
164 for ( ; cursor.depth(); cursor.pop()) {
165 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
166 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
167 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
168 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
170 // The inset's getStatus() will return 'true' if it made
171 // a definitive decision on whether it want to handle the
172 // request or not. The result of this decision is put into
173 // the 'status' parameter.
174 if (cursor.inset().getStatus(cursor, cmd, status)) {
183 /** Return the change status at cursor position, taking in account the
184 * status at each level of the document iterator (a table in a deleted
185 * footnote is deleted).
186 * When \param outer is true, the top slice is not looked at.
188 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
190 size_t const depth = dit.depth() - (outer ? 1 : 0);
192 for (size_t i = 0 ; i < depth ; ++i) {
193 CursorSlice const & slice = dit[i];
194 if (!slice.inset().inMathed()
195 && slice.pos() < slice.paragraph().size()) {
196 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
197 if (ch != Change::UNCHANGED)
201 return Change::UNCHANGED;
209 meta_fake_bit(key_modifier::none)
214 void LyXFunc::initKeySequences(KeyMap * kb)
216 keyseq.reset(new KeySequence(kb, kb));
217 cancel_meta_seq.reset(new KeySequence(kb, kb));
221 void LyXFunc::setLyXView(LyXView * lv)
223 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
224 // save current selection to the selection buffer to allow
225 // middle-button paste in another window
226 cap::saveSelection(lyx_view_->view()->cursor());
231 void LyXFunc::handleKeyFunc(kb_action action)
233 char_type c = encoded_last_key;
235 if (keyseq->length())
238 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
239 lyx_view_->view()->getIntl().getTransManager().deadkey(
240 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
241 // Need to clear, in case the minibuffer calls these
244 // copied verbatim from do_accent_char
245 view()->cursor().resetAnchor();
250 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
252 BOOST_ASSERT(lyx_view_);
253 if (!LyX::ref().session().bookmarks().isValid(idx))
255 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
256 BOOST_ASSERT(!bm.filename.empty());
257 string const file = bm.filename.absFilename();
258 // if the file is not opened, open it.
259 if (!theBufferList().exists(file)) {
261 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
265 // open may fail, so we need to test it again
266 if (!theBufferList().exists(file))
269 // if the current buffer is not that one, switch to it.
270 if (lyx_view_->buffer()->fileName() != file) {
273 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
275 // moveToPosition try paragraph id first and then paragraph (pit, pos).
276 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
277 bm.top_id, bm.top_pos))
280 // Cursor jump succeeded!
281 Cursor const & cur = view()->cursor();
282 pit_type new_pit = cur.pit();
283 pos_type new_pos = cur.pos();
284 int new_id = cur.paragraph().id();
286 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
287 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
288 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
289 || bm.top_id != new_id) {
290 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
291 new_pit, new_pos, new_id);
296 void LyXFunc::processKeySym(KeySymbolPtr keysym, key_modifier::state state)
298 LYXERR(Debug::KEY) << "KeySym is " << keysym->getSymbolName() << endl;
300 // Do nothing if we have nothing (JMarc)
301 if (!keysym->isOK()) {
302 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
307 if (keysym->isModifier()) {
308 LYXERR(Debug::KEY) << "isModifier true" << endl;
312 //Encoding const * encoding = view()->cursor().getEncoding();
313 //encoded_last_key = keysym->getISOEncoded(encoding ? encoding->name() : "");
314 // FIXME: encoded_last_key shadows the member variable of the same
315 // name. Is that intended?
316 char_type encoded_last_key = keysym->getUCSEncoded();
318 // Do a one-deep top-level lookup for
319 // cancel and meta-fake keys. RVDK_PATCH_5
320 cancel_meta_seq->reset();
322 FuncRequest func = cancel_meta_seq->addkey(keysym, state);
323 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
324 << " action first set to [" << func.action << ']'
327 // When not cancel or meta-fake, do the normal lookup.
328 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
329 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
330 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
331 // remove Caps Lock and Mod2 as a modifiers
332 func = keyseq->addkey(keysym, (state | meta_fake_bit));
333 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
334 << "action now set to ["
335 << func.action << ']' << endl;
338 // Dont remove this unless you know what you are doing.
339 meta_fake_bit = key_modifier::none;
341 // Can this happen now ?
342 if (func.action == LFUN_NOACTION) {
343 func = FuncRequest(LFUN_COMMAND_PREFIX);
346 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
348 << func.action << "]["
349 << to_utf8(keyseq->print(false)) << ']'
352 // already here we know if it any point in going further
353 // why not return already here if action == -1 and
354 // num_bytes == 0? (Lgb)
356 if (keyseq->length() > 1) {
357 lyx_view_->message(keyseq->print(true));
361 // Maybe user can only reach the key via holding down shift.
362 // Let's see. But only if shift is the only modifier
363 if (func.action == LFUN_UNKNOWN_ACTION &&
364 state == key_modifier::shift) {
365 LYXERR(Debug::KEY) << "Trying without shift" << endl;
366 func = keyseq->addkey(keysym, key_modifier::none);
367 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
370 if (func.action == LFUN_UNKNOWN_ACTION) {
371 // Hmm, we didn't match any of the keysequences. See
372 // if it's normal insertable text not already covered
374 if (keysym->isText() && keyseq->length() == 1) {
375 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
376 func = FuncRequest(LFUN_SELF_INSERT,
377 FuncRequest::KEYBOARD);
379 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
380 lyx_view_->message(_("Unknown function."));
385 if (func.action == LFUN_SELF_INSERT) {
386 if (encoded_last_key != 0) {
387 docstring const arg(1, encoded_last_key);
388 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
389 FuncRequest::KEYBOARD));
391 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
397 /* When we move around, or type, it's nice to be able to see
398 * the cursor immediately after the keypress.
400 if (lyx_view_ && lyx_view_->currentWorkArea())
401 lyx_view_->currentWorkArea()->startBlinkingCursor();
405 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
407 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
410 Cursor & cur = view()->cursor();
412 /* In LyX/Mac, when a dialog is open, the menus of the
413 application can still be accessed without giving focus to
414 the main window. In this case, we want to disable the menu
415 entries that are buffer-related.
417 Note that this code is not perfect, as bug 1941 attests:
418 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
420 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
421 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
424 if (cmd.action == LFUN_NOACTION) {
425 flag.message(from_utf8(N_("Nothing to do")));
430 switch (cmd.action) {
431 case LFUN_UNKNOWN_ACTION:
432 #ifndef HAVE_LIBAIKSAURUS
433 case LFUN_THESAURUS_ENTRY:
443 if (flag.unknown()) {
444 flag.message(from_utf8(N_("Unknown action")));
448 if (!flag.enabled()) {
449 if (flag.message().empty())
450 flag.message(from_utf8(N_("Command disabled")));
454 // Check whether we need a buffer
455 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
457 flag.message(from_utf8(N_("Command not allowed with"
458 "out any document open")));
463 // I would really like to avoid having this switch and rather try to
464 // encode this in the function itself.
465 // -- And I'd rather let an inset decide which LFUNs it is willing
466 // to handle (Andre')
468 switch (cmd.action) {
469 case LFUN_BUFFER_TOGGLE_READ_ONLY:
470 flag.setOnOff(buf->isReadonly());
473 case LFUN_BUFFER_SWITCH:
474 // toggle on the current buffer, but do not toggle off
475 // the other ones (is that a good idea?)
476 if (buf && to_utf8(cmd.argument()) == buf->fileName())
480 case LFUN_BUFFER_EXPORT:
481 enable = cmd.argument() == "custom"
482 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
485 case LFUN_BUFFER_CHKTEX:
486 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
489 case LFUN_BUILD_PROGRAM:
490 enable = Exporter::isExportable(*buf, "program");
493 case LFUN_LAYOUT_TABULAR:
494 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
498 case LFUN_LAYOUT_PARAGRAPH:
499 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
502 case LFUN_VC_REGISTER:
503 enable = !buf->lyxvc().inUse();
505 case LFUN_VC_CHECK_IN:
506 enable = buf->lyxvc().inUse() && !buf->isReadonly();
508 case LFUN_VC_CHECK_OUT:
509 enable = buf->lyxvc().inUse() && buf->isReadonly();
512 case LFUN_VC_UNDO_LAST:
513 enable = buf->lyxvc().inUse();
515 case LFUN_BUFFER_RELOAD:
516 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
517 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
520 case LFUN_INSET_SETTINGS: {
524 Inset::Code code = cur.inset().lyxCode();
526 case Inset::TABULAR_CODE:
527 enable = cmd.argument() == "tabular";
529 case Inset::ERT_CODE:
530 enable = cmd.argument() == "ert";
532 case Inset::FLOAT_CODE:
533 enable = cmd.argument() == "float";
535 case Inset::WRAP_CODE:
536 enable = cmd.argument() == "wrap";
538 case Inset::NOTE_CODE:
539 enable = cmd.argument() == "note";
541 case Inset::BRANCH_CODE:
542 enable = cmd.argument() == "branch";
544 case Inset::BOX_CODE:
545 enable = cmd.argument() == "box";
547 case Inset::LISTINGS_CODE:
548 enable = cmd.argument() == "listings";
556 case LFUN_INSET_APPLY: {
557 string const name = cmd.getArg(0);
558 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
560 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
562 if (!inset->getStatus(cur, fr, fs)) {
563 // Every inset is supposed to handle this
568 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
569 flag |= getStatus(fr);
571 enable = flag.enabled();
575 case LFUN_DIALOG_TOGGLE:
576 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
577 // fall through to set "enable"
578 case LFUN_DIALOG_SHOW: {
579 string const name = cmd.getArg(0);
581 enable = name == "aboutlyx"
582 || name == "file" //FIXME: should be removed.
584 || name == "texinfo";
585 else if (name == "print")
586 enable = Exporter::isExportable(*buf, "dvi")
587 && lyxrc.print_command != "none";
588 else if (name == "character")
589 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
590 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
591 else if (name == "latexlog")
592 enable = isFileReadable(FileName(buf->getLogName().second));
593 else if (name == "spellchecker")
594 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
595 enable = !buf->isReadonly();
599 else if (name == "vclog")
600 enable = buf->lyxvc().inUse();
604 case LFUN_DIALOG_SHOW_NEW_INSET:
605 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
606 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
607 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
609 if (cur.inset().getStatus(cur, cmd, flag))
614 case LFUN_DIALOG_UPDATE: {
615 string const name = cmd.getArg(0);
617 enable = name == "prefs";
621 case LFUN_CITATION_INSERT: {
622 FuncRequest fr(LFUN_INSET_INSERT, "citation");
623 enable = getStatus(fr).enabled();
627 case LFUN_BUFFER_WRITE: {
628 enable = lyx_view_->buffer()->isUnnamed()
629 || !lyx_view_->buffer()->isClean();
634 case LFUN_BUFFER_WRITE_ALL: {
635 // We enable the command only if there are some modified buffers
636 Buffer * first = theBufferList().first();
637 bool modified = false;
641 // We cannot use a for loop as the buffer list is a cycle.
647 b = theBufferList().next(b);
648 } while (b != first);
656 case LFUN_BOOKMARK_GOTO: {
657 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
658 enable = LyX::ref().session().bookmarks().isValid(num);
662 case LFUN_BOOKMARK_CLEAR:
663 enable = LyX::ref().session().bookmarks().size() > 0;
666 case LFUN_TOOLBAR_TOGGLE: {
667 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
668 flag.setOnOff(current);
671 case LFUN_WINDOW_CLOSE: {
672 enable = (theApp()->gui().viewIds().size() > 1);
676 // this one is difficult to get right. As a half-baked
677 // solution, we consider only the first action of the sequence
678 case LFUN_COMMAND_SEQUENCE: {
679 // argument contains ';'-terminated commands
680 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
681 FuncRequest func(lyxaction.lookupFunc(firstcmd));
682 func.origin = cmd.origin;
683 flag = getStatus(func);
686 case LFUN_BUFFER_NEW:
687 case LFUN_BUFFER_NEW_TEMPLATE:
688 case LFUN_WORD_FIND_FORWARD:
689 case LFUN_WORD_FIND_BACKWARD:
690 case LFUN_COMMAND_PREFIX:
691 case LFUN_COMMAND_EXECUTE:
693 case LFUN_META_PREFIX:
694 case LFUN_BUFFER_CLOSE:
695 case LFUN_BUFFER_WRITE_AS:
696 case LFUN_BUFFER_UPDATE:
697 case LFUN_BUFFER_VIEW:
698 case LFUN_BUFFER_IMPORT:
699 case LFUN_BUFFER_AUTO_SAVE:
700 case LFUN_RECONFIGURE:
704 case LFUN_DROP_LAYOUTS_CHOICE:
706 case LFUN_SERVER_GET_NAME:
707 case LFUN_SERVER_NOTIFY:
708 case LFUN_SERVER_GOTO_FILE_ROW:
709 case LFUN_DIALOG_HIDE:
710 case LFUN_DIALOG_DISCONNECT_INSET:
711 case LFUN_BUFFER_CHILD_OPEN:
712 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
713 case LFUN_KEYMAP_OFF:
714 case LFUN_KEYMAP_PRIMARY:
715 case LFUN_KEYMAP_SECONDARY:
716 case LFUN_KEYMAP_TOGGLE:
718 case LFUN_BUFFER_EXPORT_CUSTOM:
719 case LFUN_BUFFER_PRINT:
720 case LFUN_PREFERENCES_SAVE:
721 case LFUN_SCREEN_FONT_UPDATE:
724 case LFUN_EXTERNAL_EDIT:
725 case LFUN_GRAPHICS_EDIT:
726 case LFUN_ALL_INSETS_TOGGLE:
727 case LFUN_BUFFER_LANGUAGE:
728 case LFUN_TEXTCLASS_APPLY:
729 case LFUN_TEXTCLASS_LOAD:
730 case LFUN_BUFFER_SAVE_AS_DEFAULT:
731 case LFUN_BUFFER_PARAMS_APPLY:
732 case LFUN_LYXRC_APPLY:
733 case LFUN_BUFFER_NEXT:
734 case LFUN_BUFFER_PREVIOUS:
735 case LFUN_WINDOW_NEW:
737 // these are handled in our dispatch()
741 if (!getLocalStatus(cur, cmd, flag))
742 flag = view()->getStatus(cmd);
748 // Can we use a readonly buffer?
749 if (buf && buf->isReadonly()
750 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
751 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
752 flag.message(from_utf8(N_("Document is read-only")));
756 // Are we in a DELETED change-tracking region?
757 if (buf && lookupChangeType(cur, true) == Change::DELETED
758 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
759 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
760 flag.message(from_utf8(N_("This portion of the document is deleted.")));
764 // the default error message if we disable the command
765 if (!flag.enabled() && flag.message().empty())
766 flag.message(from_utf8(N_("Command disabled")));
772 bool LyXFunc::ensureBufferClean(BufferView * bv)
774 Buffer & buf = bv->buffer();
778 docstring const file = makeDisplayPath(buf.fileName(), 30);
779 docstring text = bformat(_("The document %1$s has unsaved "
780 "changes.\n\nDo you want to save "
781 "the document?"), file);
782 int const ret = Alert::prompt(_("Save changed document?"),
783 text, 0, 1, _("&Save"),
787 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
789 return buf.isClean();
795 void showPrintError(string const & name)
797 docstring str = bformat(_("Could not print the document %1$s.\n"
798 "Check that your printer is set up correctly."),
799 makeDisplayPath(name, 50));
800 Alert::error(_("Print document failed"), str);
804 void loadTextclass(string const & name)
806 std::pair<bool, textclass_type> const tc_pair =
807 textclasslist.numberOfClass(name);
809 if (!tc_pair.first) {
810 lyxerr << "Document class \"" << name
811 << "\" does not exist."
816 textclass_type const tc = tc_pair.second;
818 if (!textclasslist[tc].load()) {
819 docstring s = bformat(_("The document class %1$s."
820 "could not be loaded."),
821 from_utf8(textclasslist[tc].name()));
822 Alert::error(_("Could not load class"), s);
827 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
832 void LyXFunc::dispatch(FuncRequest const & cmd)
834 string const argument = to_utf8(cmd.argument());
835 kb_action const action = cmd.action;
837 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
838 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
840 // we have not done anything wrong yet.
842 dispatch_buffer.erase();
844 // redraw the screen at the end (first of the two drawing steps).
845 //This is done unless explicitely requested otherwise
846 Update::flags updateFlags = Update::FitCursor;
848 FuncStatus const flag = getStatus(cmd);
849 if (!flag.enabled()) {
850 // We cannot use this function here
851 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
852 << lyxaction.getActionName(action)
853 << " [" << action << "] is disabled at this location"
855 setErrorMessage(flag.message());
859 case LFUN_WORD_FIND_FORWARD:
860 case LFUN_WORD_FIND_BACKWARD: {
861 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
862 static docstring last_search;
863 docstring searched_string;
865 if (!cmd.argument().empty()) {
866 last_search = cmd.argument();
867 searched_string = cmd.argument();
869 searched_string = last_search;
872 if (searched_string.empty())
875 bool const fw = action == LFUN_WORD_FIND_FORWARD;
876 docstring const data =
877 find2string(searched_string, true, false, fw);
878 find(view(), FuncRequest(LFUN_WORD_FIND, data));
882 case LFUN_COMMAND_PREFIX:
883 BOOST_ASSERT(lyx_view_);
884 lyx_view_->message(keyseq->printOptions(true));
887 case LFUN_COMMAND_EXECUTE:
888 BOOST_ASSERT(lyx_view_);
889 lyx_view_->showMiniBuffer(true);
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_->openLayoutList();
1297 case LFUN_MENU_OPEN:
1298 BOOST_ASSERT(lyx_view_);
1299 lyx_view_->openMenu(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 loadTextclass(argument);
1782 std::pair<bool, textclass_type> const tc_pair =
1783 textclasslist.numberOfClass(argument);
1788 textclass_type const old_class = buffer->params().getBaseClass();
1789 textclass_type const new_class = tc_pair.second;
1791 if (old_class == new_class)
1795 lyx_view_->message(_("Converting document to new document class..."));
1796 recordUndoFullDocument(view());
1797 //Save the old, possibly modular, layout for use in conversion.
1798 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1799 buffer->params().setBaseClass(new_class);
1801 StableDocIterator backcur(view()->cursor());
1802 ErrorList & el = buffer->errorList("Class Switch");
1803 cap::switchBetweenClasses(
1804 oldClass, buffer->params().getTextClass_ptr(),
1805 static_cast<InsetText &>(buffer->inset()), el);
1807 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1809 buffer->errors("Class Switch");
1810 updateLabels(*buffer);
1811 updateFlags = Update::Force | Update::FitCursor;
1815 case LFUN_TEXTCLASS_LOAD:
1816 loadTextclass(argument);
1819 case LFUN_LYXRC_APPLY: {
1820 LyXRC const lyxrc_orig = lyxrc;
1822 istringstream ss(argument);
1823 bool const success = lyxrc.read(ss) == 0;
1826 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1827 << "Unable to read lyxrc data"
1832 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1834 /// We force the redraw in any case because there might be
1835 /// some screen font changes.
1836 /// FIXME: only the current view will be updated. the Gui
1837 /// class is able to furnish the list of views.
1838 updateFlags = Update::Force;
1842 case LFUN_WINDOW_NEW:
1843 LyX::ref().newLyXView();
1846 case LFUN_WINDOW_CLOSE:
1847 BOOST_ASSERT(lyx_view_);
1848 BOOST_ASSERT(theApp());
1849 // update bookmark pit of the current buffer before window close
1850 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1851 gotoBookmark(i+1, false, false);
1852 // ask the user for saving changes or cancel quit
1853 if (!theBufferList().quitWriteAll())
1858 case LFUN_BOOKMARK_GOTO:
1859 // go to bookmark, open unopened file and switch to buffer if necessary
1860 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1863 case LFUN_BOOKMARK_CLEAR:
1864 LyX::ref().session().bookmarks().clear();
1867 case LFUN_TOOLBAR_TOGGLE: {
1868 BOOST_ASSERT(lyx_view_);
1869 string const name = cmd.getArg(0);
1870 bool const allowauto = cmd.getArg(1) == "allowauto";
1871 lyx_view_->toggleToolbarState(name, allowauto);
1872 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1874 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1879 if (tbi->flags & ToolbarInfo::ON)
1881 else if (tbi->flags & ToolbarInfo::OFF)
1883 else if (tbi->flags & ToolbarInfo::AUTO)
1886 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1887 _(tbi->gui_name), state));
1892 BOOST_ASSERT(lyx_view_);
1893 view()->cursor().dispatch(cmd);
1894 updateFlags = view()->cursor().result().update();
1895 if (!view()->cursor().result().dispatched())
1896 updateFlags = view()->dispatch(cmd);
1901 if (lyx_view_ && lyx_view_->buffer()) {
1902 // BufferView::update() updates the ViewMetricsInfo and
1903 // also initializes the position cache for all insets in
1904 // (at least partially) visible top-level paragraphs.
1905 // We will redraw the screen only if needed.
1906 if (view()->update(updateFlags)) {
1907 // Buffer::changed() signals that a repaint is needed.
1908 // The frontend (WorkArea) knows which area to repaint
1909 // thanks to the ViewMetricsInfo updated above.
1910 lyx_view_->buffer()->changed();
1913 lyx_view_->updateStatusBar();
1915 // if we executed a mutating lfun, mark the buffer as dirty
1917 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1918 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1919 lyx_view_->buffer()->markDirty();
1921 //Do we have a selection?
1922 theSelection().haveSelection(view()->cursor().selection());
1924 if (view()->cursor().inTexted()) {
1925 lyx_view_->updateLayoutChoice();
1929 if (!quitting && lyx_view_) {
1930 lyx_view_->updateToolbars();
1931 // Some messages may already be translated, so we cannot use _()
1932 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1937 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1939 const bool verbose = (cmd.origin == FuncRequest::MENU
1940 || cmd.origin == FuncRequest::TOOLBAR
1941 || cmd.origin == FuncRequest::COMMANDBUFFER);
1943 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1944 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1946 lyx_view_->message(msg);
1950 docstring dispatch_msg = msg;
1951 if (!dispatch_msg.empty())
1952 dispatch_msg += ' ';
1954 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1956 bool argsadded = false;
1958 if (!cmd.argument().empty()) {
1959 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1960 comname += ' ' + cmd.argument();
1965 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
1967 if (!shortcuts.empty())
1968 comname += ": " + shortcuts;
1969 else if (!argsadded && !cmd.argument().empty())
1970 comname += ' ' + cmd.argument();
1972 if (!comname.empty()) {
1973 comname = rtrim(comname);
1974 dispatch_msg += '(' + rtrim(comname) + ')';
1977 LYXERR(Debug::ACTION) << "verbose dispatch msg "
1978 << to_utf8(dispatch_msg) << endl;
1979 if (!dispatch_msg.empty())
1980 lyx_view_->message(dispatch_msg);
1984 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1986 // FIXME: initpath is not used. What to do?
1987 string initpath = lyxrc.document_path;
1988 string filename(name);
1990 if (lyx_view_->buffer()) {
1991 string const trypath = lyx_view_->buffer()->filePath();
1992 // If directory is writeable, use this as default.
1993 if (isDirWriteable(FileName(trypath)))
1997 static int newfile_number;
1999 if (filename.empty()) {
2000 filename = addName(lyxrc.document_path,
2001 "newfile" + convert<string>(++newfile_number) + ".lyx");
2002 while (theBufferList().exists(filename) ||
2003 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2005 filename = addName(lyxrc.document_path,
2006 "newfile" + convert<string>(newfile_number) +
2011 // The template stuff
2014 FileDialog fileDlg(_("Select template file"),
2015 LFUN_SELECT_FILE_SYNC,
2016 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2017 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2019 FileDialog::Result result =
2020 fileDlg.open(from_utf8(lyxrc.template_path),
2021 FileFilterList(_("LyX Documents (*.lyx)")),
2024 if (result.first == FileDialog::Later)
2026 if (result.second.empty())
2028 templname = to_utf8(result.second);
2031 Buffer * const b = newFile(filename, templname, !name.empty());
2033 lyx_view_->setBuffer(b);
2037 void LyXFunc::open(string const & fname)
2039 string initpath = lyxrc.document_path;
2041 if (lyx_view_->buffer()) {
2042 string const trypath = lyx_view_->buffer()->filePath();
2043 // If directory is writeable, use this as default.
2044 if (isDirWriteable(FileName(trypath)))
2050 if (fname.empty()) {
2051 FileDialog fileDlg(_("Select document to open"),
2053 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2054 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2056 FileDialog::Result result =
2057 fileDlg.open(from_utf8(initpath),
2058 FileFilterList(_("LyX Documents (*.lyx)")),
2061 if (result.first == FileDialog::Later)
2064 filename = to_utf8(result.second);
2066 // check selected filename
2067 if (filename.empty()) {
2068 lyx_view_->message(_("Canceled."));
2074 // get absolute path of file and add ".lyx" to the filename if
2076 FileName const fullname = fileSearch(string(), filename, "lyx");
2077 if (!fullname.empty())
2078 filename = fullname.absFilename();
2080 // if the file doesn't exist, let the user create one
2081 if (!fs::exists(fullname.toFilesystemEncoding())) {
2082 // the user specifically chose this name. Believe him.
2083 Buffer * const b = newFile(filename, string(), true);
2085 lyx_view_->setBuffer(b);
2089 docstring const disp_fn = makeDisplayPath(filename);
2090 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2093 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2096 lyx_view_->setBuffer(buf);
2097 lyx_view_->showErrorList("Parse");
2098 str2 = bformat(_("Document %1$s opened."), disp_fn);
2100 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2102 lyx_view_->message(str2);
2106 void LyXFunc::doImport(string const & argument)
2109 string filename = split(argument, format, ' ');
2111 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2112 << " file: " << filename << endl;
2114 // need user interaction
2115 if (filename.empty()) {
2116 string initpath = lyxrc.document_path;
2118 if (lyx_view_->buffer()) {
2119 string const trypath = lyx_view_->buffer()->filePath();
2120 // If directory is writeable, use this as default.
2121 if (isDirWriteable(FileName(trypath)))
2125 docstring const text = bformat(_("Select %1$s file to import"),
2126 formats.prettyName(format));
2128 FileDialog fileDlg(text,
2130 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2131 make_pair(_("Examples|#E#e"),
2132 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2134 docstring filter = formats.prettyName(format);
2137 filter += from_utf8(formats.extension(format));
2140 FileDialog::Result result =
2141 fileDlg.open(from_utf8(initpath),
2142 FileFilterList(filter),
2145 if (result.first == FileDialog::Later)
2148 filename = to_utf8(result.second);
2150 // check selected filename
2151 if (filename.empty())
2152 lyx_view_->message(_("Canceled."));
2155 if (filename.empty())
2158 // get absolute path of file
2159 FileName const fullname(makeAbsPath(filename));
2161 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2163 // Check if the document already is open
2164 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2165 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2166 lyx_view_->message(_("Canceled."));
2171 // if the file exists already, and we didn't do
2172 // -i lyx thefile.lyx, warn
2173 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2174 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2176 docstring text = bformat(_("The document %1$s already exists.\n\n"
2177 "Do you want to overwrite that document?"), file);
2178 int const ret = Alert::prompt(_("Overwrite document?"),
2179 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2182 lyx_view_->message(_("Canceled."));
2187 ErrorList errorList;
2188 Importer::Import(lyx_view_, fullname, format, errorList);
2189 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2193 void LyXFunc::closeBuffer()
2195 // goto bookmark to update bookmark pit.
2196 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2197 gotoBookmark(i+1, false, false);
2199 theBufferList().close(lyx_view_->buffer(), true);
2203 void LyXFunc::reloadBuffer()
2205 FileName filename(lyx_view_->buffer()->fileName());
2206 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2209 Buffer * buf = lyx_view_->loadLyXFile(filename);
2212 lyx_view_->setBuffer(buf);
2213 lyx_view_->showErrorList("Parse");
2214 str = bformat(_("Document %1$s reloaded."), disp_fn);
2216 str = bformat(_("Could not reload document %1$s"), disp_fn);
2218 lyx_view_->message(str);
2221 // Each "lyx_view_" should have it's own message method. lyxview and
2222 // the minibuffer would use the minibuffer, but lyxserver would
2223 // send an ERROR signal to its client. Alejandro 970603
2224 // This function is bit problematic when it comes to NLS, to make the
2225 // lyx servers client be language indepenent we must not translate
2226 // strings sent to this func.
2227 void LyXFunc::setErrorMessage(docstring const & m) const
2229 dispatch_buffer = m;
2234 void LyXFunc::setMessage(docstring const & m) const
2236 dispatch_buffer = m;
2240 docstring const LyXFunc::viewStatusMessage()
2242 // When meta-fake key is pressed, show the key sequence so far + "M-".
2244 return keyseq->print(true) + "M-";
2246 // Else, when a non-complete key sequence is pressed,
2247 // show the available options.
2248 if (keyseq->length() > 0 && !keyseq->deleted())
2249 return keyseq->printOptions(true);
2251 BOOST_ASSERT(lyx_view_);
2252 if (!lyx_view_->buffer())
2253 return _("Welcome to LyX!");
2255 return view()->cursor().currentState();
2259 BufferView * LyXFunc::view() const
2261 BOOST_ASSERT(lyx_view_);
2262 return lyx_view_->view();
2266 bool LyXFunc::wasMetaKey() const
2268 return (meta_fake_bit != key_modifier::none);
2274 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2276 // Why the switch you might ask. It is a trick to ensure that all
2277 // the elements in the LyXRCTags enum is handled. As you can see
2278 // there are no breaks at all. So it is just a huge fall-through.
2279 // The nice thing is that we will get a warning from the compiler
2280 // if we forget an element.
2281 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2283 case LyXRC::RC_ACCEPT_COMPOUND:
2284 case LyXRC::RC_ALT_LANG:
2285 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2286 case LyXRC::RC_PLAINTEXT_LINELEN:
2287 case LyXRC::RC_AUTOREGIONDELETE:
2288 case LyXRC::RC_AUTORESET_OPTIONS:
2289 case LyXRC::RC_AUTOSAVE:
2290 case LyXRC::RC_AUTO_NUMBER:
2291 case LyXRC::RC_BACKUPDIR_PATH:
2292 case LyXRC::RC_BIBTEX_COMMAND:
2293 case LyXRC::RC_BINDFILE:
2294 case LyXRC::RC_CHECKLASTFILES:
2295 case LyXRC::RC_USELASTFILEPOS:
2296 case LyXRC::RC_LOADSESSION:
2297 case LyXRC::RC_CHKTEX_COMMAND:
2298 case LyXRC::RC_CONVERTER:
2299 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2300 case LyXRC::RC_COPIER:
2301 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2302 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2303 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2304 case LyXRC::RC_DATE_INSERT_FORMAT:
2305 case LyXRC::RC_DEFAULT_LANGUAGE:
2306 case LyXRC::RC_DEFAULT_PAPERSIZE:
2307 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2308 case LyXRC::RC_DISPLAY_GRAPHICS:
2309 case LyXRC::RC_DOCUMENTPATH:
2310 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2311 string const encoded = FileName(
2312 lyxrc_new.document_path).toFilesystemEncoding();
2313 if (fs::exists(encoded) && fs::is_directory(encoded))
2314 support::package().document_dir() = FileName(lyxrc.document_path);
2316 case LyXRC::RC_ESC_CHARS:
2317 case LyXRC::RC_FONT_ENCODING:
2318 case LyXRC::RC_FORMAT:
2319 case LyXRC::RC_INDEX_COMMAND:
2320 case LyXRC::RC_INPUT:
2321 case LyXRC::RC_KBMAP:
2322 case LyXRC::RC_KBMAP_PRIMARY:
2323 case LyXRC::RC_KBMAP_SECONDARY:
2324 case LyXRC::RC_LABEL_INIT_LENGTH:
2325 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2326 case LyXRC::RC_LANGUAGE_AUTO_END:
2327 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2328 case LyXRC::RC_LANGUAGE_COMMAND_END:
2329 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2330 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2331 case LyXRC::RC_LANGUAGE_PACKAGE:
2332 case LyXRC::RC_LANGUAGE_USE_BABEL:
2333 case LyXRC::RC_MAKE_BACKUP:
2334 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2335 case LyXRC::RC_NUMLASTFILES:
2336 case LyXRC::RC_PATH_PREFIX:
2337 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2338 support::prependEnvPath("PATH", lyxrc.path_prefix);
2340 case LyXRC::RC_PERS_DICT:
2341 case LyXRC::RC_PREVIEW:
2342 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2343 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2344 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2345 case LyXRC::RC_PRINTCOPIESFLAG:
2346 case LyXRC::RC_PRINTER:
2347 case LyXRC::RC_PRINTEVENPAGEFLAG:
2348 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2349 case LyXRC::RC_PRINTFILEEXTENSION:
2350 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2351 case LyXRC::RC_PRINTODDPAGEFLAG:
2352 case LyXRC::RC_PRINTPAGERANGEFLAG:
2353 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2354 case LyXRC::RC_PRINTPAPERFLAG:
2355 case LyXRC::RC_PRINTREVERSEFLAG:
2356 case LyXRC::RC_PRINTSPOOL_COMMAND:
2357 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2358 case LyXRC::RC_PRINTTOFILE:
2359 case LyXRC::RC_PRINTTOPRINTER:
2360 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2361 case LyXRC::RC_PRINT_COMMAND:
2362 case LyXRC::RC_RTL_SUPPORT:
2363 case LyXRC::RC_SCREEN_DPI:
2364 case LyXRC::RC_SCREEN_FONT_ROMAN:
2365 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2366 case LyXRC::RC_SCREEN_FONT_SANS:
2367 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2368 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2369 case LyXRC::RC_SCREEN_FONT_SIZES:
2370 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2371 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2372 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2373 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2374 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2375 case LyXRC::RC_SCREEN_ZOOM:
2376 case LyXRC::RC_SERVERPIPE:
2377 case LyXRC::RC_SET_COLOR:
2378 case LyXRC::RC_SHOW_BANNER:
2379 case LyXRC::RC_SPELL_COMMAND:
2380 case LyXRC::RC_TEMPDIRPATH:
2381 case LyXRC::RC_TEMPLATEPATH:
2382 case LyXRC::RC_TEX_ALLOWS_SPACES:
2383 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2384 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2385 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2387 case LyXRC::RC_UIFILE:
2388 case LyXRC::RC_USER_EMAIL:
2389 case LyXRC::RC_USER_NAME:
2390 case LyXRC::RC_USETEMPDIR:
2391 case LyXRC::RC_USE_ALT_LANG:
2392 case LyXRC::RC_USE_CONVERTER_CACHE:
2393 case LyXRC::RC_USE_ESC_CHARS:
2394 case LyXRC::RC_USE_INP_ENC:
2395 case LyXRC::RC_USE_PERS_DICT:
2396 case LyXRC::RC_USE_SPELL_LIB:
2397 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2398 case LyXRC::RC_VIEWER:
2399 case LyXRC::RC_LAST: