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 use par_id, and par_pit and return new par_id.
280 boost::tie(new_pit, new_pos, new_id) = view()->moveToPosition(bm.bottom_pit, bm.bottom_pos, bm.top_id, bm.top_pos);
281 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
282 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
283 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos || bm.top_id != new_id )
284 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(new_pit, new_pos, new_id);
289 void LyXFunc::processKeySym(KeySymbolPtr keysym, key_modifier::state state)
291 LYXERR(Debug::KEY) << "KeySym is " << keysym->getSymbolName() << endl;
293 // Do nothing if we have nothing (JMarc)
294 if (!keysym->isOK()) {
295 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
300 if (keysym->isModifier()) {
301 LYXERR(Debug::KEY) << "isModifier true" << endl;
305 //Encoding const * encoding = view()->cursor().getEncoding();
306 //encoded_last_key = keysym->getISOEncoded(encoding ? encoding->name() : "");
307 // FIXME: encoded_last_key shadows the member variable of the same
308 // name. Is that intended?
309 char_type encoded_last_key = keysym->getUCSEncoded();
311 // Do a one-deep top-level lookup for
312 // cancel and meta-fake keys. RVDK_PATCH_5
313 cancel_meta_seq->reset();
315 FuncRequest func = cancel_meta_seq->addkey(keysym, state);
316 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
317 << " action first set to [" << func.action << ']'
320 // When not cancel or meta-fake, do the normal lookup.
321 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
322 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
323 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
324 // remove Caps Lock and Mod2 as a modifiers
325 func = keyseq->addkey(keysym, (state | meta_fake_bit));
326 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
327 << "action now set to ["
328 << func.action << ']' << endl;
331 // Dont remove this unless you know what you are doing.
332 meta_fake_bit = key_modifier::none;
334 // Can this happen now ?
335 if (func.action == LFUN_NOACTION) {
336 func = FuncRequest(LFUN_COMMAND_PREFIX);
339 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
341 << func.action << "]["
342 << to_utf8(keyseq->print(false)) << ']'
345 // already here we know if it any point in going further
346 // why not return already here if action == -1 and
347 // num_bytes == 0? (Lgb)
349 if (keyseq->length() > 1) {
350 lyx_view_->message(keyseq->print(true));
354 // Maybe user can only reach the key via holding down shift.
355 // Let's see. But only if shift is the only modifier
356 if (func.action == LFUN_UNKNOWN_ACTION &&
357 state == key_modifier::shift) {
358 LYXERR(Debug::KEY) << "Trying without shift" << endl;
359 func = keyseq->addkey(keysym, key_modifier::none);
360 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
363 if (func.action == LFUN_UNKNOWN_ACTION) {
364 // Hmm, we didn't match any of the keysequences. See
365 // if it's normal insertable text not already covered
367 if (keysym->isText() && keyseq->length() == 1) {
368 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
369 func = FuncRequest(LFUN_SELF_INSERT,
370 FuncRequest::KEYBOARD);
372 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
373 lyx_view_->message(_("Unknown function."));
378 if (func.action == LFUN_SELF_INSERT) {
379 if (encoded_last_key != 0) {
380 docstring const arg(1, encoded_last_key);
381 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
382 FuncRequest::KEYBOARD));
384 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
390 /* When we move around, or type, it's nice to be able to see
391 * the cursor immediately after the keypress.
393 if (lyx_view_ && lyx_view_->currentWorkArea())
394 lyx_view_->currentWorkArea()->startBlinkingCursor();
398 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
400 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
403 Cursor & cur = view()->cursor();
405 /* In LyX/Mac, when a dialog is open, the menus of the
406 application can still be accessed without giving focus to
407 the main window. In this case, we want to disable the menu
408 entries that are buffer-related.
410 Note that this code is not perfect, as bug 1941 attests:
411 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
413 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
414 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
417 if (cmd.action == LFUN_NOACTION) {
418 flag.message(from_utf8(N_("Nothing to do")));
423 switch (cmd.action) {
424 case LFUN_UNKNOWN_ACTION:
425 #ifndef HAVE_LIBAIKSAURUS
426 case LFUN_THESAURUS_ENTRY:
436 if (flag.unknown()) {
437 flag.message(from_utf8(N_("Unknown action")));
441 if (!flag.enabled()) {
442 if (flag.message().empty())
443 flag.message(from_utf8(N_("Command disabled")));
447 // Check whether we need a buffer
448 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
450 flag.message(from_utf8(N_("Command not allowed with"
451 "out any document open")));
456 // I would really like to avoid having this switch and rather try to
457 // encode this in the function itself.
458 // -- And I'd rather let an inset decide which LFUNs it is willing
459 // to handle (Andre')
461 switch (cmd.action) {
462 case LFUN_BUFFER_TOGGLE_READ_ONLY:
463 flag.setOnOff(buf->isReadonly());
466 case LFUN_BUFFER_SWITCH:
467 // toggle on the current buffer, but do not toggle off
468 // the other ones (is that a good idea?)
469 if (buf && to_utf8(cmd.argument()) == buf->fileName())
473 case LFUN_BUFFER_EXPORT:
474 enable = cmd.argument() == "custom"
475 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
478 case LFUN_BUFFER_CHKTEX:
479 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
482 case LFUN_BUILD_PROGRAM:
483 enable = Exporter::isExportable(*buf, "program");
486 case LFUN_LAYOUT_TABULAR:
487 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
491 case LFUN_LAYOUT_PARAGRAPH:
492 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
495 case LFUN_VC_REGISTER:
496 enable = !buf->lyxvc().inUse();
498 case LFUN_VC_CHECK_IN:
499 enable = buf->lyxvc().inUse() && !buf->isReadonly();
501 case LFUN_VC_CHECK_OUT:
502 enable = buf->lyxvc().inUse() && buf->isReadonly();
505 case LFUN_VC_UNDO_LAST:
506 enable = buf->lyxvc().inUse();
508 case LFUN_BUFFER_RELOAD:
509 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
510 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
513 case LFUN_INSET_SETTINGS: {
517 Inset::Code code = cur.inset().lyxCode();
519 case Inset::TABULAR_CODE:
520 enable = cmd.argument() == "tabular";
522 case Inset::ERT_CODE:
523 enable = cmd.argument() == "ert";
525 case Inset::FLOAT_CODE:
526 enable = cmd.argument() == "float";
528 case Inset::WRAP_CODE:
529 enable = cmd.argument() == "wrap";
531 case Inset::NOTE_CODE:
532 enable = cmd.argument() == "note";
534 case Inset::BRANCH_CODE:
535 enable = cmd.argument() == "branch";
537 case Inset::BOX_CODE:
538 enable = cmd.argument() == "box";
540 case Inset::LISTINGS_CODE:
541 enable = cmd.argument() == "listings";
549 case LFUN_INSET_APPLY: {
550 string const name = cmd.getArg(0);
551 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
553 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
555 if (!inset->getStatus(cur, fr, fs)) {
556 // Every inset is supposed to handle this
561 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
562 flag |= getStatus(fr);
564 enable = flag.enabled();
568 case LFUN_DIALOG_TOGGLE:
569 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
570 // fall through to set "enable"
571 case LFUN_DIALOG_SHOW: {
572 string const name = cmd.getArg(0);
574 enable = name == "aboutlyx"
575 || name == "file" //FIXME: should be removed.
577 || name == "texinfo";
578 else if (name == "print")
579 enable = Exporter::isExportable(*buf, "dvi")
580 && lyxrc.print_command != "none";
581 else if (name == "character")
582 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
583 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
584 else if (name == "latexlog")
585 enable = isFileReadable(FileName(buf->getLogName().second));
586 else if (name == "spellchecker")
587 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
588 enable = !buf->isReadonly();
592 else if (name == "vclog")
593 enable = buf->lyxvc().inUse();
597 case LFUN_DIALOG_SHOW_NEW_INSET:
598 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
599 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
600 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
602 if (cur.inset().getStatus(cur, cmd, flag))
607 case LFUN_DIALOG_UPDATE: {
608 string const name = cmd.getArg(0);
610 enable = name == "prefs";
614 case LFUN_CITATION_INSERT: {
615 FuncRequest fr(LFUN_INSET_INSERT, "citation");
616 enable = getStatus(fr).enabled();
620 case LFUN_BUFFER_WRITE: {
621 enable = lyx_view_->buffer()->isUnnamed()
622 || !lyx_view_->buffer()->isClean();
627 case LFUN_BUFFER_WRITE_ALL: {
628 // We enable the command only if there are some modified buffers
629 Buffer * first = theBufferList().first();
630 bool modified = false;
634 // We cannot use a for loop as the buffer list is a cycle.
640 b = theBufferList().next(b);
641 } while (b != first);
649 case LFUN_BOOKMARK_GOTO: {
650 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
651 enable = LyX::ref().session().bookmarks().isValid(num);
655 case LFUN_BOOKMARK_CLEAR:
656 enable = LyX::ref().session().bookmarks().size() > 0;
659 case LFUN_TOOLBAR_TOGGLE: {
660 bool const current = lyx_view_->getToolbars().visible(cmd.getArg(0));
661 flag.setOnOff(current);
664 case LFUN_WINDOW_CLOSE: {
665 enable = (theApp()->gui().viewIds().size() > 1);
669 // this one is difficult to get right. As a half-baked
670 // solution, we consider only the first action of the sequence
671 case LFUN_COMMAND_SEQUENCE: {
672 // argument contains ';'-terminated commands
673 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
674 FuncRequest func(lyxaction.lookupFunc(firstcmd));
675 func.origin = cmd.origin;
676 flag = getStatus(func);
679 case LFUN_BUFFER_NEW:
680 case LFUN_BUFFER_NEW_TEMPLATE:
681 case LFUN_WORD_FIND_FORWARD:
682 case LFUN_WORD_FIND_BACKWARD:
683 case LFUN_COMMAND_PREFIX:
684 case LFUN_COMMAND_EXECUTE:
686 case LFUN_META_PREFIX:
687 case LFUN_BUFFER_CLOSE:
688 case LFUN_BUFFER_WRITE_AS:
689 case LFUN_BUFFER_UPDATE:
690 case LFUN_BUFFER_VIEW:
691 case LFUN_BUFFER_IMPORT:
692 case LFUN_BUFFER_AUTO_SAVE:
693 case LFUN_RECONFIGURE:
697 case LFUN_DROP_LAYOUTS_CHOICE:
699 case LFUN_SERVER_GET_NAME:
700 case LFUN_SERVER_NOTIFY:
701 case LFUN_SERVER_GOTO_FILE_ROW:
702 case LFUN_DIALOG_HIDE:
703 case LFUN_DIALOG_DISCONNECT_INSET:
704 case LFUN_BUFFER_CHILD_OPEN:
705 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
706 case LFUN_KEYMAP_OFF:
707 case LFUN_KEYMAP_PRIMARY:
708 case LFUN_KEYMAP_SECONDARY:
709 case LFUN_KEYMAP_TOGGLE:
711 case LFUN_BUFFER_EXPORT_CUSTOM:
712 case LFUN_BUFFER_PRINT:
713 case LFUN_PREFERENCES_SAVE:
714 case LFUN_SCREEN_FONT_UPDATE:
717 case LFUN_EXTERNAL_EDIT:
718 case LFUN_GRAPHICS_EDIT:
719 case LFUN_ALL_INSETS_TOGGLE:
720 case LFUN_BUFFER_LANGUAGE:
721 case LFUN_TEXTCLASS_APPLY:
722 case LFUN_TEXTCLASS_LOAD:
723 case LFUN_BUFFER_SAVE_AS_DEFAULT:
724 case LFUN_BUFFER_PARAMS_APPLY:
725 case LFUN_LYXRC_APPLY:
726 case LFUN_BUFFER_NEXT:
727 case LFUN_BUFFER_PREVIOUS:
728 case LFUN_WINDOW_NEW:
730 // these are handled in our dispatch()
734 if (!getLocalStatus(cur, cmd, flag))
735 flag = view()->getStatus(cmd);
741 // Can we use a readonly buffer?
742 if (buf && buf->isReadonly()
743 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
744 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
745 flag.message(from_utf8(N_("Document is read-only")));
749 // Are we in a DELETED change-tracking region?
750 if (buf && lookupChangeType(cur, true) == Change::DELETED
751 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
752 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
753 flag.message(from_utf8(N_("This portion of the document is deleted.")));
757 // the default error message if we disable the command
758 if (!flag.enabled() && flag.message().empty())
759 flag.message(from_utf8(N_("Command disabled")));
765 bool LyXFunc::ensureBufferClean(BufferView * bv)
767 Buffer & buf = bv->buffer();
771 docstring const file = makeDisplayPath(buf.fileName(), 30);
772 docstring text = bformat(_("The document %1$s has unsaved "
773 "changes.\n\nDo you want to save "
774 "the document?"), file);
775 int const ret = Alert::prompt(_("Save changed document?"),
776 text, 0, 1, _("&Save"),
780 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
782 return buf.isClean();
788 void showPrintError(string const & name)
790 docstring str = bformat(_("Could not print the document %1$s.\n"
791 "Check that your printer is set up correctly."),
792 makeDisplayPath(name, 50));
793 Alert::error(_("Print document failed"), str);
797 void loadTextclass(string const & name)
799 std::pair<bool, textclass_type> const tc_pair =
800 textclasslist.numberOfClass(name);
802 if (!tc_pair.first) {
803 lyxerr << "Document class \"" << name
804 << "\" does not exist."
809 textclass_type const tc = tc_pair.second;
811 if (!textclasslist[tc].load()) {
812 docstring s = bformat(_("The document could not be converted\n"
813 "into the document class %1$s."),
814 from_utf8(textclasslist[tc].name()));
815 Alert::error(_("Could not change class"), s);
820 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
825 void LyXFunc::dispatch(FuncRequest const & cmd)
827 string const argument = to_utf8(cmd.argument());
828 kb_action const action = cmd.action;
830 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
831 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
833 // we have not done anything wrong yet.
835 dispatch_buffer.erase();
837 // redraw the screen at the end (first of the two drawing steps).
838 //This is done unless explicitely requested otherwise
839 Update::flags updateFlags = Update::FitCursor;
841 FuncStatus const flag = getStatus(cmd);
842 if (!flag.enabled()) {
843 // We cannot use this function here
844 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
845 << lyxaction.getActionName(action)
846 << " [" << action << "] is disabled at this location"
848 setErrorMessage(flag.message());
852 case LFUN_WORD_FIND_FORWARD:
853 case LFUN_WORD_FIND_BACKWARD: {
854 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
855 static docstring last_search;
856 docstring searched_string;
858 if (!cmd.argument().empty()) {
859 last_search = cmd.argument();
860 searched_string = cmd.argument();
862 searched_string = last_search;
865 if (searched_string.empty())
868 bool const fw = action == LFUN_WORD_FIND_FORWARD;
869 docstring const data =
870 find2string(searched_string, true, false, fw);
871 find(view(), FuncRequest(LFUN_WORD_FIND, data));
875 case LFUN_COMMAND_PREFIX:
876 BOOST_ASSERT(lyx_view_);
877 lyx_view_->message(keyseq->printOptions(true));
880 case LFUN_COMMAND_EXECUTE:
881 BOOST_ASSERT(lyx_view_);
882 lyx_view_->getToolbars().display("minibuffer", true);
883 lyx_view_->focus_command_buffer();
887 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
889 meta_fake_bit = key_modifier::none;
890 if (lyx_view_->buffer())
891 // cancel any selection
892 dispatch(FuncRequest(LFUN_MARK_OFF));
893 setMessage(from_ascii(N_("Cancel")));
896 case LFUN_META_PREFIX:
897 meta_fake_bit = key_modifier::alt;
898 setMessage(keyseq->print(true));
901 case LFUN_BUFFER_TOGGLE_READ_ONLY:
902 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
903 if (lyx_view_->buffer()->lyxvc().inUse())
904 lyx_view_->buffer()->lyxvc().toggleReadOnly();
906 lyx_view_->buffer()->setReadonly(
907 !lyx_view_->buffer()->isReadonly());
910 // --- Menus -----------------------------------------------
911 case LFUN_BUFFER_NEW:
912 menuNew(argument, false);
913 updateFlags = Update::None;
916 case LFUN_BUFFER_NEW_TEMPLATE:
917 menuNew(argument, true);
918 updateFlags = Update::None;
921 case LFUN_BUFFER_CLOSE:
923 updateFlags = Update::None;
926 case LFUN_BUFFER_WRITE:
927 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
928 if (!lyx_view_->buffer()->isUnnamed()) {
929 docstring const str = bformat(_("Saving document %1$s..."),
930 makeDisplayPath(lyx_view_->buffer()->fileName()));
931 lyx_view_->message(str);
932 menuWrite(lyx_view_->buffer());
933 lyx_view_->message(str + _(" done."));
935 writeAs(lyx_view_->buffer());
937 updateFlags = Update::None;
940 case LFUN_BUFFER_WRITE_AS:
941 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
942 writeAs(lyx_view_->buffer(), argument);
943 updateFlags = Update::None;
946 case LFUN_BUFFER_WRITE_ALL: {
947 Buffer * first = theBufferList().first();
950 lyx_view_->message(_("Saving all documents..."));
952 // We cannot use a for loop as the buffer list cycles.
955 if (!b->isUnnamed()) {
957 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
961 b = theBufferList().next(b);
962 } while (b != first);
963 lyx_view_->message(_("All documents saved."));
966 updateFlags = Update::None;
970 case LFUN_BUFFER_RELOAD: {
971 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
972 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
973 docstring text = bformat(_("Any changes will be lost. Are you sure "
974 "you want to revert to the saved version of the document %1$s?"), file);
975 int const ret = Alert::prompt(_("Revert to saved document?"),
976 text, 1, 1, _("&Revert"), _("&Cancel"));
983 case LFUN_BUFFER_UPDATE:
984 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
985 Exporter::Export(lyx_view_->buffer(), argument, true);
988 case LFUN_BUFFER_VIEW:
989 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
990 Exporter::preview(lyx_view_->buffer(), argument);
993 case LFUN_BUILD_PROGRAM:
994 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
995 Exporter::Export(lyx_view_->buffer(), "program", true);
998 case LFUN_BUFFER_CHKTEX:
999 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1000 lyx_view_->buffer()->runChktex();
1003 case LFUN_BUFFER_EXPORT:
1004 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1005 if (argument == "custom")
1006 lyx_view_->getDialogs().show("sendto");
1008 Exporter::Export(lyx_view_->buffer(), argument, false);
1012 case LFUN_BUFFER_EXPORT_CUSTOM: {
1013 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1015 string command = split(argument, format_name, ' ');
1016 Format const * format = formats.getFormat(format_name);
1018 lyxerr << "Format \"" << format_name
1019 << "\" not recognized!"
1024 Buffer * buffer = lyx_view_->buffer();
1026 // The name of the file created by the conversion process
1029 // Output to filename
1030 if (format->name() == "lyx") {
1031 string const latexname =
1032 buffer->getLatexName(false);
1033 filename = changeExtension(latexname,
1034 format->extension());
1035 filename = addName(buffer->temppath(), filename);
1037 if (!buffer->writeFile(FileName(filename)))
1041 Exporter::Export(buffer, format_name, true, filename);
1044 // Substitute $$FName for filename
1045 if (!contains(command, "$$FName"))
1046 command = "( " + command + " ) < $$FName";
1047 command = subst(command, "$$FName", filename);
1049 // Execute the command in the background
1051 call.startscript(Systemcall::DontWait, command);
1055 case LFUN_BUFFER_PRINT: {
1056 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1057 // FIXME: cmd.getArg() might fail if one of the arguments
1058 // contains double quotes
1059 string target = cmd.getArg(0);
1060 string target_name = cmd.getArg(1);
1061 string command = cmd.getArg(2);
1064 || target_name.empty()
1065 || command.empty()) {
1066 lyxerr << "Unable to parse \""
1067 << argument << '"' << endl;
1070 if (target != "printer" && target != "file") {
1071 lyxerr << "Unrecognized target \""
1072 << target << '"' << endl;
1076 Buffer * buffer = lyx_view_->buffer();
1078 if (!Exporter::Export(buffer, "dvi", true)) {
1079 showPrintError(buffer->fileName());
1083 // Push directory path.
1084 string const path(buffer->temppath());
1085 // Prevent the compiler from optimizing away p
1087 support::Path p(pp);
1089 // there are three cases here:
1090 // 1. we print to a file
1091 // 2. we print directly to a printer
1092 // 3. we print using a spool command (print to file first)
1095 string const dviname =
1096 changeExtension(buffer->getLatexName(true),
1099 if (target == "printer") {
1100 if (!lyxrc.print_spool_command.empty()) {
1101 // case 3: print using a spool
1102 string const psname =
1103 changeExtension(dviname,".ps");
1104 command += ' ' + lyxrc.print_to_file
1107 + quoteName(dviname);
1110 lyxrc.print_spool_command + ' ';
1111 if (target_name != "default") {
1112 command2 += lyxrc.print_spool_printerprefix
1116 command2 += quoteName(psname);
1118 // If successful, then spool command
1119 res = one.startscript(
1124 res = one.startscript(
1125 Systemcall::DontWait,
1128 // case 2: print directly to a printer
1129 if (target_name != "default")
1130 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1131 res = one.startscript(
1132 Systemcall::DontWait,
1133 command + quoteName(dviname));
1137 // case 1: print to a file
1138 FileName const filename(makeAbsPath(target_name,
1139 lyx_view_->buffer()->filePath()));
1140 FileName const dvifile(makeAbsPath(dviname, path));
1141 if (fs::exists(filename.toFilesystemEncoding())) {
1142 docstring text = bformat(
1143 _("The file %1$s already exists.\n\n"
1144 "Do you want to overwrite that file?"),
1145 makeDisplayPath(filename.absFilename()));
1146 if (Alert::prompt(_("Overwrite file?"),
1147 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1150 command += ' ' + lyxrc.print_to_file
1151 + quoteName(filename.toFilesystemEncoding())
1153 + quoteName(dvifile.toFilesystemEncoding());
1154 res = one.startscript(Systemcall::DontWait,
1159 showPrintError(buffer->fileName());
1163 case LFUN_BUFFER_IMPORT:
1168 // quitting is triggered by the gui code
1169 // (leaving the event loop).
1170 lyx_view_->message(from_utf8(N_("Exiting.")));
1171 if (theBufferList().quitWriteAll())
1172 theApp()->gui().closeAllViews();
1175 case LFUN_BUFFER_AUTO_SAVE:
1179 case LFUN_RECONFIGURE:
1180 BOOST_ASSERT(lyx_view_);
1181 reconfigure(*lyx_view_);
1184 case LFUN_HELP_OPEN: {
1185 BOOST_ASSERT(lyx_view_);
1186 string const arg = argument;
1188 setErrorMessage(from_ascii(N_("Missing argument")));
1191 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1192 if (fname.empty()) {
1193 lyxerr << "LyX: unable to find documentation file `"
1194 << arg << "'. Bad installation?" << endl;
1197 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1198 makeDisplayPath(fname.absFilename())));
1199 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1202 lyx_view_->setBuffer(buf);
1203 lyx_view_->showErrorList("Parse");
1205 updateFlags = Update::None;
1209 // --- version control -------------------------------
1210 case LFUN_VC_REGISTER:
1211 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1212 if (!ensureBufferClean(view()))
1214 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1215 lyx_view_->buffer()->lyxvc().registrer();
1218 updateFlags = Update::Force;
1221 case LFUN_VC_CHECK_IN:
1222 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1223 if (!ensureBufferClean(view()))
1225 if (lyx_view_->buffer()->lyxvc().inUse()
1226 && !lyx_view_->buffer()->isReadonly()) {
1227 lyx_view_->buffer()->lyxvc().checkIn();
1232 case LFUN_VC_CHECK_OUT:
1233 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1234 if (!ensureBufferClean(view()))
1236 if (lyx_view_->buffer()->lyxvc().inUse()
1237 && lyx_view_->buffer()->isReadonly()) {
1238 lyx_view_->buffer()->lyxvc().checkOut();
1243 case LFUN_VC_REVERT:
1244 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1245 lyx_view_->buffer()->lyxvc().revert();
1249 case LFUN_VC_UNDO_LAST:
1250 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1251 lyx_view_->buffer()->lyxvc().undoLast();
1255 // --- buffers ----------------------------------------
1256 case LFUN_BUFFER_SWITCH:
1257 BOOST_ASSERT(lyx_view_);
1258 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1259 updateFlags = Update::None;
1262 case LFUN_BUFFER_NEXT:
1263 BOOST_ASSERT(lyx_view_);
1264 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1265 updateFlags = Update::None;
1268 case LFUN_BUFFER_PREVIOUS:
1269 BOOST_ASSERT(lyx_view_);
1270 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1271 updateFlags = Update::None;
1275 BOOST_ASSERT(lyx_view_);
1276 newFile(*lyx_view_, argument);
1277 updateFlags = Update::None;
1280 case LFUN_FILE_OPEN:
1281 BOOST_ASSERT(lyx_view_);
1283 updateFlags = Update::None;
1286 case LFUN_DROP_LAYOUTS_CHOICE:
1287 BOOST_ASSERT(lyx_view_);
1288 lyx_view_->getToolbars().openLayoutList();
1291 case LFUN_MENU_OPEN:
1292 BOOST_ASSERT(lyx_view_);
1293 lyx_view_->getMenubar().openByName(from_utf8(argument));
1296 // --- lyxserver commands ----------------------------
1297 case LFUN_SERVER_GET_NAME:
1298 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1299 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1300 LYXERR(Debug::INFO) << "FNAME["
1301 << lyx_view_->buffer()->fileName()
1305 case LFUN_SERVER_NOTIFY:
1306 dispatch_buffer = keyseq->print(false);
1307 theServer().notifyClient(to_utf8(dispatch_buffer));
1310 case LFUN_SERVER_GOTO_FILE_ROW: {
1311 BOOST_ASSERT(lyx_view_);
1314 istringstream is(argument);
1315 is >> file_name >> row;
1317 bool loaded = false;
1318 if (prefixIs(file_name, package().temp_dir().absFilename()))
1319 // Needed by inverse dvi search. If it is a file
1320 // in tmpdir, call the apropriated function
1321 buf = theBufferList().getBufferFromTmp(file_name);
1323 // Must replace extension of the file to be .lyx
1324 // and get full path
1325 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1326 // Either change buffer or load the file
1327 if (theBufferList().exists(s.absFilename()))
1328 buf = theBufferList().getBuffer(s.absFilename());
1330 buf = lyx_view_->loadLyXFile(s);
1336 updateFlags = Update::None;
1341 lyx_view_->setBuffer(buf);
1342 view()->setCursorFromRow(row);
1344 lyx_view_->showErrorList("Parse");
1345 updateFlags = Update::FitCursor;
1349 case LFUN_DIALOG_SHOW: {
1350 BOOST_ASSERT(lyx_view_);
1351 string const name = cmd.getArg(0);
1352 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1354 if (name == "character") {
1355 data = freefont2string();
1357 lyx_view_->getDialogs().show("character", data);
1358 } else if (name == "latexlog") {
1359 pair<Buffer::LogType, string> const logfile =
1360 lyx_view_->buffer()->getLogName();
1361 switch (logfile.first) {
1362 case Buffer::latexlog:
1365 case Buffer::buildlog:
1369 data += Lexer::quoteString(logfile.second);
1370 lyx_view_->getDialogs().show("log", data);
1371 } else if (name == "vclog") {
1372 string const data = "vc " +
1373 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1374 lyx_view_->getDialogs().show("log", data);
1376 lyx_view_->getDialogs().show(name, data);
1380 case LFUN_DIALOG_SHOW_NEW_INSET: {
1381 BOOST_ASSERT(lyx_view_);
1382 string const name = cmd.getArg(0);
1383 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1384 if (name == "bibitem" ||
1388 name == "nomenclature" ||
1392 InsetCommandParams p(name);
1393 data = InsetCommandMailer::params2string(name, p);
1394 } else if (name == "include") {
1395 // data is the include type: one of "include",
1396 // "input", "verbatiminput" or "verbatiminput*"
1398 // default type is requested
1400 InsetCommandParams p(data);
1401 data = InsetIncludeMailer::params2string(p);
1402 } else if (name == "box") {
1403 // \c data == "Boxed" || "Frameless" etc
1404 InsetBoxParams p(data);
1405 data = InsetBoxMailer::params2string(p);
1406 } else if (name == "branch") {
1407 InsetBranchParams p;
1408 data = InsetBranchMailer::params2string(p);
1409 } else if (name == "citation") {
1410 InsetCommandParams p("cite");
1411 data = InsetCommandMailer::params2string(name, p);
1412 } else if (name == "ert") {
1413 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1414 } else if (name == "external") {
1415 InsetExternalParams p;
1416 Buffer const & buffer = *lyx_view_->buffer();
1417 data = InsetExternalMailer::params2string(p, buffer);
1418 } else if (name == "float") {
1420 data = InsetFloatMailer::params2string(p);
1421 } else if (name == "listings") {
1422 InsetListingsParams p;
1423 data = InsetListingsMailer::params2string(p);
1424 } else if (name == "graphics") {
1425 InsetGraphicsParams p;
1426 Buffer const & buffer = *lyx_view_->buffer();
1427 data = InsetGraphicsMailer::params2string(p, buffer);
1428 } else if (name == "note") {
1430 data = InsetNoteMailer::params2string(p);
1431 } else if (name == "vspace") {
1433 data = InsetVSpaceMailer::params2string(space);
1434 } else if (name == "wrap") {
1436 data = InsetWrapMailer::params2string(p);
1438 lyx_view_->getDialogs().show(name, data, 0);
1442 case LFUN_DIALOG_UPDATE: {
1443 BOOST_ASSERT(lyx_view_);
1444 string const & name = argument;
1445 // Can only update a dialog connected to an existing inset
1446 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1448 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1449 inset->dispatch(view()->cursor(), fr);
1450 } else if (name == "paragraph") {
1451 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1452 } else if (name == "prefs") {
1453 lyx_view_->getDialogs().update(name, string());
1458 case LFUN_DIALOG_HIDE:
1459 LyX::cref().hideDialogs(argument, 0);
1462 case LFUN_DIALOG_TOGGLE: {
1463 BOOST_ASSERT(lyx_view_);
1464 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1465 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1467 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1471 case LFUN_DIALOG_DISCONNECT_INSET:
1472 BOOST_ASSERT(lyx_view_);
1473 lyx_view_->getDialogs().disconnect(argument);
1477 case LFUN_CITATION_INSERT: {
1478 BOOST_ASSERT(lyx_view_);
1479 if (!argument.empty()) {
1480 // we can have one optional argument, delimited by '|'
1481 // citation-insert <key>|<text_before>
1482 // this should be enhanced to also support text_after
1483 // and citation style
1484 string arg = argument;
1486 if (contains(argument, "|")) {
1487 arg = token(argument, '|', 0);
1488 opt1 = token(argument, '|', 1);
1490 InsetCommandParams icp("cite");
1491 icp["key"] = from_utf8(arg);
1493 icp["before"] = from_utf8(opt1);
1494 string icstr = InsetCommandMailer::params2string("citation", icp);
1495 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1498 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1502 case LFUN_BUFFER_CHILD_OPEN: {
1503 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1504 Buffer * parent = lyx_view_->buffer();
1505 FileName filename = makeAbsPath(argument, parent->filePath());
1506 view()->saveBookmark(false);
1508 bool parsed = false;
1509 if (theBufferList().exists(filename.absFilename())) {
1510 child = theBufferList().getBuffer(filename.absFilename());
1512 setMessage(bformat(_("Opening child document %1$s..."),
1513 makeDisplayPath(filename.absFilename())));
1514 child = lyx_view_->loadLyXFile(filename, true);
1518 // Set the parent name of the child document.
1519 // This makes insertion of citations and references in the child work,
1520 // when the target is in the parent or another child document.
1521 child->setParentName(parent->fileName());
1522 updateLabels(*child->getMasterBuffer());
1523 lyx_view_->setBuffer(child);
1525 lyx_view_->showErrorList("Parse");
1528 // If a screen update is required (in case where auto_open is false),
1529 // setBuffer() would have taken care of it already. Otherwise we shall
1530 // reset the update flag because it can cause a circular problem.
1532 updateFlags = Update::None;
1536 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1537 BOOST_ASSERT(lyx_view_);
1538 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1541 case LFUN_KEYMAP_OFF:
1542 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1543 lyx_view_->view()->getIntl().keyMapOn(false);
1546 case LFUN_KEYMAP_PRIMARY:
1547 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1548 lyx_view_->view()->getIntl().keyMapPrim();
1551 case LFUN_KEYMAP_SECONDARY:
1552 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1553 lyx_view_->view()->getIntl().keyMapSec();
1556 case LFUN_KEYMAP_TOGGLE:
1557 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1558 lyx_view_->view()->getIntl().toggleKeyMap();
1564 string rest = split(argument, countstr, ' ');
1565 istringstream is(countstr);
1568 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1569 for (int i = 0; i < count; ++i)
1570 dispatch(lyxaction.lookupFunc(rest));
1574 case LFUN_COMMAND_SEQUENCE: {
1575 // argument contains ';'-terminated commands
1576 string arg = argument;
1577 while (!arg.empty()) {
1579 arg = split(arg, first, ';');
1580 FuncRequest func(lyxaction.lookupFunc(first));
1581 func.origin = cmd.origin;
1587 case LFUN_PREFERENCES_SAVE: {
1588 lyxrc.write(makeAbsPath("preferences",
1589 package().user_support().absFilename()),
1594 case LFUN_SCREEN_FONT_UPDATE:
1595 BOOST_ASSERT(lyx_view_);
1596 // handle the screen font changes.
1597 theFontLoader().update();
1598 /// FIXME: only the current view will be updated. the Gui
1599 /// class is able to furnish the list of views.
1600 updateFlags = Update::Force;
1603 case LFUN_SET_COLOR: {
1605 string const x11_name = split(argument, lyx_name, ' ');
1606 if (lyx_name.empty() || x11_name.empty()) {
1607 setErrorMessage(from_ascii(N_(
1608 "Syntax: set-color <lyx_name>"
1613 bool const graphicsbg_changed =
1614 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1615 x11_name != lcolor.getX11Name(Color::graphicsbg));
1617 if (!lcolor.setColor(lyx_name, x11_name)) {
1619 bformat(_("Set-color \"%1$s\" failed "
1620 "- color is undefined or "
1621 "may not be redefined"),
1622 from_utf8(lyx_name)));
1626 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1628 if (graphicsbg_changed) {
1629 // FIXME: The graphics cache no longer has a changeDisplay method.
1631 graphics::GCache::get().changeDisplay(true);
1638 BOOST_ASSERT(lyx_view_);
1639 lyx_view_->message(from_utf8(argument));
1642 case LFUN_EXTERNAL_EDIT: {
1643 BOOST_ASSERT(lyx_view_);
1644 FuncRequest fr(action, argument);
1645 InsetExternal().dispatch(view()->cursor(), fr);
1649 case LFUN_GRAPHICS_EDIT: {
1650 FuncRequest fr(action, argument);
1651 InsetGraphics().dispatch(view()->cursor(), fr);
1655 case LFUN_INSET_APPLY: {
1656 BOOST_ASSERT(lyx_view_);
1657 string const name = cmd.getArg(0);
1658 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1660 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1661 inset->dispatch(view()->cursor(), fr);
1663 FuncRequest fr(LFUN_INSET_INSERT, argument);
1666 // ideally, the update flag should be set by the insets,
1667 // but this is not possible currently
1668 updateFlags = Update::Force | Update::FitCursor;
1672 case LFUN_ALL_INSETS_TOGGLE: {
1673 BOOST_ASSERT(lyx_view_);
1675 string const name = split(argument, action, ' ');
1676 Inset::Code const inset_code =
1677 Inset::translate(name);
1679 Cursor & cur = view()->cursor();
1680 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1682 Inset & inset = lyx_view_->buffer()->inset();
1683 InsetIterator it = inset_iterator_begin(inset);
1684 InsetIterator const end = inset_iterator_end(inset);
1685 for (; it != end; ++it) {
1686 if (!it->asInsetMath()
1687 && (inset_code == Inset::NO_CODE
1688 || inset_code == it->lyxCode())) {
1689 Cursor tmpcur = cur;
1690 tmpcur.pushLeft(*it);
1691 it->dispatch(tmpcur, fr);
1694 updateFlags = Update::Force | Update::FitCursor;
1698 case LFUN_BUFFER_LANGUAGE: {
1699 BOOST_ASSERT(lyx_view_);
1700 Buffer & buffer = *lyx_view_->buffer();
1701 Language const * oldL = buffer.params().language;
1702 Language const * newL = languages.getLanguage(argument);
1703 if (!newL || oldL == newL)
1706 if (oldL->rightToLeft() == newL->rightToLeft()
1707 && !buffer.isMultiLingual())
1708 buffer.changeLanguage(oldL, newL);
1712 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1713 string const fname =
1714 addName(addPath(package().user_support().absFilename(), "templates/"),
1716 Buffer defaults(fname);
1718 istringstream ss(argument);
1721 int const unknown_tokens = defaults.readHeader(lex);
1723 if (unknown_tokens != 0) {
1724 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1725 << unknown_tokens << " unknown token"
1726 << (unknown_tokens == 1 ? "" : "s")
1730 if (defaults.writeFile(FileName(defaults.fileName())))
1731 setMessage(bformat(_("Document defaults saved in %1$s"),
1732 makeDisplayPath(fname)));
1734 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1738 case LFUN_BUFFER_PARAMS_APPLY: {
1739 BOOST_ASSERT(lyx_view_);
1740 biblio::CiteEngine const engine =
1741 lyx_view_->buffer()->params().getEngine();
1743 istringstream ss(argument);
1746 int const unknown_tokens =
1747 lyx_view_->buffer()->readHeader(lex);
1749 if (unknown_tokens != 0) {
1750 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1751 << unknown_tokens << " unknown token"
1752 << (unknown_tokens == 1 ? "" : "s")
1755 if (engine == lyx_view_->buffer()->params().getEngine())
1758 Cursor & cur = view()->cursor();
1759 FuncRequest fr(LFUN_INSET_REFRESH);
1761 Inset & inset = lyx_view_->buffer()->inset();
1762 InsetIterator it = inset_iterator_begin(inset);
1763 InsetIterator const end = inset_iterator_end(inset);
1764 for (; it != end; ++it)
1765 if (it->lyxCode() == Inset::CITE_CODE)
1766 it->dispatch(cur, fr);
1770 case LFUN_TEXTCLASS_APPLY: {
1771 BOOST_ASSERT(lyx_view_);
1772 Buffer * buffer = lyx_view_->buffer();
1774 textclass_type const old_class =
1775 buffer->params().textclass;
1777 loadTextclass(argument);
1779 std::pair<bool, textclass_type> const tc_pair =
1780 textclasslist.numberOfClass(argument);
1785 textclass_type const new_class = tc_pair.second;
1786 if (old_class == new_class)
1790 lyx_view_->message(_("Converting document to new document class..."));
1791 recordUndoFullDocument(view());
1792 buffer->params().textclass = new_class;
1793 StableDocIterator backcur(view()->cursor());
1794 ErrorList & el = buffer->errorList("Class Switch");
1795 cap::switchBetweenClasses(
1796 old_class, new_class,
1797 static_cast<InsetText &>(buffer->inset()), el);
1799 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1801 buffer->errors("Class Switch");
1802 updateLabels(*buffer);
1803 updateFlags = Update::Force | Update::FitCursor;
1807 case LFUN_TEXTCLASS_LOAD:
1808 loadTextclass(argument);
1811 case LFUN_LYXRC_APPLY: {
1812 LyXRC const lyxrc_orig = lyxrc;
1814 istringstream ss(argument);
1815 bool const success = lyxrc.read(ss) == 0;
1818 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1819 << "Unable to read lyxrc data"
1824 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1826 /// We force the redraw in any case because there might be
1827 /// some screen font changes.
1828 /// FIXME: only the current view will be updated. the Gui
1829 /// class is able to furnish the list of views.
1830 updateFlags = Update::Force;
1834 case LFUN_WINDOW_NEW:
1835 LyX::ref().newLyXView();
1838 case LFUN_WINDOW_CLOSE:
1839 BOOST_ASSERT(lyx_view_);
1840 BOOST_ASSERT(theApp());
1841 // update bookmark pit of the current buffer before window close
1842 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1843 gotoBookmark(i+1, false, false);
1844 // ask the user for saving changes or cancel quit
1845 if (!theBufferList().quitWriteAll())
1850 case LFUN_BOOKMARK_GOTO:
1851 // go to bookmark, open unopened file and switch to buffer if necessary
1852 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1855 case LFUN_BOOKMARK_CLEAR:
1856 LyX::ref().session().bookmarks().clear();
1859 case LFUN_TOOLBAR_TOGGLE: {
1860 BOOST_ASSERT(lyx_view_);
1861 string const name = cmd.getArg(0);
1862 bool const allowauto = cmd.getArg(1) == "allowauto";
1863 lyx_view_->toggleToolbarState(name, allowauto);
1864 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1866 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1871 if (tbi->flags & ToolbarInfo::ON)
1873 else if (tbi->flags & ToolbarInfo::OFF)
1875 else if (tbi->flags & ToolbarInfo::AUTO)
1878 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1879 _(tbi->gui_name), state));
1884 BOOST_ASSERT(lyx_view_);
1885 view()->cursor().dispatch(cmd);
1886 updateFlags = view()->cursor().result().update();
1887 if (!view()->cursor().result().dispatched())
1888 updateFlags = view()->dispatch(cmd);
1893 if (lyx_view_ && lyx_view_->buffer()) {
1894 // BufferView::update() updates the ViewMetricsInfo and
1895 // also initializes the position cache for all insets in
1896 // (at least partially) visible top-level paragraphs.
1897 // We will redraw the screen only if needed.
1898 if (view()->update(updateFlags)) {
1899 // Buffer::changed() signals that a repaint is needed.
1900 // The frontend (WorkArea) knows which area to repaint
1901 // thanks to the ViewMetricsInfo updated above.
1902 lyx_view_->buffer()->changed();
1905 lyx_view_->updateStatusBar();
1907 // if we executed a mutating lfun, mark the buffer as dirty
1909 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1910 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1911 lyx_view_->buffer()->markDirty();
1913 //Do we have a selection?
1914 theSelection().haveSelection(view()->cursor().selection());
1916 if (view()->cursor().inTexted()) {
1917 lyx_view_->updateLayoutChoice();
1921 if (!quitting && lyx_view_) {
1922 lyx_view_->updateMenubar();
1923 lyx_view_->updateToolbars();
1924 // Some messages may already be translated, so we cannot use _()
1925 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1930 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1932 const bool verbose = (cmd.origin == FuncRequest::MENU
1933 || cmd.origin == FuncRequest::TOOLBAR
1934 || cmd.origin == FuncRequest::COMMANDBUFFER);
1936 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1937 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1939 lyx_view_->message(msg);
1943 docstring dispatch_msg = msg;
1944 if (!dispatch_msg.empty())
1945 dispatch_msg += ' ';
1947 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1949 bool argsadded = false;
1951 if (!cmd.argument().empty()) {
1952 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1953 comname += ' ' + cmd.argument();
1958 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
1960 if (!shortcuts.empty())
1961 comname += ": " + shortcuts;
1962 else if (!argsadded && !cmd.argument().empty())
1963 comname += ' ' + cmd.argument();
1965 if (!comname.empty()) {
1966 comname = rtrim(comname);
1967 dispatch_msg += '(' + rtrim(comname) + ')';
1970 LYXERR(Debug::ACTION) << "verbose dispatch msg "
1971 << to_utf8(dispatch_msg) << endl;
1972 if (!dispatch_msg.empty())
1973 lyx_view_->message(dispatch_msg);
1977 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1979 // FIXME: initpath is not used. What to do?
1980 string initpath = lyxrc.document_path;
1981 string filename(name);
1983 if (lyx_view_->buffer()) {
1984 string const trypath = lyx_view_->buffer()->filePath();
1985 // If directory is writeable, use this as default.
1986 if (isDirWriteable(FileName(trypath)))
1990 static int newfile_number;
1992 if (filename.empty()) {
1993 filename = addName(lyxrc.document_path,
1994 "newfile" + convert<string>(++newfile_number) + ".lyx");
1995 while (theBufferList().exists(filename) ||
1996 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
1998 filename = addName(lyxrc.document_path,
1999 "newfile" + convert<string>(newfile_number) +
2004 // The template stuff
2007 FileDialog fileDlg(_("Select template file"),
2008 LFUN_SELECT_FILE_SYNC,
2009 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2010 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2012 FileDialog::Result result =
2013 fileDlg.open(from_utf8(lyxrc.template_path),
2014 FileFilterList(_("LyX Documents (*.lyx)")),
2017 if (result.first == FileDialog::Later)
2019 if (result.second.empty())
2021 templname = to_utf8(result.second);
2024 Buffer * const b = newFile(filename, templname, !name.empty());
2026 lyx_view_->setBuffer(b);
2030 void LyXFunc::open(string const & fname)
2032 string initpath = lyxrc.document_path;
2034 if (lyx_view_->buffer()) {
2035 string const trypath = lyx_view_->buffer()->filePath();
2036 // If directory is writeable, use this as default.
2037 if (isDirWriteable(FileName(trypath)))
2043 if (fname.empty()) {
2044 FileDialog fileDlg(_("Select document to open"),
2046 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2047 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2049 FileDialog::Result result =
2050 fileDlg.open(from_utf8(initpath),
2051 FileFilterList(_("LyX Documents (*.lyx)")),
2054 if (result.first == FileDialog::Later)
2057 filename = to_utf8(result.second);
2059 // check selected filename
2060 if (filename.empty()) {
2061 lyx_view_->message(_("Canceled."));
2067 // get absolute path of file and add ".lyx" to the filename if
2069 FileName const fullname = fileSearch(string(), filename, "lyx");
2070 if (!fullname.empty())
2071 filename = fullname.absFilename();
2073 // if the file doesn't exist, let the user create one
2074 if (!fs::exists(fullname.toFilesystemEncoding())) {
2075 // the user specifically chose this name. Believe him.
2076 Buffer * const b = newFile(filename, string(), true);
2078 lyx_view_->setBuffer(b);
2082 docstring const disp_fn = makeDisplayPath(filename);
2083 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2086 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2089 lyx_view_->setBuffer(buf);
2090 lyx_view_->showErrorList("Parse");
2091 str2 = bformat(_("Document %1$s opened."), disp_fn);
2093 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2095 lyx_view_->message(str2);
2099 void LyXFunc::doImport(string const & argument)
2102 string filename = split(argument, format, ' ');
2104 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2105 << " file: " << filename << endl;
2107 // need user interaction
2108 if (filename.empty()) {
2109 string initpath = lyxrc.document_path;
2111 if (lyx_view_->buffer()) {
2112 string const trypath = lyx_view_->buffer()->filePath();
2113 // If directory is writeable, use this as default.
2114 if (isDirWriteable(FileName(trypath)))
2118 docstring const text = bformat(_("Select %1$s file to import"),
2119 formats.prettyName(format));
2121 FileDialog fileDlg(text,
2123 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2124 make_pair(_("Examples|#E#e"),
2125 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2127 docstring filter = formats.prettyName(format);
2130 filter += from_utf8(formats.extension(format));
2133 FileDialog::Result result =
2134 fileDlg.open(from_utf8(initpath),
2135 FileFilterList(filter),
2138 if (result.first == FileDialog::Later)
2141 filename = to_utf8(result.second);
2143 // check selected filename
2144 if (filename.empty())
2145 lyx_view_->message(_("Canceled."));
2148 if (filename.empty())
2151 // get absolute path of file
2152 FileName const fullname(makeAbsPath(filename));
2154 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2156 // Check if the document already is open
2157 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2158 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2159 lyx_view_->message(_("Canceled."));
2164 // if the file exists already, and we didn't do
2165 // -i lyx thefile.lyx, warn
2166 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2167 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2169 docstring text = bformat(_("The document %1$s already exists.\n\n"
2170 "Do you want to overwrite that document?"), file);
2171 int const ret = Alert::prompt(_("Overwrite document?"),
2172 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2175 lyx_view_->message(_("Canceled."));
2180 ErrorList errorList;
2181 Importer::Import(lyx_view_, fullname, format, errorList);
2182 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2186 void LyXFunc::closeBuffer()
2188 // goto bookmark to update bookmark pit.
2189 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2190 gotoBookmark(i+1, false, false);
2192 theBufferList().close(lyx_view_->buffer(), true);
2196 void LyXFunc::reloadBuffer()
2198 FileName filename(lyx_view_->buffer()->fileName());
2199 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2202 Buffer * buf = lyx_view_->loadLyXFile(filename);
2205 lyx_view_->setBuffer(buf);
2206 lyx_view_->showErrorList("Parse");
2207 str = bformat(_("Document %1$s reloaded."), disp_fn);
2209 str = bformat(_("Could not reload document %1$s"), disp_fn);
2211 lyx_view_->message(str);
2214 // Each "lyx_view_" should have it's own message method. lyxview and
2215 // the minibuffer would use the minibuffer, but lyxserver would
2216 // send an ERROR signal to its client. Alejandro 970603
2217 // This function is bit problematic when it comes to NLS, to make the
2218 // lyx servers client be language indepenent we must not translate
2219 // strings sent to this func.
2220 void LyXFunc::setErrorMessage(docstring const & m) const
2222 dispatch_buffer = m;
2227 void LyXFunc::setMessage(docstring const & m) const
2229 dispatch_buffer = m;
2233 docstring const LyXFunc::viewStatusMessage()
2235 // When meta-fake key is pressed, show the key sequence so far + "M-".
2237 return keyseq->print(true) + "M-";
2239 // Else, when a non-complete key sequence is pressed,
2240 // show the available options.
2241 if (keyseq->length() > 0 && !keyseq->deleted())
2242 return keyseq->printOptions(true);
2244 BOOST_ASSERT(lyx_view_);
2245 if (!lyx_view_->buffer())
2246 return _("Welcome to LyX!");
2248 return view()->cursor().currentState();
2252 BufferView * LyXFunc::view() const
2254 BOOST_ASSERT(lyx_view_);
2255 return lyx_view_->view();
2259 bool LyXFunc::wasMetaKey() const
2261 return (meta_fake_bit != key_modifier::none);
2267 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2269 // Why the switch you might ask. It is a trick to ensure that all
2270 // the elements in the LyXRCTags enum is handled. As you can see
2271 // there are no breaks at all. So it is just a huge fall-through.
2272 // The nice thing is that we will get a warning from the compiler
2273 // if we forget an element.
2274 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2276 case LyXRC::RC_ACCEPT_COMPOUND:
2277 case LyXRC::RC_ALT_LANG:
2278 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2279 case LyXRC::RC_PLAINTEXT_LINELEN:
2280 case LyXRC::RC_AUTOREGIONDELETE:
2281 case LyXRC::RC_AUTORESET_OPTIONS:
2282 case LyXRC::RC_AUTOSAVE:
2283 case LyXRC::RC_AUTO_NUMBER:
2284 case LyXRC::RC_BACKUPDIR_PATH:
2285 case LyXRC::RC_BIBTEX_COMMAND:
2286 case LyXRC::RC_BINDFILE:
2287 case LyXRC::RC_CHECKLASTFILES:
2288 case LyXRC::RC_USELASTFILEPOS:
2289 case LyXRC::RC_LOADSESSION:
2290 case LyXRC::RC_CHKTEX_COMMAND:
2291 case LyXRC::RC_CONVERTER:
2292 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2293 case LyXRC::RC_COPIER:
2294 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2295 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2296 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2297 case LyXRC::RC_DATE_INSERT_FORMAT:
2298 case LyXRC::RC_DEFAULT_LANGUAGE:
2299 case LyXRC::RC_DEFAULT_PAPERSIZE:
2300 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2301 case LyXRC::RC_DISPLAY_GRAPHICS:
2302 case LyXRC::RC_DOCUMENTPATH:
2303 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2304 string const encoded = FileName(
2305 lyxrc_new.document_path).toFilesystemEncoding();
2306 if (fs::exists(encoded) && fs::is_directory(encoded))
2307 support::package().document_dir() = FileName(lyxrc.document_path);
2309 case LyXRC::RC_ESC_CHARS:
2310 case LyXRC::RC_FONT_ENCODING:
2311 case LyXRC::RC_FORMAT:
2312 case LyXRC::RC_INDEX_COMMAND:
2313 case LyXRC::RC_INPUT:
2314 case LyXRC::RC_KBMAP:
2315 case LyXRC::RC_KBMAP_PRIMARY:
2316 case LyXRC::RC_KBMAP_SECONDARY:
2317 case LyXRC::RC_LABEL_INIT_LENGTH:
2318 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2319 case LyXRC::RC_LANGUAGE_AUTO_END:
2320 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2321 case LyXRC::RC_LANGUAGE_COMMAND_END:
2322 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2323 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2324 case LyXRC::RC_LANGUAGE_PACKAGE:
2325 case LyXRC::RC_LANGUAGE_USE_BABEL:
2326 case LyXRC::RC_MAKE_BACKUP:
2327 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2328 case LyXRC::RC_NUMLASTFILES:
2329 case LyXRC::RC_PATH_PREFIX:
2330 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2331 support::prependEnvPath("PATH", lyxrc.path_prefix);
2333 case LyXRC::RC_PERS_DICT:
2334 case LyXRC::RC_PREVIEW:
2335 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2336 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2337 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2338 case LyXRC::RC_PRINTCOPIESFLAG:
2339 case LyXRC::RC_PRINTER:
2340 case LyXRC::RC_PRINTEVENPAGEFLAG:
2341 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2342 case LyXRC::RC_PRINTFILEEXTENSION:
2343 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2344 case LyXRC::RC_PRINTODDPAGEFLAG:
2345 case LyXRC::RC_PRINTPAGERANGEFLAG:
2346 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2347 case LyXRC::RC_PRINTPAPERFLAG:
2348 case LyXRC::RC_PRINTREVERSEFLAG:
2349 case LyXRC::RC_PRINTSPOOL_COMMAND:
2350 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2351 case LyXRC::RC_PRINTTOFILE:
2352 case LyXRC::RC_PRINTTOPRINTER:
2353 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2354 case LyXRC::RC_PRINT_COMMAND:
2355 case LyXRC::RC_RTL_SUPPORT:
2356 case LyXRC::RC_SCREEN_DPI:
2357 case LyXRC::RC_SCREEN_FONT_ROMAN:
2358 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2359 case LyXRC::RC_SCREEN_FONT_SANS:
2360 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2361 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2362 case LyXRC::RC_SCREEN_FONT_SIZES:
2363 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2364 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2365 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2366 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2367 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2368 case LyXRC::RC_SCREEN_ZOOM:
2369 case LyXRC::RC_SERVERPIPE:
2370 case LyXRC::RC_SET_COLOR:
2371 case LyXRC::RC_SHOW_BANNER:
2372 case LyXRC::RC_SPELL_COMMAND:
2373 case LyXRC::RC_TEMPDIRPATH:
2374 case LyXRC::RC_TEMPLATEPATH:
2375 case LyXRC::RC_TEX_ALLOWS_SPACES:
2376 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2377 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2378 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2380 case LyXRC::RC_UIFILE:
2381 case LyXRC::RC_USER_EMAIL:
2382 case LyXRC::RC_USER_NAME:
2383 case LyXRC::RC_USETEMPDIR:
2384 case LyXRC::RC_USE_ALT_LANG:
2385 case LyXRC::RC_USE_CONVERTER_CACHE:
2386 case LyXRC::RC_USE_ESC_CHARS:
2387 case LyXRC::RC_USE_INP_ENC:
2388 case LyXRC::RC_USE_PERS_DICT:
2389 case LyXRC::RC_USE_SPELL_LIB:
2390 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2391 case LyXRC::RC_VIEWER:
2392 case LyXRC::RC_LAST: