3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
33 #include "Converter.h"
35 #include "CutAndPaste.h"
37 #include "DispatchResult.h"
39 #include "ErrorList.h"
41 #include "FuncRequest.h"
42 #include "FuncStatus.h"
44 #include "InsetIterator.h"
49 #include "LyXAction.h"
54 #include "Paragraph.h"
55 #include "ParagraphParameters.h"
56 #include "ParIterator.h"
60 #include "TextClassList.h"
61 #include "ToolbarBackend.h"
63 #include "insets/InsetBox.h"
64 #include "insets/InsetBranch.h"
65 #include "insets/InsetCommand.h"
66 #include "insets/InsetERT.h"
67 #include "insets/InsetExternal.h"
68 #include "insets/InsetFloat.h"
69 #include "insets/InsetListings.h"
70 #include "insets/InsetGraphics.h"
71 #include "insets/InsetInclude.h"
72 #include "insets/InsetNote.h"
73 #include "insets/InsetTabular.h"
74 #include "insets/InsetVSpace.h"
75 #include "insets/InsetWrap.h"
77 #include "frontends/Application.h"
78 #include "frontends/alert.h"
79 #include "frontends/Dialogs.h"
80 #include "frontends/FileDialog.h"
81 #include "frontends/FontLoader.h"
82 #include "frontends/Gui.h"
83 #include "frontends/KeySymbol.h"
84 #include "frontends/LyXView.h"
85 #include "frontends/Selection.h"
87 #include "support/environment.h"
88 #include "support/FileFilterList.h"
89 #include "support/filetools.h"
90 #include "support/lstrings.h"
91 #include "support/Path.h"
92 #include "support/Package.h"
93 #include "support/Systemcall.h"
94 #include "support/convert.h"
95 #include "support/os.h"
97 #include <boost/current_function.hpp>
102 using std::make_pair;
105 using std::istringstream;
106 using std::ostringstream;
112 using frontend::LyXView;
114 using support::absolutePath;
115 using support::addName;
116 using support::addPath;
117 using support::bformat;
118 using support::changeExtension;
119 using support::contains;
120 using support::FileFilterList;
121 using support::FileName;
122 using support::fileSearch;
123 using support::i18nLibFileSearch;
124 using support::makeDisplayPath;
125 using support::makeAbsPath;
126 using support::package;
127 using support::quoteName;
128 using support::rtrim;
129 using support::split;
130 using support::subst;
131 using support::Systemcall;
132 using support::token;
134 using support::prefixIs;
137 namespace Alert = frontend::Alert;
139 extern bool quitting;
144 bool import(LyXView * lv, FileName const & filename,
145 string const & format, ErrorList & errorList)
147 docstring const displaypath = makeDisplayPath(filename.absFilename());
148 lv->message(bformat(_("Importing %1$s..."), displaypath));
150 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
152 string loader_format;
153 vector<string> loaders = theConverters().loaders();
154 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
155 for (vector<string>::const_iterator it = loaders.begin();
156 it != loaders.end(); ++it) {
157 if (theConverters().isReachable(format, *it)) {
158 string const tofile =
159 changeExtension(filename.absFilename(),
160 formats.extension(*it));
161 if (!theConverters().convert(0, filename, FileName(tofile),
162 filename, format, *it, errorList))
168 if (loader_format.empty()) {
169 frontend::Alert::error(_("Couldn't import file"),
170 bformat(_("No information for importing the format %1$s."),
171 formats.prettyName(format)));
175 loader_format = format;
179 if (loader_format == "lyx") {
180 Buffer * buf = lv->loadLyXFile(lyxfile);
183 lv->message(_("file not imported!"));
190 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
195 bool as_paragraphs = loader_format == "textparagraph";
196 string filename2 = (loader_format == format) ? filename.absFilename()
197 : changeExtension(filename.absFilename(),
198 formats.extension(loader_format));
199 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
200 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
204 lv->message(_("imported."));
210 // This function runs "configure" and then rereads lyx.defaults to
211 // reconfigure the automatic settings.
212 void reconfigure(LyXView & lv, string const & option)
214 // emit message signal.
215 lv.message(_("Running configure..."));
217 // Run configure in user lyx directory
218 support::PathChanger p(package().user_support());
219 string configure_command = package().configure_command();
220 configure_command += option;
222 int ret = one.startscript(Systemcall::Wait, configure_command);
224 // emit message signal.
225 lv.message(_("Reloading configuration..."));
226 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
227 // Re-read packages.lst
228 LaTeXFeatures::getAvailable();
231 Alert::information(_("System reconfiguration failed"),
232 _("The system reconfiguration has failed.\n"
233 "Default textclass is used but LyX may "
234 "not be able to work properly.\n"
235 "Please reconfigure again if needed."));
238 Alert::information(_("System reconfigured"),
239 _("The system has been reconfigured.\n"
240 "You need to restart LyX to make use of any\n"
241 "updated document class specifications."));
245 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
247 // Try to fix cursor in case it is broken.
248 cursor.fixIfBroken();
250 // This is, of course, a mess. Better create a new doc iterator and use
251 // this in Inset::getStatus. This might require an additional
252 // BufferView * arg, though (which should be avoided)
253 //Cursor safe = *this;
255 for ( ; cursor.depth(); cursor.pop()) {
256 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
257 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
258 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
259 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
261 // The inset's getStatus() will return 'true' if it made
262 // a definitive decision on whether it want to handle the
263 // request or not. The result of this decision is put into
264 // the 'status' parameter.
265 if (cursor.inset().getStatus(cursor, cmd, status)) {
274 /** Return the change status at cursor position, taking in account the
275 * status at each level of the document iterator (a table in a deleted
276 * footnote is deleted).
277 * When \param outer is true, the top slice is not looked at.
279 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
281 size_t const depth = dit.depth() - (outer ? 1 : 0);
283 for (size_t i = 0 ; i < depth ; ++i) {
284 CursorSlice const & slice = dit[i];
285 if (!slice.inset().inMathed()
286 && slice.pos() < slice.paragraph().size()) {
287 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
288 if (ch != Change::UNCHANGED)
292 return Change::UNCHANGED;
299 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
304 void LyXFunc::initKeySequences(KeyMap * kb)
306 keyseq = KeySequence(kb, kb);
307 cancel_meta_seq = KeySequence(kb, kb);
311 void LyXFunc::setLyXView(LyXView * lv)
313 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
314 // save current selection to the selection buffer to allow
315 // middle-button paste in another window
316 cap::saveSelection(lyx_view_->view()->cursor());
321 void LyXFunc::handleKeyFunc(kb_action action)
323 char_type c = encoded_last_key;
328 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
329 lyx_view_->view()->getIntl().getTransManager().deadkey(
330 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
331 // Need to clear, in case the minibuffer calls these
334 // copied verbatim from do_accent_char
335 view()->cursor().resetAnchor();
336 view()->processUpdateFlags(Update::FitCursor);
340 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
342 BOOST_ASSERT(lyx_view_);
343 if (!LyX::ref().session().bookmarks().isValid(idx))
345 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
346 BOOST_ASSERT(!bm.filename.empty());
347 string const file = bm.filename.absFilename();
348 // if the file is not opened, open it.
349 if (!theBufferList().exists(file)) {
351 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
355 // open may fail, so we need to test it again
356 if (!theBufferList().exists(file))
359 // if the current buffer is not that one, switch to it.
360 if (lyx_view_->buffer()->absFileName() != file) {
363 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
365 // moveToPosition try paragraph id first and then paragraph (pit, pos).
366 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
367 bm.top_id, bm.top_pos))
370 // Cursor jump succeeded!
371 Cursor const & cur = view()->cursor();
372 pit_type new_pit = cur.pit();
373 pos_type new_pos = cur.pos();
374 int new_id = cur.paragraph().id();
376 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
377 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
378 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
379 || bm.top_id != new_id) {
380 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
381 new_pit, new_pos, new_id);
386 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
388 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
390 // Do nothing if we have nothing (JMarc)
391 if (!keysym.isOK()) {
392 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
394 lyx_view_->restartCursor();
398 if (keysym.isModifier()) {
399 LYXERR(Debug::KEY) << "isModifier true" << endl;
400 lyx_view_->restartCursor();
404 //Encoding const * encoding = view()->cursor().getEncoding();
405 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
406 // FIXME: encoded_last_key shadows the member variable of the same
407 // name. Is that intended?
408 char_type encoded_last_key = keysym.getUCSEncoded();
410 // Do a one-deep top-level lookup for
411 // cancel and meta-fake keys. RVDK_PATCH_5
412 cancel_meta_seq.reset();
414 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
415 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
416 << " action first set to [" << func.action << ']'
419 // When not cancel or meta-fake, do the normal lookup.
420 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
421 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
422 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
423 // remove Caps Lock and Mod2 as a modifiers
424 func = keyseq.addkey(keysym, (state | meta_fake_bit));
425 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
426 << "action now set to ["
427 << func.action << ']' << endl;
430 // Dont remove this unless you know what you are doing.
431 meta_fake_bit = NoModifier;
433 // Can this happen now ?
434 if (func.action == LFUN_NOACTION)
435 func = FuncRequest(LFUN_COMMAND_PREFIX);
437 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
439 << func.action << "]["
440 << to_utf8(keyseq.print(KeySequence::Portable)) << ']'
443 // already here we know if it any point in going further
444 // why not return already here if action == -1 and
445 // num_bytes == 0? (Lgb)
447 if (keyseq.length() > 1)
448 lyx_view_->message(keyseq.print(KeySequence::ForGui));
451 // Maybe user can only reach the key via holding down shift.
452 // Let's see. But only if shift is the only modifier
453 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
454 LYXERR(Debug::KEY) << "Trying without shift" << endl;
455 func = keyseq.addkey(keysym, NoModifier);
456 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
459 if (func.action == LFUN_UNKNOWN_ACTION) {
460 // Hmm, we didn't match any of the keysequences. See
461 // if it's normal insertable text not already covered
463 if (keysym.isText() && keyseq.length() == 1) {
464 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
465 func = FuncRequest(LFUN_SELF_INSERT,
466 FuncRequest::KEYBOARD);
468 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
469 lyx_view_->message(_("Unknown function."));
470 lyx_view_->restartCursor();
475 if (func.action == LFUN_SELF_INSERT) {
476 if (encoded_last_key != 0) {
477 docstring const arg(1, encoded_last_key);
478 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
479 FuncRequest::KEYBOARD));
481 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
487 lyx_view_->restartCursor();
491 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
493 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
496 /* In LyX/Mac, when a dialog is open, the menus of the
497 application can still be accessed without giving focus to
498 the main window. In this case, we want to disable the menu
499 entries that are buffer-related.
501 Note that this code is not perfect, as bug 1941 attests:
502 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
504 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
505 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
508 if (cmd.action == LFUN_NOACTION) {
509 flag.message(from_utf8(N_("Nothing to do")));
514 switch (cmd.action) {
515 case LFUN_UNKNOWN_ACTION:
516 #ifndef HAVE_LIBAIKSAURUS
517 case LFUN_THESAURUS_ENTRY:
527 if (flag.unknown()) {
528 flag.message(from_utf8(N_("Unknown action")));
532 if (!flag.enabled()) {
533 if (flag.message().empty())
534 flag.message(from_utf8(N_("Command disabled")));
538 // Check whether we need a buffer
539 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
541 flag.message(from_utf8(N_("Command not allowed with"
542 "out any document open")));
547 // I would really like to avoid having this switch and rather try to
548 // encode this in the function itself.
549 // -- And I'd rather let an inset decide which LFUNs it is willing
550 // to handle (Andre')
552 switch (cmd.action) {
553 case LFUN_BUFFER_TOGGLE_READ_ONLY:
554 flag.setOnOff(buf->isReadonly());
557 case LFUN_BUFFER_SWITCH:
558 // toggle on the current buffer, but do not toggle off
559 // the other ones (is that a good idea?)
560 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
564 case LFUN_BUFFER_EXPORT:
565 enable = cmd.argument() == "custom"
566 || buf->isExportable(to_utf8(cmd.argument()));
569 case LFUN_BUFFER_CHKTEX:
570 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
573 case LFUN_BUILD_PROGRAM:
574 enable = buf->isExportable("program");
577 case LFUN_VC_REGISTER:
578 enable = !buf->lyxvc().inUse();
580 case LFUN_VC_CHECK_IN:
581 enable = buf->lyxvc().inUse() && !buf->isReadonly();
583 case LFUN_VC_CHECK_OUT:
584 enable = buf->lyxvc().inUse() && buf->isReadonly();
587 case LFUN_VC_UNDO_LAST:
588 enable = buf->lyxvc().inUse();
590 case LFUN_BUFFER_RELOAD:
591 enable = !buf->isUnnamed() && buf->fileName().exists()
592 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
595 case LFUN_INSET_APPLY: {
600 string const name = cmd.getArg(0);
601 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
603 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
605 if (!inset->getStatus(view()->cursor(), fr, fs)) {
606 // Every inset is supposed to handle this
611 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
612 flag |= getStatus(fr);
614 enable = flag.enabled();
618 case LFUN_DIALOG_TOGGLE:
619 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
620 // fall through to set "enable"
621 case LFUN_DIALOG_SHOW: {
622 string const name = cmd.getArg(0);
624 enable = name == "aboutlyx"
625 || name == "file" //FIXME: should be removed.
627 || name == "texinfo";
628 else if (name == "print")
629 enable = buf->isExportable("dvi")
630 && lyxrc.print_command != "none";
631 else if (name == "character") {
635 InsetCode ic = view()->cursor().inset().lyxCode();
636 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
639 else if (name == "latexlog")
640 enable = FileName(buf->logName()).isFileReadable();
641 else if (name == "spellchecker")
642 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
643 enable = !buf->isReadonly();
647 else if (name == "vclog")
648 enable = buf->lyxvc().inUse();
652 case LFUN_DIALOG_UPDATE: {
653 string const name = cmd.getArg(0);
655 enable = name == "prefs";
659 case LFUN_CITATION_INSERT: {
660 FuncRequest fr(LFUN_INSET_INSERT, "citation");
661 enable = getStatus(fr).enabled();
665 case LFUN_BUFFER_WRITE: {
666 enable = lyx_view_->buffer()->isUnnamed()
667 || !lyx_view_->buffer()->isClean();
672 case LFUN_BUFFER_WRITE_ALL: {
673 // We enable the command only if there are some modified buffers
674 Buffer * first = theBufferList().first();
675 bool modified = false;
679 // We cannot use a for loop as the buffer list is a cycle.
685 b = theBufferList().next(b);
686 } while (b != first);
694 case LFUN_BOOKMARK_GOTO: {
695 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
696 enable = LyX::ref().session().bookmarks().isValid(num);
700 case LFUN_BOOKMARK_CLEAR:
701 enable = LyX::ref().session().bookmarks().size() > 0;
704 case LFUN_TOOLBAR_TOGGLE: {
705 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
706 flag.setOnOff(current);
709 case LFUN_WINDOW_CLOSE: {
710 enable = (theApp()->gui().viewIds().size() > 1);
714 // this one is difficult to get right. As a half-baked
715 // solution, we consider only the first action of the sequence
716 case LFUN_COMMAND_SEQUENCE: {
717 // argument contains ';'-terminated commands
718 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
719 FuncRequest func(lyxaction.lookupFunc(firstcmd));
720 func.origin = cmd.origin;
721 flag = getStatus(func);
727 std::string name(to_utf8(cmd.argument()));
728 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
729 func.origin = cmd.origin;
730 flag = getStatus(func);
731 LyX::ref().topLevelCmdDef().release(name);
733 // catch recursion or unknown command definiton
734 // all operations until the recursion or unknown command
735 // definiton occures are performed, so set the state to enabled
741 case LFUN_BUFFER_NEW:
742 case LFUN_BUFFER_NEW_TEMPLATE:
743 case LFUN_WORD_FIND_FORWARD:
744 case LFUN_WORD_FIND_BACKWARD:
745 case LFUN_COMMAND_PREFIX:
746 case LFUN_COMMAND_EXECUTE:
748 case LFUN_META_PREFIX:
749 case LFUN_BUFFER_CLOSE:
750 case LFUN_BUFFER_WRITE_AS:
751 case LFUN_BUFFER_UPDATE:
752 case LFUN_BUFFER_VIEW:
753 case LFUN_MASTER_BUFFER_UPDATE:
754 case LFUN_MASTER_BUFFER_VIEW:
755 case LFUN_BUFFER_IMPORT:
756 case LFUN_BUFFER_AUTO_SAVE:
757 case LFUN_RECONFIGURE:
761 case LFUN_DROP_LAYOUTS_CHOICE:
763 case LFUN_SERVER_GET_NAME:
764 case LFUN_SERVER_NOTIFY:
765 case LFUN_SERVER_GOTO_FILE_ROW:
766 case LFUN_DIALOG_HIDE:
767 case LFUN_DIALOG_DISCONNECT_INSET:
768 case LFUN_BUFFER_CHILD_OPEN:
769 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
770 case LFUN_KEYMAP_OFF:
771 case LFUN_KEYMAP_PRIMARY:
772 case LFUN_KEYMAP_SECONDARY:
773 case LFUN_KEYMAP_TOGGLE:
775 case LFUN_BUFFER_EXPORT_CUSTOM:
776 case LFUN_BUFFER_PRINT:
777 case LFUN_PREFERENCES_SAVE:
778 case LFUN_SCREEN_FONT_UPDATE:
781 case LFUN_EXTERNAL_EDIT:
782 case LFUN_GRAPHICS_EDIT:
783 case LFUN_ALL_INSETS_TOGGLE:
784 case LFUN_BUFFER_LANGUAGE:
785 case LFUN_TEXTCLASS_APPLY:
786 case LFUN_TEXTCLASS_LOAD:
787 case LFUN_BUFFER_SAVE_AS_DEFAULT:
788 case LFUN_BUFFER_PARAMS_APPLY:
789 case LFUN_LAYOUT_MODULES_CLEAR:
790 case LFUN_LAYOUT_MODULE_ADD:
791 case LFUN_LAYOUT_RELOAD:
792 case LFUN_LYXRC_APPLY:
793 case LFUN_BUFFER_NEXT:
794 case LFUN_BUFFER_PREVIOUS:
795 case LFUN_WINDOW_NEW:
797 // these are handled in our dispatch()
805 if (!getLocalStatus(view()->cursor(), cmd, flag))
806 flag = view()->getStatus(cmd);
812 // Can we use a readonly buffer?
813 if (buf && buf->isReadonly()
814 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
815 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
816 flag.message(from_utf8(N_("Document is read-only")));
820 // Are we in a DELETED change-tracking region?
822 && lookupChangeType(view()->cursor(), true) == Change::DELETED
823 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
824 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
825 flag.message(from_utf8(N_("This portion of the document is deleted.")));
829 // the default error message if we disable the command
830 if (!flag.enabled() && flag.message().empty())
831 flag.message(from_utf8(N_("Command disabled")));
837 bool LyXFunc::ensureBufferClean(BufferView * bv)
839 Buffer & buf = bv->buffer();
843 docstring const file = buf.fileName().displayName(30);
844 docstring text = bformat(_("The document %1$s has unsaved "
845 "changes.\n\nDo you want to save "
846 "the document?"), file);
847 int const ret = Alert::prompt(_("Save changed document?"),
848 text, 0, 1, _("&Save"),
852 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
854 return buf.isClean();
860 void showPrintError(string const & name)
862 docstring str = bformat(_("Could not print the document %1$s.\n"
863 "Check that your printer is set up correctly."),
864 makeDisplayPath(name, 50));
865 Alert::error(_("Print document failed"), str);
869 void loadTextClass(string const & name)
871 std::pair<bool, textclass_type> const tc_pair =
872 textclasslist.numberOfClass(name);
874 if (!tc_pair.first) {
875 lyxerr << "Document class \"" << name
876 << "\" does not exist."
881 textclass_type const tc = tc_pair.second;
883 if (!textclasslist[tc].load()) {
884 docstring s = bformat(_("The document class %1$s."
885 "could not be loaded."),
886 from_utf8(textclasslist[tc].name()));
887 Alert::error(_("Could not load class"), s);
892 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
897 void LyXFunc::dispatch(FuncRequest const & cmd)
899 string const argument = to_utf8(cmd.argument());
900 kb_action const action = cmd.action;
902 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
903 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
905 // we have not done anything wrong yet.
907 dispatch_buffer.erase();
909 // redraw the screen at the end (first of the two drawing steps).
910 //This is done unless explicitely requested otherwise
911 Update::flags updateFlags = Update::FitCursor;
913 FuncStatus const flag = getStatus(cmd);
914 if (!flag.enabled()) {
915 // We cannot use this function here
916 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
917 << lyxaction.getActionName(action)
918 << " [" << action << "] is disabled at this location"
920 setErrorMessage(flag.message());
923 // Let lyx_view_ dispatch its own actions.
924 case LFUN_COMMAND_EXECUTE:
925 case LFUN_DROP_LAYOUTS_CHOICE:
927 case LFUN_TOOLBAR_TOGGLE:
928 BOOST_ASSERT(lyx_view_);
929 lyx_view_->dispatch(cmd);
932 case LFUN_WORD_FIND_FORWARD:
933 case LFUN_WORD_FIND_BACKWARD: {
934 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
935 static docstring last_search;
936 docstring searched_string;
938 if (!cmd.argument().empty()) {
939 last_search = cmd.argument();
940 searched_string = cmd.argument();
942 searched_string = last_search;
945 if (searched_string.empty())
948 bool const fw = action == LFUN_WORD_FIND_FORWARD;
949 docstring const data =
950 find2string(searched_string, true, false, fw);
951 find(view(), FuncRequest(LFUN_WORD_FIND, data));
955 case LFUN_COMMAND_PREFIX:
956 BOOST_ASSERT(lyx_view_);
957 lyx_view_->message(keyseq.printOptions(true));
961 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
963 meta_fake_bit = NoModifier;
964 if (lyx_view_->buffer())
965 // cancel any selection
966 dispatch(FuncRequest(LFUN_MARK_OFF));
967 setMessage(from_ascii(N_("Cancel")));
970 case LFUN_META_PREFIX:
971 meta_fake_bit = AltModifier;
972 setMessage(keyseq.print(KeySequence::ForGui));
975 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
976 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
977 Buffer * buf = lyx_view_->buffer();
978 if (buf->lyxvc().inUse())
979 buf->lyxvc().toggleReadOnly();
981 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
985 // --- Menus -----------------------------------------------
986 case LFUN_BUFFER_NEW:
987 menuNew(argument, false);
988 updateFlags = Update::None;
991 case LFUN_BUFFER_NEW_TEMPLATE:
992 menuNew(argument, true);
993 updateFlags = Update::None;
996 case LFUN_BUFFER_CLOSE:
998 updateFlags = Update::None;
1001 case LFUN_BUFFER_WRITE:
1002 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1003 if (!lyx_view_->buffer()->isUnnamed()) {
1004 docstring const str = bformat(_("Saving document %1$s..."),
1005 makeDisplayPath(lyx_view_->buffer()->absFileName()));
1006 lyx_view_->message(str);
1007 lyx_view_->buffer()->menuWrite();
1008 lyx_view_->message(str + _(" done."));
1010 lyx_view_->buffer()->writeAs();
1012 updateFlags = Update::None;
1015 case LFUN_BUFFER_WRITE_AS:
1016 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1017 lyx_view_->buffer()->writeAs(argument);
1018 updateFlags = Update::None;
1021 case LFUN_BUFFER_WRITE_ALL: {
1022 Buffer * first = theBufferList().first();
1025 lyx_view_->message(_("Saving all documents..."));
1027 // We cannot use a for loop as the buffer list cycles.
1029 if (!b->isClean()) {
1030 if (!b->isUnnamed()) {
1032 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1036 b = theBufferList().next(b);
1037 } while (b != first);
1038 lyx_view_->message(_("All documents saved."));
1041 updateFlags = Update::None;
1045 case LFUN_BUFFER_RELOAD: {
1046 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1047 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1048 docstring text = bformat(_("Any changes will be lost. Are you sure "
1049 "you want to revert to the saved version of the document %1$s?"), file);
1050 int const ret = Alert::prompt(_("Revert to saved document?"),
1051 text, 1, 1, _("&Revert"), _("&Cancel"));
1058 case LFUN_BUFFER_UPDATE:
1059 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1060 lyx_view_->buffer()->doExport(argument, true);
1063 case LFUN_BUFFER_VIEW:
1064 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1065 lyx_view_->buffer()->preview(argument);
1068 case LFUN_MASTER_BUFFER_UPDATE:
1069 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1070 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1073 case LFUN_MASTER_BUFFER_VIEW:
1074 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1075 lyx_view_->buffer()->masterBuffer()->preview(argument);
1078 case LFUN_BUILD_PROGRAM:
1079 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1080 lyx_view_->buffer()->doExport("program", true);
1083 case LFUN_BUFFER_CHKTEX:
1084 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1085 lyx_view_->buffer()->runChktex();
1088 case LFUN_BUFFER_EXPORT:
1089 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1090 if (argument == "custom")
1091 lyx_view_->showDialog("sendto");
1093 lyx_view_->buffer()->doExport(argument, false);
1096 case LFUN_BUFFER_EXPORT_CUSTOM: {
1097 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1099 string command = split(argument, format_name, ' ');
1100 Format const * format = formats.getFormat(format_name);
1102 lyxerr << "Format \"" << format_name
1103 << "\" not recognized!"
1108 Buffer * buffer = lyx_view_->buffer();
1110 // The name of the file created by the conversion process
1113 // Output to filename
1114 if (format->name() == "lyx") {
1115 string const latexname = buffer->latexName(false);
1116 filename = changeExtension(latexname,
1117 format->extension());
1118 filename = addName(buffer->temppath(), filename);
1120 if (!buffer->writeFile(FileName(filename)))
1124 buffer->doExport(format_name, true, filename);
1127 // Substitute $$FName for filename
1128 if (!contains(command, "$$FName"))
1129 command = "( " + command + " ) < $$FName";
1130 command = subst(command, "$$FName", filename);
1132 // Execute the command in the background
1134 call.startscript(Systemcall::DontWait, command);
1138 case LFUN_BUFFER_PRINT: {
1139 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1140 // FIXME: cmd.getArg() might fail if one of the arguments
1141 // contains double quotes
1142 string target = cmd.getArg(0);
1143 string target_name = cmd.getArg(1);
1144 string command = cmd.getArg(2);
1147 || target_name.empty()
1148 || command.empty()) {
1149 lyxerr << "Unable to parse \""
1150 << argument << '"' << endl;
1153 if (target != "printer" && target != "file") {
1154 lyxerr << "Unrecognized target \""
1155 << target << '"' << endl;
1159 Buffer * buffer = lyx_view_->buffer();
1161 if (!buffer->doExport("dvi", true)) {
1162 showPrintError(buffer->absFileName());
1166 // Push directory path.
1167 string const path = buffer->temppath();
1168 // Prevent the compiler from optimizing away p
1170 support::PathChanger p(pp);
1172 // there are three cases here:
1173 // 1. we print to a file
1174 // 2. we print directly to a printer
1175 // 3. we print using a spool command (print to file first)
1178 string const dviname =
1179 changeExtension(buffer->latexName(true), "dvi");
1181 if (target == "printer") {
1182 if (!lyxrc.print_spool_command.empty()) {
1183 // case 3: print using a spool
1184 string const psname =
1185 changeExtension(dviname,".ps");
1186 command += ' ' + lyxrc.print_to_file
1189 + quoteName(dviname);
1192 lyxrc.print_spool_command + ' ';
1193 if (target_name != "default") {
1194 command2 += lyxrc.print_spool_printerprefix
1198 command2 += quoteName(psname);
1200 // If successful, then spool command
1201 res = one.startscript(
1206 res = one.startscript(
1207 Systemcall::DontWait,
1210 // case 2: print directly to a printer
1211 if (target_name != "default")
1212 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1213 res = one.startscript(
1214 Systemcall::DontWait,
1215 command + quoteName(dviname));
1219 // case 1: print to a file
1220 FileName const filename(makeAbsPath(target_name,
1221 lyx_view_->buffer()->filePath()));
1222 FileName const dvifile(makeAbsPath(dviname, path));
1223 if (filename.exists()) {
1224 docstring text = bformat(
1225 _("The file %1$s already exists.\n\n"
1226 "Do you want to overwrite that file?"),
1227 makeDisplayPath(filename.absFilename()));
1228 if (Alert::prompt(_("Overwrite file?"),
1229 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1232 command += ' ' + lyxrc.print_to_file
1233 + quoteName(filename.toFilesystemEncoding())
1235 + quoteName(dvifile.toFilesystemEncoding());
1236 res = one.startscript(Systemcall::DontWait,
1241 showPrintError(buffer->absFileName());
1245 case LFUN_BUFFER_IMPORT:
1250 // quitting is triggered by the gui code
1251 // (leaving the event loop).
1252 lyx_view_->message(from_utf8(N_("Exiting.")));
1253 if (theBufferList().quitWriteAll())
1254 theApp()->gui().closeAllViews();
1257 case LFUN_BUFFER_AUTO_SAVE:
1258 lyx_view_->buffer()->autoSave();
1261 case LFUN_RECONFIGURE:
1262 BOOST_ASSERT(lyx_view_);
1263 // argument is any additional parameter to the configure.py command
1264 reconfigure(*lyx_view_, argument);
1267 case LFUN_HELP_OPEN: {
1268 BOOST_ASSERT(lyx_view_);
1269 string const arg = argument;
1271 setErrorMessage(from_ascii(N_("Missing argument")));
1274 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1275 if (fname.empty()) {
1276 lyxerr << "LyX: unable to find documentation file `"
1277 << arg << "'. Bad installation?" << endl;
1280 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1281 makeDisplayPath(fname.absFilename())));
1282 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1285 lyx_view_->setBuffer(buf);
1286 lyx_view_->errors("Parse");
1288 updateFlags = Update::None;
1292 // --- version control -------------------------------
1293 case LFUN_VC_REGISTER:
1294 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1295 if (!ensureBufferClean(view()))
1297 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1298 lyx_view_->buffer()->lyxvc().registrer();
1301 updateFlags = Update::Force;
1304 case LFUN_VC_CHECK_IN:
1305 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1306 if (!ensureBufferClean(view()))
1308 if (lyx_view_->buffer()->lyxvc().inUse()
1309 && !lyx_view_->buffer()->isReadonly()) {
1310 lyx_view_->buffer()->lyxvc().checkIn();
1315 case LFUN_VC_CHECK_OUT:
1316 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1317 if (!ensureBufferClean(view()))
1319 if (lyx_view_->buffer()->lyxvc().inUse()
1320 && lyx_view_->buffer()->isReadonly()) {
1321 lyx_view_->buffer()->lyxvc().checkOut();
1326 case LFUN_VC_REVERT:
1327 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1328 lyx_view_->buffer()->lyxvc().revert();
1332 case LFUN_VC_UNDO_LAST:
1333 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1334 lyx_view_->buffer()->lyxvc().undoLast();
1338 // --- buffers ----------------------------------------
1339 case LFUN_BUFFER_SWITCH:
1340 BOOST_ASSERT(lyx_view_);
1341 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1342 updateFlags = Update::None;
1345 case LFUN_BUFFER_NEXT:
1346 BOOST_ASSERT(lyx_view_);
1347 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1348 updateFlags = Update::None;
1351 case LFUN_BUFFER_PREVIOUS:
1352 BOOST_ASSERT(lyx_view_);
1353 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1354 updateFlags = Update::None;
1357 case LFUN_FILE_NEW: {
1358 BOOST_ASSERT(lyx_view_);
1360 string tmpname = split(argument, name, ':'); // Split filename
1361 Buffer * const b = newFile(name, tmpname);
1363 lyx_view_->setBuffer(b);
1364 updateFlags = Update::None;
1368 case LFUN_FILE_OPEN:
1369 BOOST_ASSERT(lyx_view_);
1371 updateFlags = Update::None;
1374 // --- lyxserver commands ----------------------------
1375 case LFUN_SERVER_GET_NAME:
1376 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1377 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1378 LYXERR(Debug::INFO) << "FNAME["
1379 << lyx_view_->buffer()->absFileName()
1383 case LFUN_SERVER_NOTIFY:
1384 dispatch_buffer = keyseq.print(KeySequence::Portable);
1385 theServer().notifyClient(to_utf8(dispatch_buffer));
1388 case LFUN_SERVER_GOTO_FILE_ROW: {
1389 BOOST_ASSERT(lyx_view_);
1392 istringstream is(argument);
1393 is >> file_name >> row;
1395 bool loaded = false;
1396 if (prefixIs(file_name, package().temp_dir().absFilename()))
1397 // Needed by inverse dvi search. If it is a file
1398 // in tmpdir, call the apropriated function
1399 buf = theBufferList().getBufferFromTmp(file_name);
1401 // Must replace extension of the file to be .lyx
1402 // and get full path
1403 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1404 // Either change buffer or load the file
1405 if (theBufferList().exists(s.absFilename()))
1406 buf = theBufferList().getBuffer(s.absFilename());
1408 buf = lyx_view_->loadLyXFile(s);
1414 updateFlags = Update::None;
1419 lyx_view_->setBuffer(buf);
1420 view()->setCursorFromRow(row);
1422 lyx_view_->errors("Parse");
1423 updateFlags = Update::FitCursor;
1427 case LFUN_DIALOG_SHOW: {
1428 BOOST_ASSERT(lyx_view_);
1429 string const name = cmd.getArg(0);
1430 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1432 if (name == "character") {
1433 data = freefont2string();
1435 lyx_view_->showDialogWithData("character", data);
1436 } else if (name == "latexlog") {
1437 Buffer::LogType type;
1438 string const logfile = lyx_view_->buffer()->logName(&type);
1440 case Buffer::latexlog:
1443 case Buffer::buildlog:
1447 data += Lexer::quoteString(logfile);
1448 lyx_view_->showDialogWithData("log", data);
1449 } else if (name == "vclog") {
1450 string const data = "vc " +
1451 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1452 lyx_view_->showDialogWithData("log", data);
1454 lyx_view_->showDialogWithData(name, data);
1458 case LFUN_DIALOG_SHOW_NEW_INSET: {
1459 BOOST_ASSERT(lyx_view_);
1460 string const name = cmd.getArg(0);
1461 InsetCode code = insetCode(name);
1462 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1463 bool insetCodeOK = true;
1472 case HYPERLINK_CODE: {
1473 InsetCommandParams p(code);
1474 data = InsetCommandMailer::params2string(name, p);
1477 case INCLUDE_CODE: {
1478 // data is the include type: one of "include",
1479 // "input", "verbatiminput" or "verbatiminput*"
1481 // default type is requested
1483 InsetCommandParams p(INCLUDE_CODE, data);
1484 data = InsetCommandMailer::params2string("include", p);
1488 // \c data == "Boxed" || "Frameless" etc
1489 InsetBoxParams p(data);
1490 data = InsetBoxMailer::params2string(p);
1494 InsetBranchParams p;
1495 data = InsetBranchMailer::params2string(p);
1499 InsetCommandParams p(CITE_CODE);
1500 data = InsetCommandMailer::params2string(name, p);
1504 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1507 case EXTERNAL_CODE: {
1508 InsetExternalParams p;
1509 Buffer const & buffer = *lyx_view_->buffer();
1510 data = InsetExternalMailer::params2string(p, buffer);
1515 data = InsetFloatMailer::params2string(p);
1518 case LISTINGS_CODE: {
1519 InsetListingsParams p;
1520 data = InsetListingsMailer::params2string(p);
1523 case GRAPHICS_CODE: {
1524 InsetGraphicsParams p;
1525 Buffer const & buffer = *lyx_view_->buffer();
1526 data = InsetGraphicsMailer::params2string(p, buffer);
1531 data = InsetNoteMailer::params2string(p);
1536 data = InsetVSpaceMailer::params2string(space);
1541 data = InsetWrapMailer::params2string(p);
1545 lyxerr << "Inset type '" << name <<
1546 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1547 insetCodeOK = false;
1549 } // end switch(code)
1551 lyx_view_->getDialogs().show(name, data, 0);
1555 case LFUN_DIALOG_UPDATE: {
1556 BOOST_ASSERT(lyx_view_);
1557 string const & name = argument;
1558 // Can only update a dialog connected to an existing inset
1559 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1561 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1562 inset->dispatch(view()->cursor(), fr);
1563 } else if (name == "paragraph") {
1564 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1565 } else if (name == "prefs") {
1566 lyx_view_->updateDialog(name, string());
1571 case LFUN_DIALOG_HIDE:
1572 LyX::cref().hideDialogs(argument, 0);
1575 case LFUN_DIALOG_TOGGLE: {
1576 BOOST_ASSERT(lyx_view_);
1577 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1578 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1580 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1584 case LFUN_DIALOG_DISCONNECT_INSET:
1585 BOOST_ASSERT(lyx_view_);
1586 lyx_view_->getDialogs().disconnect(argument);
1590 case LFUN_CITATION_INSERT: {
1591 BOOST_ASSERT(lyx_view_);
1592 if (!argument.empty()) {
1593 // we can have one optional argument, delimited by '|'
1594 // citation-insert <key>|<text_before>
1595 // this should be enhanced to also support text_after
1596 // and citation style
1597 string arg = argument;
1599 if (contains(argument, "|")) {
1600 arg = token(argument, '|', 0);
1601 opt1 = token(argument, '|', 1);
1603 InsetCommandParams icp(CITE_CODE);
1604 icp["key"] = from_utf8(arg);
1606 icp["before"] = from_utf8(opt1);
1607 string icstr = InsetCommandMailer::params2string("citation", icp);
1608 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1611 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1615 case LFUN_BUFFER_CHILD_OPEN: {
1616 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1617 Buffer * parent = lyx_view_->buffer();
1618 FileName filename = makeAbsPath(argument, parent->filePath());
1619 view()->saveBookmark(false);
1621 bool parsed = false;
1622 if (theBufferList().exists(filename.absFilename())) {
1623 child = theBufferList().getBuffer(filename.absFilename());
1625 setMessage(bformat(_("Opening child document %1$s..."),
1626 makeDisplayPath(filename.absFilename())));
1627 child = lyx_view_->loadLyXFile(filename, true);
1631 // Set the parent name of the child document.
1632 // This makes insertion of citations and references in the child work,
1633 // when the target is in the parent or another child document.
1634 child->setParentName(parent->absFileName());
1635 updateLabels(*child->masterBuffer());
1636 lyx_view_->setBuffer(child);
1638 lyx_view_->errors("Parse");
1641 // If a screen update is required (in case where auto_open is false),
1642 // setBuffer() would have taken care of it already. Otherwise we shall
1643 // reset the update flag because it can cause a circular problem.
1645 updateFlags = Update::None;
1649 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1650 BOOST_ASSERT(lyx_view_);
1651 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1654 case LFUN_KEYMAP_OFF:
1655 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1656 lyx_view_->view()->getIntl().keyMapOn(false);
1659 case LFUN_KEYMAP_PRIMARY:
1660 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1661 lyx_view_->view()->getIntl().keyMapPrim();
1664 case LFUN_KEYMAP_SECONDARY:
1665 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1666 lyx_view_->view()->getIntl().keyMapSec();
1669 case LFUN_KEYMAP_TOGGLE:
1670 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1671 lyx_view_->view()->getIntl().toggleKeyMap();
1677 string rest = split(argument, countstr, ' ');
1678 istringstream is(countstr);
1681 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1682 for (int i = 0; i < count; ++i)
1683 dispatch(lyxaction.lookupFunc(rest));
1687 case LFUN_COMMAND_SEQUENCE: {
1688 // argument contains ';'-terminated commands
1689 string arg = argument;
1690 while (!arg.empty()) {
1692 arg = split(arg, first, ';');
1693 FuncRequest func(lyxaction.lookupFunc(first));
1694 func.origin = cmd.origin;
1702 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1703 func.origin = cmd.origin;
1705 LyX::ref().topLevelCmdDef().release(argument);
1707 if (func.action == LFUN_UNKNOWN_ACTION) {
1708 // unknown command definition
1709 lyxerr << "Warning: unknown command definition `"
1713 // recursion detected
1714 lyxerr << "Warning: Recursion in the command definition `"
1715 << argument << "' detected"
1722 case LFUN_PREFERENCES_SAVE: {
1723 lyxrc.write(makeAbsPath("preferences",
1724 package().user_support().absFilename()),
1729 case LFUN_SCREEN_FONT_UPDATE:
1730 BOOST_ASSERT(lyx_view_);
1731 // handle the screen font changes.
1732 theFontLoader().update();
1733 /// FIXME: only the current view will be updated. the Gui
1734 /// class is able to furnish the list of views.
1735 updateFlags = Update::Force;
1738 case LFUN_SET_COLOR: {
1740 string const x11_name = split(argument, lyx_name, ' ');
1741 if (lyx_name.empty() || x11_name.empty()) {
1742 setErrorMessage(from_ascii(N_(
1743 "Syntax: set-color <lyx_name>"
1748 bool const graphicsbg_changed =
1749 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1750 x11_name != lcolor.getX11Name(Color_graphicsbg));
1752 if (!lcolor.setColor(lyx_name, x11_name)) {
1754 bformat(_("Set-color \"%1$s\" failed "
1755 "- color is undefined or "
1756 "may not be redefined"),
1757 from_utf8(lyx_name)));
1761 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1763 if (graphicsbg_changed) {
1764 // FIXME: The graphics cache no longer has a changeDisplay method.
1766 graphics::GCache::get().changeDisplay(true);
1773 BOOST_ASSERT(lyx_view_);
1774 lyx_view_->message(from_utf8(argument));
1777 case LFUN_EXTERNAL_EDIT: {
1778 BOOST_ASSERT(lyx_view_);
1779 FuncRequest fr(action, argument);
1780 InsetExternal().dispatch(view()->cursor(), fr);
1784 case LFUN_GRAPHICS_EDIT: {
1785 FuncRequest fr(action, argument);
1786 InsetGraphics().dispatch(view()->cursor(), fr);
1790 case LFUN_INSET_APPLY: {
1791 BOOST_ASSERT(lyx_view_);
1792 string const name = cmd.getArg(0);
1793 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1795 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1796 inset->dispatch(view()->cursor(), fr);
1798 FuncRequest fr(LFUN_INSET_INSERT, argument);
1801 // ideally, the update flag should be set by the insets,
1802 // but this is not possible currently
1803 updateFlags = Update::Force | Update::FitCursor;
1807 case LFUN_ALL_INSETS_TOGGLE: {
1808 BOOST_ASSERT(lyx_view_);
1810 string const name = split(argument, action, ' ');
1811 InsetCode const inset_code = insetCode(name);
1813 Cursor & cur = view()->cursor();
1814 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1816 Inset & inset = lyx_view_->buffer()->inset();
1817 InsetIterator it = inset_iterator_begin(inset);
1818 InsetIterator const end = inset_iterator_end(inset);
1819 for (; it != end; ++it) {
1820 if (!it->asInsetMath()
1821 && (inset_code == NO_CODE
1822 || inset_code == it->lyxCode())) {
1823 Cursor tmpcur = cur;
1824 tmpcur.pushBackward(*it);
1825 it->dispatch(tmpcur, fr);
1828 updateFlags = Update::Force | Update::FitCursor;
1832 case LFUN_BUFFER_LANGUAGE: {
1833 BOOST_ASSERT(lyx_view_);
1834 Buffer & buffer = *lyx_view_->buffer();
1835 Language const * oldL = buffer.params().language;
1836 Language const * newL = languages.getLanguage(argument);
1837 if (!newL || oldL == newL)
1840 if (oldL->rightToLeft() == newL->rightToLeft()
1841 && !buffer.isMultiLingual())
1842 buffer.changeLanguage(oldL, newL);
1846 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1847 string const fname =
1848 addName(addPath(package().user_support().absFilename(), "templates/"),
1850 Buffer defaults(fname);
1852 istringstream ss(argument);
1855 int const unknown_tokens = defaults.readHeader(lex);
1857 if (unknown_tokens != 0) {
1858 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1859 << unknown_tokens << " unknown token"
1860 << (unknown_tokens == 1 ? "" : "s")
1864 if (defaults.writeFile(FileName(defaults.absFileName())))
1865 setMessage(bformat(_("Document defaults saved in %1$s"),
1866 makeDisplayPath(fname)));
1868 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1872 case LFUN_BUFFER_PARAMS_APPLY: {
1873 BOOST_ASSERT(lyx_view_);
1874 biblio::CiteEngine const oldEngine =
1875 lyx_view_->buffer()->params().getEngine();
1877 Buffer * buffer = lyx_view_->buffer();
1879 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1881 Cursor & cur = view()->cursor();
1882 cur.recordUndoFullDocument();
1884 istringstream ss(argument);
1887 int const unknown_tokens = buffer->readHeader(lex);
1889 if (unknown_tokens != 0) {
1890 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1891 << unknown_tokens << " unknown token"
1892 << (unknown_tokens == 1 ? "" : "s")
1896 updateLayout(oldClass, buffer);
1898 biblio::CiteEngine const newEngine =
1899 lyx_view_->buffer()->params().getEngine();
1901 if (oldEngine != newEngine) {
1902 FuncRequest fr(LFUN_INSET_REFRESH);
1904 Inset & inset = lyx_view_->buffer()->inset();
1905 InsetIterator it = inset_iterator_begin(inset);
1906 InsetIterator const end = inset_iterator_end(inset);
1907 for (; it != end; ++it)
1908 if (it->lyxCode() == CITE_CODE)
1909 it->dispatch(cur, fr);
1912 updateFlags = Update::Force | Update::FitCursor;
1916 case LFUN_LAYOUT_MODULES_CLEAR: {
1917 BOOST_ASSERT(lyx_view_);
1918 Buffer * buffer = lyx_view_->buffer();
1919 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1920 view()->cursor().recordUndoFullDocument();
1921 buffer->params().clearLayoutModules();
1922 updateLayout(oldClass, buffer);
1923 updateFlags = Update::Force | Update::FitCursor;
1927 case LFUN_LAYOUT_MODULE_ADD: {
1928 BOOST_ASSERT(lyx_view_);
1929 Buffer * buffer = lyx_view_->buffer();
1930 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1931 view()->cursor().recordUndoFullDocument();
1932 buffer->params().addLayoutModule(argument);
1933 updateLayout(oldClass, buffer);
1934 updateFlags = Update::Force | Update::FitCursor;
1938 case LFUN_TEXTCLASS_APPLY: {
1939 BOOST_ASSERT(lyx_view_);
1940 Buffer * buffer = lyx_view_->buffer();
1942 loadTextClass(argument);
1944 std::pair<bool, textclass_type> const tc_pair =
1945 textclasslist.numberOfClass(argument);
1950 textclass_type const old_class = buffer->params().getBaseClass();
1951 textclass_type const new_class = tc_pair.second;
1953 if (old_class == new_class)
1957 //Save the old, possibly modular, layout for use in conversion.
1958 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1959 view()->cursor().recordUndoFullDocument();
1960 buffer->params().setBaseClass(new_class);
1961 updateLayout(oldClass, buffer);
1962 updateFlags = Update::Force | Update::FitCursor;
1966 case LFUN_LAYOUT_RELOAD: {
1967 BOOST_ASSERT(lyx_view_);
1968 Buffer * buffer = lyx_view_->buffer();
1969 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1970 textclass_type const tc = buffer->params().getBaseClass();
1971 textclasslist.reset(tc);
1972 buffer->params().setBaseClass(tc);
1973 updateLayout(oldClass, buffer);
1974 updateFlags = Update::Force | Update::FitCursor;
1978 case LFUN_TEXTCLASS_LOAD:
1979 loadTextClass(argument);
1982 case LFUN_LYXRC_APPLY: {
1983 LyXRC const lyxrc_orig = lyxrc;
1985 istringstream ss(argument);
1986 bool const success = lyxrc.read(ss) == 0;
1989 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1990 << "Unable to read lyxrc data"
1995 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1997 if (lyx_view_ && lyx_view_->buffer())
1998 lyx_view_->updateLayoutChoice(true);
2000 /// We force the redraw in any case because there might be
2001 /// some screen font changes.
2002 /// FIXME: only the current view will be updated. the Gui
2003 /// class is able to furnish the list of views.
2004 updateFlags = Update::Force;
2008 case LFUN_WINDOW_NEW:
2009 LyX::ref().newLyXView();
2012 case LFUN_WINDOW_CLOSE:
2013 BOOST_ASSERT(lyx_view_);
2014 BOOST_ASSERT(theApp());
2015 // update bookmark pit of the current buffer before window close
2016 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2017 gotoBookmark(i+1, false, false);
2018 // ask the user for saving changes or cancel quit
2019 if (!theBufferList().quitWriteAll())
2024 case LFUN_BOOKMARK_GOTO:
2025 // go to bookmark, open unopened file and switch to buffer if necessary
2026 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2029 case LFUN_BOOKMARK_CLEAR:
2030 LyX::ref().session().bookmarks().clear();
2034 BOOST_ASSERT(lyx_view_);
2035 view()->cursor().dispatch(cmd);
2036 updateFlags = view()->cursor().result().update();
2037 if (!view()->cursor().result().dispatched())
2038 updateFlags = view()->dispatch(cmd);
2043 if (lyx_view_ && lyx_view_->buffer()) {
2044 // BufferView::update() updates the ViewMetricsInfo and
2045 // also initializes the position cache for all insets in
2046 // (at least partially) visible top-level paragraphs.
2047 // We will redraw the screen only if needed.
2048 view()->processUpdateFlags(updateFlags);
2049 lyx_view_->updateStatusBar();
2051 // if we executed a mutating lfun, mark the buffer as dirty
2053 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2054 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2055 lyx_view_->buffer()->markDirty();
2057 //Do we have a selection?
2058 theSelection().haveSelection(view()->cursor().selection());
2060 if (view()->cursor().inTexted()) {
2061 lyx_view_->updateLayoutChoice(false);
2065 if (!quitting && lyx_view_) {
2066 lyx_view_->updateToolbars();
2067 // Some messages may already be translated, so we cannot use _()
2068 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2073 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2075 const bool verbose = (cmd.origin == FuncRequest::MENU
2076 || cmd.origin == FuncRequest::TOOLBAR
2077 || cmd.origin == FuncRequest::COMMANDBUFFER);
2079 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2080 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2082 lyx_view_->message(msg);
2086 docstring dispatch_msg = msg;
2087 if (!dispatch_msg.empty())
2088 dispatch_msg += ' ';
2090 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2092 bool argsadded = false;
2094 if (!cmd.argument().empty()) {
2095 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2096 comname += ' ' + cmd.argument();
2101 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2103 if (!shortcuts.empty())
2104 comname += ": " + shortcuts;
2105 else if (!argsadded && !cmd.argument().empty())
2106 comname += ' ' + cmd.argument();
2108 if (!comname.empty()) {
2109 comname = rtrim(comname);
2110 dispatch_msg += '(' + rtrim(comname) + ')';
2113 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2114 << to_utf8(dispatch_msg) << endl;
2115 if (!dispatch_msg.empty())
2116 lyx_view_->message(dispatch_msg);
2120 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2122 // FIXME: initpath is not used. What to do?
2123 string initpath = lyxrc.document_path;
2124 string filename(name);
2126 if (lyx_view_->buffer()) {
2127 string const trypath = lyx_view_->buffer()->filePath();
2128 // If directory is writeable, use this as default.
2129 if (FileName(trypath).isDirWritable())
2133 static int newfile_number;
2135 if (filename.empty()) {
2136 filename = addName(lyxrc.document_path,
2137 "newfile" + convert<string>(++newfile_number) + ".lyx");
2138 while (theBufferList().exists(filename) ||
2139 FileName(filename).isReadable()) {
2141 filename = addName(lyxrc.document_path,
2142 "newfile" + convert<string>(newfile_number) +
2147 // The template stuff
2150 FileDialog dlg(_("Select template file"));
2151 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2152 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2154 FileDialog::Result result =
2155 dlg.open(from_utf8(lyxrc.template_path),
2156 FileFilterList(_("LyX Documents (*.lyx)")),
2159 if (result.first == FileDialog::Later)
2161 if (result.second.empty())
2163 templname = to_utf8(result.second);
2166 Buffer * const b = newFile(filename, templname, !name.empty());
2168 lyx_view_->setBuffer(b);
2172 void LyXFunc::open(string const & fname)
2174 string initpath = lyxrc.document_path;
2176 if (lyx_view_->buffer()) {
2177 string const trypath = lyx_view_->buffer()->filePath();
2178 // If directory is writeable, use this as default.
2179 if (FileName(trypath).isDirWritable())
2185 if (fname.empty()) {
2186 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2187 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2188 dlg.setButton2(_("Examples|#E#e"),
2189 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2191 FileDialog::Result result =
2192 dlg.open(from_utf8(initpath),
2193 FileFilterList(_("LyX Documents (*.lyx)")),
2196 if (result.first == FileDialog::Later)
2199 filename = to_utf8(result.second);
2201 // check selected filename
2202 if (filename.empty()) {
2203 lyx_view_->message(_("Canceled."));
2209 // get absolute path of file and add ".lyx" to the filename if
2211 FileName const fullname = fileSearch(string(), filename, "lyx");
2212 if (!fullname.empty())
2213 filename = fullname.absFilename();
2215 // if the file doesn't exist, let the user create one
2216 if (!fullname.exists()) {
2217 // the user specifically chose this name. Believe him.
2218 Buffer * const b = newFile(filename, string(), true);
2220 lyx_view_->setBuffer(b);
2224 docstring const disp_fn = makeDisplayPath(filename);
2225 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2228 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2231 lyx_view_->setBuffer(buf);
2232 lyx_view_->errors("Parse");
2233 str2 = bformat(_("Document %1$s opened."), disp_fn);
2235 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2237 lyx_view_->message(str2);
2241 void LyXFunc::doImport(string const & argument)
2244 string filename = split(argument, format, ' ');
2246 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2247 << " file: " << filename << endl;
2249 // need user interaction
2250 if (filename.empty()) {
2251 string initpath = lyxrc.document_path;
2253 if (lyx_view_->buffer()) {
2254 string const trypath = lyx_view_->buffer()->filePath();
2255 // If directory is writeable, use this as default.
2256 if (FileName(trypath).isDirWritable())
2260 docstring const text = bformat(_("Select %1$s file to import"),
2261 formats.prettyName(format));
2263 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2264 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2265 dlg.setButton2(_("Examples|#E#e"),
2266 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2268 docstring filter = formats.prettyName(format);
2271 filter += from_utf8(formats.extension(format));
2274 FileDialog::Result result =
2275 dlg.open(from_utf8(initpath),
2276 FileFilterList(filter),
2279 if (result.first == FileDialog::Later)
2282 filename = to_utf8(result.second);
2284 // check selected filename
2285 if (filename.empty())
2286 lyx_view_->message(_("Canceled."));
2289 if (filename.empty())
2292 // get absolute path of file
2293 FileName const fullname(makeAbsPath(filename));
2295 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2297 // Check if the document already is open
2298 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2299 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2300 lyx_view_->message(_("Canceled."));
2305 // if the file exists already, and we didn't do
2306 // -i lyx thefile.lyx, warn
2307 if (lyxfile.exists() && fullname != lyxfile) {
2308 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2310 docstring text = bformat(_("The document %1$s already exists.\n\n"
2311 "Do you want to overwrite that document?"), file);
2312 int const ret = Alert::prompt(_("Overwrite document?"),
2313 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2316 lyx_view_->message(_("Canceled."));
2321 ErrorList errorList;
2322 import(lyx_view_, fullname, format, errorList);
2323 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2327 void LyXFunc::closeBuffer()
2329 // goto bookmark to update bookmark pit.
2330 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2331 gotoBookmark(i+1, false, false);
2333 theBufferList().close(lyx_view_->buffer(), true);
2337 void LyXFunc::reloadBuffer()
2339 FileName filename(lyx_view_->buffer()->absFileName());
2340 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2343 Buffer * buf = lyx_view_->loadLyXFile(filename);
2346 lyx_view_->setBuffer(buf);
2347 lyx_view_->errors("Parse");
2348 str = bformat(_("Document %1$s reloaded."), disp_fn);
2350 str = bformat(_("Could not reload document %1$s"), disp_fn);
2352 lyx_view_->message(str);
2355 // Each "lyx_view_" should have it's own message method. lyxview and
2356 // the minibuffer would use the minibuffer, but lyxserver would
2357 // send an ERROR signal to its client. Alejandro 970603
2358 // This function is bit problematic when it comes to NLS, to make the
2359 // lyx servers client be language indepenent we must not translate
2360 // strings sent to this func.
2361 void LyXFunc::setErrorMessage(docstring const & m) const
2363 dispatch_buffer = m;
2368 void LyXFunc::setMessage(docstring const & m) const
2370 dispatch_buffer = m;
2374 docstring const LyXFunc::viewStatusMessage()
2376 // When meta-fake key is pressed, show the key sequence so far + "M-".
2378 return keyseq.print(KeySequence::ForGui) + "M-";
2380 // Else, when a non-complete key sequence is pressed,
2381 // show the available options.
2382 if (keyseq.length() > 0 && !keyseq.deleted())
2383 return keyseq.printOptions(true);
2385 BOOST_ASSERT(lyx_view_);
2386 if (!lyx_view_->buffer())
2387 return _("Welcome to LyX!");
2389 return view()->cursor().currentState();
2393 BufferView * LyXFunc::view() const
2395 BOOST_ASSERT(lyx_view_);
2396 return lyx_view_->view();
2400 bool LyXFunc::wasMetaKey() const
2402 return (meta_fake_bit != NoModifier);
2406 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2409 lyx_view_->message(_("Converting document to new document class..."));
2411 StableDocIterator backcur(view()->cursor());
2412 ErrorList & el = buffer->errorList("Class Switch");
2413 cap::switchBetweenClasses(
2414 oldlayout, buffer->params().getTextClassPtr(),
2415 static_cast<InsetText &>(buffer->inset()), el);
2417 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2419 buffer->errors("Class Switch");
2420 updateLabels(*buffer);
2426 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2428 // Why the switch you might ask. It is a trick to ensure that all
2429 // the elements in the LyXRCTags enum is handled. As you can see
2430 // there are no breaks at all. So it is just a huge fall-through.
2431 // The nice thing is that we will get a warning from the compiler
2432 // if we forget an element.
2433 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2435 case LyXRC::RC_ACCEPT_COMPOUND:
2436 case LyXRC::RC_ALT_LANG:
2437 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2438 case LyXRC::RC_PLAINTEXT_LINELEN:
2439 case LyXRC::RC_AUTOREGIONDELETE:
2440 case LyXRC::RC_AUTORESET_OPTIONS:
2441 case LyXRC::RC_AUTOSAVE:
2442 case LyXRC::RC_AUTO_NUMBER:
2443 case LyXRC::RC_BACKUPDIR_PATH:
2444 case LyXRC::RC_BIBTEX_COMMAND:
2445 case LyXRC::RC_BINDFILE:
2446 case LyXRC::RC_CHECKLASTFILES:
2447 case LyXRC::RC_USELASTFILEPOS:
2448 case LyXRC::RC_LOADSESSION:
2449 case LyXRC::RC_CHKTEX_COMMAND:
2450 case LyXRC::RC_CONVERTER:
2451 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2452 case LyXRC::RC_COPIER:
2453 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2454 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2455 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2456 case LyXRC::RC_DATE_INSERT_FORMAT:
2457 case LyXRC::RC_DEFAULT_LANGUAGE:
2458 case LyXRC::RC_DEFAULT_PAPERSIZE:
2459 case LyXRC::RC_DEFFILE:
2460 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2461 case LyXRC::RC_DISPLAY_GRAPHICS:
2462 case LyXRC::RC_DOCUMENTPATH:
2463 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2464 FileName path(lyxrc_new.document_path);
2465 if (path.exists() && path.isDirectory())
2466 support::package().document_dir() = FileName(lyxrc.document_path);
2468 case LyXRC::RC_ESC_CHARS:
2469 case LyXRC::RC_FONT_ENCODING:
2470 case LyXRC::RC_FORMAT:
2471 case LyXRC::RC_INDEX_COMMAND:
2472 case LyXRC::RC_INPUT:
2473 case LyXRC::RC_KBMAP:
2474 case LyXRC::RC_KBMAP_PRIMARY:
2475 case LyXRC::RC_KBMAP_SECONDARY:
2476 case LyXRC::RC_LABEL_INIT_LENGTH:
2477 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2478 case LyXRC::RC_LANGUAGE_AUTO_END:
2479 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2480 case LyXRC::RC_LANGUAGE_COMMAND_END:
2481 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2482 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2483 case LyXRC::RC_LANGUAGE_PACKAGE:
2484 case LyXRC::RC_LANGUAGE_USE_BABEL:
2485 case LyXRC::RC_MAKE_BACKUP:
2486 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2487 case LyXRC::RC_NUMLASTFILES:
2488 case LyXRC::RC_PATH_PREFIX:
2489 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2490 support::prependEnvPath("PATH", lyxrc.path_prefix);
2492 case LyXRC::RC_PERS_DICT:
2493 case LyXRC::RC_PREVIEW:
2494 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2495 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2496 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2497 case LyXRC::RC_PRINTCOPIESFLAG:
2498 case LyXRC::RC_PRINTER:
2499 case LyXRC::RC_PRINTEVENPAGEFLAG:
2500 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2501 case LyXRC::RC_PRINTFILEEXTENSION:
2502 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2503 case LyXRC::RC_PRINTODDPAGEFLAG:
2504 case LyXRC::RC_PRINTPAGERANGEFLAG:
2505 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2506 case LyXRC::RC_PRINTPAPERFLAG:
2507 case LyXRC::RC_PRINTREVERSEFLAG:
2508 case LyXRC::RC_PRINTSPOOL_COMMAND:
2509 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2510 case LyXRC::RC_PRINTTOFILE:
2511 case LyXRC::RC_PRINTTOPRINTER:
2512 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2513 case LyXRC::RC_PRINT_COMMAND:
2514 case LyXRC::RC_RTL_SUPPORT:
2515 case LyXRC::RC_SCREEN_DPI:
2516 case LyXRC::RC_SCREEN_FONT_ROMAN:
2517 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2518 case LyXRC::RC_SCREEN_FONT_SANS:
2519 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2520 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2521 case LyXRC::RC_SCREEN_FONT_SIZES:
2522 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2523 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2524 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2525 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2526 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2527 case LyXRC::RC_SCREEN_ZOOM:
2528 case LyXRC::RC_SERVERPIPE:
2529 case LyXRC::RC_SET_COLOR:
2530 case LyXRC::RC_SHOW_BANNER:
2531 case LyXRC::RC_SPELL_COMMAND:
2532 case LyXRC::RC_TEMPDIRPATH:
2533 case LyXRC::RC_TEMPLATEPATH:
2534 case LyXRC::RC_TEX_ALLOWS_SPACES:
2535 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2536 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2537 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2539 case LyXRC::RC_UIFILE:
2540 case LyXRC::RC_USER_EMAIL:
2541 case LyXRC::RC_USER_NAME:
2542 case LyXRC::RC_USETEMPDIR:
2543 case LyXRC::RC_USE_ALT_LANG:
2544 case LyXRC::RC_USE_CONVERTER_CACHE:
2545 case LyXRC::RC_USE_ESC_CHARS:
2546 case LyXRC::RC_USE_INP_ENC:
2547 case LyXRC::RC_USE_PERS_DICT:
2548 case LyXRC::RC_USE_PIXMAP_CACHE:
2549 case LyXRC::RC_USE_SPELL_LIB:
2550 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2551 case LyXRC::RC_SORT_LAYOUTS:
2552 case LyXRC::RC_VIEWER:
2553 case LyXRC::RC_LAST: