3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
33 #include "Converter.h"
35 #include "CutAndPaste.h"
37 #include "DispatchResult.h"
39 #include "ErrorList.h"
41 #include "FuncRequest.h"
42 #include "FuncStatus.h"
44 #include "InsetIterator.h"
49 #include "LyXAction.h"
54 #include "Paragraph.h"
55 #include "ParagraphParameters.h"
56 #include "ParIterator.h"
60 #include "TextClassList.h"
61 #include "ToolbarBackend.h"
63 #include "insets/InsetBox.h"
64 #include "insets/InsetBranch.h"
65 #include "insets/InsetCommand.h"
66 #include "insets/InsetERT.h"
67 #include "insets/InsetExternal.h"
68 #include "insets/InsetFloat.h"
69 #include "insets/InsetListings.h"
70 #include "insets/InsetGraphics.h"
71 #include "insets/InsetInclude.h"
72 #include "insets/InsetNote.h"
73 #include "insets/InsetTabular.h"
74 #include "insets/InsetVSpace.h"
75 #include "insets/InsetWrap.h"
77 #include "frontends/alert.h"
78 #include "frontends/Application.h"
79 #include "frontends/FileDialog.h"
80 #include "frontends/FontLoader.h"
81 #include "frontends/KeySymbol.h"
82 #include "frontends/LyXView.h"
83 #include "frontends/Selection.h"
85 #include "support/environment.h"
86 #include "support/FileFilterList.h"
87 #include "support/FileName.h"
88 #include "support/filetools.h"
89 #include "support/lstrings.h"
90 #include "support/Path.h"
91 #include "support/Package.h"
92 #include "support/Systemcall.h"
93 #include "support/convert.h"
94 #include "support/os.h"
96 #include <boost/current_function.hpp>
101 using std::make_pair;
104 using std::istringstream;
105 using std::ostringstream;
111 using frontend::LyXView;
113 using support::absolutePath;
114 using support::addName;
115 using support::addPath;
116 using support::bformat;
117 using support::changeExtension;
118 using support::contains;
119 using support::FileFilterList;
120 using support::FileName;
121 using support::fileSearch;
122 using support::i18nLibFileSearch;
123 using support::makeDisplayPath;
124 using support::makeAbsPath;
125 using support::package;
126 using support::quoteName;
127 using support::rtrim;
128 using support::split;
129 using support::subst;
130 using support::Systemcall;
131 using support::token;
133 using support::prefixIs;
136 namespace Alert = frontend::Alert;
138 extern bool quitting;
144 bool import(LyXView * lv, FileName const & filename,
145 string const & format, ErrorList & errorList)
147 docstring const displaypath = makeDisplayPath(filename.absFilename());
148 lv->message(bformat(_("Importing %1$s..."), displaypath));
150 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
152 string loader_format;
153 vector<string> loaders = theConverters().loaders();
154 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
155 for (vector<string>::const_iterator it = loaders.begin();
156 it != loaders.end(); ++it) {
157 if (theConverters().isReachable(format, *it)) {
158 string const tofile =
159 changeExtension(filename.absFilename(),
160 formats.extension(*it));
161 if (!theConverters().convert(0, filename, FileName(tofile),
162 filename, format, *it, errorList))
168 if (loader_format.empty()) {
169 frontend::Alert::error(_("Couldn't import file"),
170 bformat(_("No information for importing the format %1$s."),
171 formats.prettyName(format)));
175 loader_format = format;
179 if (loader_format == "lyx") {
180 Buffer * buf = theLyXFunc().loadAndViewFile(lyxfile);
183 lv->message(_("file not imported!"));
190 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
195 bool as_paragraphs = loader_format == "textparagraph";
196 string filename2 = (loader_format == format) ? filename.absFilename()
197 : changeExtension(filename.absFilename(),
198 formats.extension(loader_format));
199 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
200 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
204 lv->message(_("imported."));
210 // This function runs "configure" and then rereads lyx.defaults to
211 // reconfigure the automatic settings.
212 void reconfigure(LyXView & lv, string const & option)
214 // emit message signal.
215 lv.message(_("Running configure..."));
217 // Run configure in user lyx directory
218 support::PathChanger p(package().user_support());
219 string configure_command = package().configure_command();
220 configure_command += option;
222 int ret = one.startscript(Systemcall::Wait, configure_command);
224 // emit message signal.
225 lv.message(_("Reloading configuration..."));
226 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
227 // Re-read packages.lst
228 LaTeXFeatures::getAvailable();
231 Alert::information(_("System reconfiguration failed"),
232 _("The system reconfiguration has failed.\n"
233 "Default textclass is used but LyX may "
234 "not be able to work properly.\n"
235 "Please reconfigure again if needed."));
238 Alert::information(_("System reconfigured"),
239 _("The system has been reconfigured.\n"
240 "You need to restart LyX to make use of any\n"
241 "updated document class specifications."));
245 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
247 // Try to fix cursor in case it is broken.
248 cursor.fixIfBroken();
250 // This is, of course, a mess. Better create a new doc iterator and use
251 // this in Inset::getStatus. This might require an additional
252 // BufferView * arg, though (which should be avoided)
253 //Cursor safe = *this;
255 for ( ; cursor.depth(); cursor.pop()) {
256 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
257 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
258 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
259 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
261 // The inset's getStatus() will return 'true' if it made
262 // a definitive decision on whether it want to handle the
263 // request or not. The result of this decision is put into
264 // the 'status' parameter.
265 if (cursor.inset().getStatus(cursor, cmd, status)) {
274 /** Return the change status at cursor position, taking in account the
275 * status at each level of the document iterator (a table in a deleted
276 * footnote is deleted).
277 * When \param outer is true, the top slice is not looked at.
279 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
281 size_t const depth = dit.depth() - (outer ? 1 : 0);
283 for (size_t i = 0 ; i < depth ; ++i) {
284 CursorSlice const & slice = dit[i];
285 if (!slice.inset().inMathed()
286 && slice.pos() < slice.paragraph().size()) {
287 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
288 if (ch != Change::UNCHANGED)
292 return Change::UNCHANGED;
299 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
304 void LyXFunc::initKeySequences(KeyMap * kb)
306 keyseq = KeySequence(kb, kb);
307 cancel_meta_seq = KeySequence(kb, kb);
311 void LyXFunc::setLyXView(LyXView * lv)
313 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
314 // save current selection to the selection buffer to allow
315 // middle-button paste in another window
316 cap::saveSelection(lyx_view_->view()->cursor());
321 void LyXFunc::handleKeyFunc(kb_action action)
323 char_type c = encoded_last_key;
328 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
329 lyx_view_->view()->getIntl().getTransManager().deadkey(
330 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
331 // Need to clear, in case the minibuffer calls these
334 // copied verbatim from do_accent_char
335 view()->cursor().resetAnchor();
336 view()->processUpdateFlags(Update::FitCursor);
340 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
342 BOOST_ASSERT(lyx_view_);
343 if (!LyX::ref().session().bookmarks().isValid(idx))
345 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
346 BOOST_ASSERT(!bm.filename.empty());
347 string const file = bm.filename.absFilename();
348 // if the file is not opened, open it.
349 if (!theBufferList().exists(file)) {
351 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
355 // open may fail, so we need to test it again
356 if (!theBufferList().exists(file))
359 // if the current buffer is not that one, switch to it.
360 if (lyx_view_->buffer()->absFileName() != file) {
363 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
365 // moveToPosition try paragraph id first and then paragraph (pit, pos).
366 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
367 bm.top_id, bm.top_pos))
370 // Cursor jump succeeded!
371 Cursor const & cur = view()->cursor();
372 pit_type new_pit = cur.pit();
373 pos_type new_pos = cur.pos();
374 int new_id = cur.paragraph().id();
376 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
377 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
378 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
379 || bm.top_id != new_id) {
380 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
381 new_pit, new_pos, new_id);
386 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
388 LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
390 // Do nothing if we have nothing (JMarc)
391 if (!keysym.isOK()) {
392 LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
393 lyx_view_->restartCursor();
397 if (keysym.isModifier()) {
398 LYXERR(Debug::KEY, "isModifier true");
399 lyx_view_->restartCursor();
403 //Encoding const * encoding = view()->cursor().getEncoding();
404 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
405 // FIXME: encoded_last_key shadows the member variable of the same
406 // name. Is that intended?
407 char_type encoded_last_key = keysym.getUCSEncoded();
409 // Do a one-deep top-level lookup for
410 // cancel and meta-fake keys. RVDK_PATCH_5
411 cancel_meta_seq.reset();
413 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
414 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
415 << " action first set to [" << func.action << ']');
417 // When not cancel or meta-fake, do the normal lookup.
418 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
419 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
420 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
421 // remove Caps Lock and Mod2 as a modifiers
422 func = keyseq.addkey(keysym, (state | meta_fake_bit));
423 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
424 << "action now set to [" << func.action << ']');
427 // Dont remove this unless you know what you are doing.
428 meta_fake_bit = NoModifier;
430 // Can this happen now ?
431 if (func.action == LFUN_NOACTION)
432 func = FuncRequest(LFUN_COMMAND_PREFIX);
434 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
435 << " Key [action=" << func.action << "]["
436 << to_utf8(keyseq.print(KeySequence::Portable)) << ']');
438 // already here we know if it any point in going further
439 // why not return already here if action == -1 and
440 // num_bytes == 0? (Lgb)
442 if (keyseq.length() > 1)
443 lyx_view_->message(keyseq.print(KeySequence::ForGui));
446 // Maybe user can only reach the key via holding down shift.
447 // Let's see. But only if shift is the only modifier
448 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
449 LYXERR(Debug::KEY, "Trying without shift");
450 func = keyseq.addkey(keysym, NoModifier);
451 LYXERR(Debug::KEY, "Action now " << func.action);
454 if (func.action == LFUN_UNKNOWN_ACTION) {
455 // Hmm, we didn't match any of the keysequences. See
456 // if it's normal insertable text not already covered
458 if (keysym.isText() && keyseq.length() == 1) {
459 LYXERR(Debug::KEY, "isText() is true, inserting.");
460 func = FuncRequest(LFUN_SELF_INSERT,
461 FuncRequest::KEYBOARD);
463 LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
464 lyx_view_->message(_("Unknown function."));
465 lyx_view_->restartCursor();
470 if (func.action == LFUN_SELF_INSERT) {
471 if (encoded_last_key != 0) {
472 docstring const arg(1, encoded_last_key);
473 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
474 FuncRequest::KEYBOARD));
475 LYXERR(Debug::KEY, "SelfInsert arg[`" << to_utf8(arg) << "']");
481 lyx_view_->restartCursor();
485 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
487 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
490 /* In LyX/Mac, when a dialog is open, the menus of the
491 application can still be accessed without giving focus to
492 the main window. In this case, we want to disable the menu
493 entries that are buffer-related.
495 Note that this code is not perfect, as bug 1941 attests:
496 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
498 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
499 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
502 if (cmd.action == LFUN_NOACTION) {
503 flag.message(from_utf8(N_("Nothing to do")));
508 switch (cmd.action) {
509 case LFUN_UNKNOWN_ACTION:
510 #ifndef HAVE_LIBAIKSAURUS
511 case LFUN_THESAURUS_ENTRY:
521 if (flag.unknown()) {
522 flag.message(from_utf8(N_("Unknown action")));
526 if (!flag.enabled()) {
527 if (flag.message().empty())
528 flag.message(from_utf8(N_("Command disabled")));
532 // Check whether we need a buffer
533 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
535 flag.message(from_utf8(N_("Command not allowed with"
536 "out any document open")));
541 // I would really like to avoid having this switch and rather try to
542 // encode this in the function itself.
543 // -- And I'd rather let an inset decide which LFUNs it is willing
544 // to handle (Andre')
546 switch (cmd.action) {
547 case LFUN_BUFFER_TOGGLE_READ_ONLY:
548 flag.setOnOff(buf->isReadonly());
551 case LFUN_BUFFER_SWITCH:
552 // toggle on the current buffer, but do not toggle off
553 // the other ones (is that a good idea?)
554 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
558 case LFUN_BUFFER_EXPORT:
559 enable = cmd.argument() == "custom"
560 || buf->isExportable(to_utf8(cmd.argument()));
563 case LFUN_BUFFER_CHKTEX:
564 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
567 case LFUN_BUILD_PROGRAM:
568 enable = buf->isExportable("program");
571 case LFUN_VC_REGISTER:
572 enable = !buf->lyxvc().inUse();
574 case LFUN_VC_CHECK_IN:
575 enable = buf->lyxvc().inUse() && !buf->isReadonly();
577 case LFUN_VC_CHECK_OUT:
578 enable = buf->lyxvc().inUse() && buf->isReadonly();
581 case LFUN_VC_UNDO_LAST:
582 enable = buf->lyxvc().inUse();
584 case LFUN_BUFFER_RELOAD:
585 enable = !buf->isUnnamed() && buf->fileName().exists()
586 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
589 case LFUN_INSET_APPLY: {
594 string const name = cmd.getArg(0);
595 Inset * inset = lyx_view_->getOpenInset(name);
597 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
599 if (!inset->getStatus(view()->cursor(), fr, fs)) {
600 // Every inset is supposed to handle this
605 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
606 flag |= getStatus(fr);
608 enable = flag.enabled();
612 case LFUN_DIALOG_TOGGLE:
613 flag.setOnOff(lyx_view_?
614 lyx_view_->isDialogVisible(cmd.getArg(0)) : false);
615 // fall through to set "enable"
616 case LFUN_DIALOG_SHOW: {
617 string const name = cmd.getArg(0);
619 enable = name == "aboutlyx"
620 || name == "file" //FIXME: should be removed.
622 || name == "texinfo";
623 else if (name == "print")
624 enable = buf->isExportable("dvi")
625 && lyxrc.print_command != "none";
626 else if (name == "character") {
630 InsetCode ic = view()->cursor().inset().lyxCode();
631 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
634 else if (name == "latexlog")
635 enable = FileName(buf->logName()).isFileReadable();
636 else if (name == "spellchecker")
637 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
638 enable = !buf->isReadonly();
642 else if (name == "vclog")
643 enable = buf->lyxvc().inUse();
647 case LFUN_DIALOG_UPDATE: {
648 string const name = cmd.getArg(0);
650 enable = name == "prefs";
654 case LFUN_CITATION_INSERT: {
655 FuncRequest fr(LFUN_INSET_INSERT, "citation");
656 enable = getStatus(fr).enabled();
660 case LFUN_BUFFER_WRITE: {
661 enable = lyx_view_->buffer()->isUnnamed()
662 || !lyx_view_->buffer()->isClean();
667 case LFUN_BUFFER_WRITE_ALL: {
668 // We enable the command only if there are some modified buffers
669 Buffer * first = theBufferList().first();
670 bool modified = false;
674 // We cannot use a for loop as the buffer list is a cycle.
680 b = theBufferList().next(b);
681 } while (b != first);
689 case LFUN_BOOKMARK_GOTO: {
690 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
691 enable = LyX::ref().session().bookmarks().isValid(num);
695 case LFUN_BOOKMARK_CLEAR:
696 enable = LyX::ref().session().bookmarks().size() > 0;
699 case LFUN_TOOLBAR_TOGGLE: {
700 bool const current = lyx_view_?
701 lyx_view_->isToolbarVisible(cmd.getArg(0)) : false;
702 flag.setOnOff(current);
705 case LFUN_WINDOW_CLOSE: {
706 enable = theApp()->viewCount() > 0;
710 // this one is difficult to get right. As a half-baked
711 // solution, we consider only the first action of the sequence
712 case LFUN_COMMAND_SEQUENCE: {
713 // argument contains ';'-terminated commands
714 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
715 FuncRequest func(lyxaction.lookupFunc(firstcmd));
716 func.origin = cmd.origin;
717 flag = getStatus(func);
723 std::string name = to_utf8(cmd.argument());
724 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
725 func.origin = cmd.origin;
726 flag = getStatus(func);
727 LyX::ref().topLevelCmdDef().release(name);
729 // catch recursion or unknown command definiton
730 // all operations until the recursion or unknown command
731 // definiton occures are performed, so set the state to enabled
737 case LFUN_BUFFER_NEW:
738 case LFUN_BUFFER_NEW_TEMPLATE:
739 case LFUN_WORD_FIND_FORWARD:
740 case LFUN_WORD_FIND_BACKWARD:
741 case LFUN_COMMAND_PREFIX:
742 case LFUN_COMMAND_EXECUTE:
744 case LFUN_META_PREFIX:
745 case LFUN_BUFFER_CLOSE:
746 case LFUN_BUFFER_WRITE_AS:
747 case LFUN_BUFFER_UPDATE:
748 case LFUN_BUFFER_VIEW:
749 case LFUN_MASTER_BUFFER_UPDATE:
750 case LFUN_MASTER_BUFFER_VIEW:
751 case LFUN_BUFFER_IMPORT:
752 case LFUN_BUFFER_AUTO_SAVE:
753 case LFUN_RECONFIGURE:
757 case LFUN_DROP_LAYOUTS_CHOICE:
759 case LFUN_SERVER_GET_NAME:
760 case LFUN_SERVER_NOTIFY:
761 case LFUN_SERVER_GOTO_FILE_ROW:
762 case LFUN_DIALOG_HIDE:
763 case LFUN_DIALOG_DISCONNECT_INSET:
764 case LFUN_BUFFER_CHILD_OPEN:
765 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
766 case LFUN_KEYMAP_OFF:
767 case LFUN_KEYMAP_PRIMARY:
768 case LFUN_KEYMAP_SECONDARY:
769 case LFUN_KEYMAP_TOGGLE:
771 case LFUN_BUFFER_EXPORT_CUSTOM:
772 case LFUN_BUFFER_PRINT:
773 case LFUN_PREFERENCES_SAVE:
774 case LFUN_SCREEN_FONT_UPDATE:
777 case LFUN_EXTERNAL_EDIT:
778 case LFUN_GRAPHICS_EDIT:
779 case LFUN_ALL_INSETS_TOGGLE:
780 case LFUN_BUFFER_LANGUAGE:
781 case LFUN_TEXTCLASS_APPLY:
782 case LFUN_TEXTCLASS_LOAD:
783 case LFUN_BUFFER_SAVE_AS_DEFAULT:
784 case LFUN_BUFFER_PARAMS_APPLY:
785 case LFUN_LAYOUT_MODULES_CLEAR:
786 case LFUN_LAYOUT_MODULE_ADD:
787 case LFUN_LAYOUT_RELOAD:
788 case LFUN_LYXRC_APPLY:
789 case LFUN_BUFFER_NEXT:
790 case LFUN_BUFFER_PREVIOUS:
791 case LFUN_WINDOW_NEW:
793 // these are handled in our dispatch()
801 if (!getLocalStatus(view()->cursor(), cmd, flag))
802 flag = view()->getStatus(cmd);
808 // Can we use a readonly buffer?
809 if (buf && buf->isReadonly()
810 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
811 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
812 flag.message(from_utf8(N_("Document is read-only")));
816 // Are we in a DELETED change-tracking region?
818 && lookupChangeType(view()->cursor(), true) == Change::DELETED
819 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
820 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
821 flag.message(from_utf8(N_("This portion of the document is deleted.")));
825 // the default error message if we disable the command
826 if (!flag.enabled() && flag.message().empty())
827 flag.message(from_utf8(N_("Command disabled")));
833 bool LyXFunc::ensureBufferClean(BufferView * bv)
835 Buffer & buf = bv->buffer();
839 docstring const file = buf.fileName().displayName(30);
840 docstring text = bformat(_("The document %1$s has unsaved "
841 "changes.\n\nDo you want to save "
842 "the document?"), file);
843 int const ret = Alert::prompt(_("Save changed document?"),
844 text, 0, 1, _("&Save"),
848 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
850 return buf.isClean();
856 void showPrintError(string const & name)
858 docstring str = bformat(_("Could not print the document %1$s.\n"
859 "Check that your printer is set up correctly."),
860 makeDisplayPath(name, 50));
861 Alert::error(_("Print document failed"), str);
865 void loadTextClass(string const & name)
867 std::pair<bool, textclass_type> const tc_pair =
868 textclasslist.numberOfClass(name);
870 if (!tc_pair.first) {
871 lyxerr << "Document class \"" << name
872 << "\" does not exist."
877 textclass_type const tc = tc_pair.second;
879 if (!textclasslist[tc].load()) {
880 docstring s = bformat(_("The document class %1$s."
881 "could not be loaded."),
882 from_utf8(textclasslist[tc].name()));
883 Alert::error(_("Could not load class"), s);
888 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
893 void LyXFunc::dispatch(FuncRequest const & cmd)
895 string const argument = to_utf8(cmd.argument());
896 kb_action const action = cmd.action;
898 LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
899 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
901 // we have not done anything wrong yet.
903 dispatch_buffer.erase();
905 // redraw the screen at the end (first of the two drawing steps).
906 //This is done unless explicitely requested otherwise
907 Update::flags updateFlags = Update::FitCursor;
909 FuncStatus const flag = getStatus(cmd);
910 if (!flag.enabled()) {
911 // We cannot use this function here
912 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
913 << lyxaction.getActionName(action)
914 << " [" << action << "] is disabled at this location");
915 setErrorMessage(flag.message());
918 // Let lyx_view_ dispatch its own actions.
919 case LFUN_COMMAND_EXECUTE:
920 case LFUN_DROP_LAYOUTS_CHOICE:
922 case LFUN_TOOLBAR_TOGGLE:
923 BOOST_ASSERT(lyx_view_);
924 lyx_view_->dispatch(cmd);
927 case LFUN_WORD_FIND_FORWARD:
928 case LFUN_WORD_FIND_BACKWARD: {
929 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
930 static docstring last_search;
931 docstring searched_string;
933 if (!cmd.argument().empty()) {
934 last_search = cmd.argument();
935 searched_string = cmd.argument();
937 searched_string = last_search;
940 if (searched_string.empty())
943 bool const fw = action == LFUN_WORD_FIND_FORWARD;
944 docstring const data =
945 find2string(searched_string, true, false, fw);
946 find(view(), FuncRequest(LFUN_WORD_FIND, data));
950 case LFUN_COMMAND_PREFIX:
951 BOOST_ASSERT(lyx_view_);
952 lyx_view_->message(keyseq.printOptions(true));
956 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
958 meta_fake_bit = NoModifier;
959 if (lyx_view_->buffer())
960 // cancel any selection
961 dispatch(FuncRequest(LFUN_MARK_OFF));
962 setMessage(from_ascii(N_("Cancel")));
965 case LFUN_META_PREFIX:
966 meta_fake_bit = AltModifier;
967 setMessage(keyseq.print(KeySequence::ForGui));
970 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
971 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
972 Buffer * buf = lyx_view_->buffer();
973 if (buf->lyxvc().inUse())
974 buf->lyxvc().toggleReadOnly();
976 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
980 // --- Menus -----------------------------------------------
981 case LFUN_BUFFER_NEW:
982 menuNew(argument, false);
983 updateFlags = Update::None;
986 case LFUN_BUFFER_NEW_TEMPLATE:
987 menuNew(argument, true);
988 updateFlags = Update::None;
991 case LFUN_BUFFER_CLOSE:
993 updateFlags = Update::None;
996 case LFUN_BUFFER_WRITE:
997 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
998 if (!lyx_view_->buffer()->isUnnamed()) {
999 docstring const str = bformat(_("Saving document %1$s..."),
1000 makeDisplayPath(lyx_view_->buffer()->absFileName()));
1001 lyx_view_->message(str);
1002 lyx_view_->buffer()->menuWrite();
1003 lyx_view_->message(str + _(" done."));
1005 lyx_view_->buffer()->writeAs();
1007 updateFlags = Update::None;
1010 case LFUN_BUFFER_WRITE_AS:
1011 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1012 lyx_view_->buffer()->writeAs(argument);
1013 updateFlags = Update::None;
1016 case LFUN_BUFFER_WRITE_ALL: {
1017 Buffer * first = theBufferList().first();
1020 lyx_view_->message(_("Saving all documents..."));
1022 // We cannot use a for loop as the buffer list cycles.
1024 if (!b->isClean()) {
1025 if (!b->isUnnamed()) {
1027 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1031 b = theBufferList().next(b);
1032 } while (b != first);
1033 lyx_view_->message(_("All documents saved."));
1036 updateFlags = Update::None;
1040 case LFUN_BUFFER_RELOAD: {
1041 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1042 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1043 docstring text = bformat(_("Any changes will be lost. Are you sure "
1044 "you want to revert to the saved version of the document %1$s?"), file);
1045 int const ret = Alert::prompt(_("Revert to saved document?"),
1046 text, 1, 1, _("&Revert"), _("&Cancel"));
1053 case LFUN_BUFFER_UPDATE:
1054 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1055 lyx_view_->buffer()->doExport(argument, true);
1058 case LFUN_BUFFER_VIEW:
1059 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1060 lyx_view_->buffer()->preview(argument);
1063 case LFUN_MASTER_BUFFER_UPDATE:
1064 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1065 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1068 case LFUN_MASTER_BUFFER_VIEW:
1069 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1070 lyx_view_->buffer()->masterBuffer()->preview(argument);
1073 case LFUN_BUILD_PROGRAM:
1074 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1075 lyx_view_->buffer()->doExport("program", true);
1078 case LFUN_BUFFER_CHKTEX:
1079 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1080 lyx_view_->buffer()->runChktex();
1083 case LFUN_BUFFER_EXPORT:
1084 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1085 if (argument == "custom")
1086 lyx_view_->showDialog("sendto", string());
1088 lyx_view_->buffer()->doExport(argument, false);
1091 case LFUN_BUFFER_EXPORT_CUSTOM: {
1092 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1094 string command = split(argument, format_name, ' ');
1095 Format const * format = formats.getFormat(format_name);
1097 lyxerr << "Format \"" << format_name
1098 << "\" not recognized!"
1103 Buffer * buffer = lyx_view_->buffer();
1105 // The name of the file created by the conversion process
1108 // Output to filename
1109 if (format->name() == "lyx") {
1110 string const latexname = buffer->latexName(false);
1111 filename = changeExtension(latexname,
1112 format->extension());
1113 filename = addName(buffer->temppath(), filename);
1115 if (!buffer->writeFile(FileName(filename)))
1119 buffer->doExport(format_name, true, filename);
1122 // Substitute $$FName for filename
1123 if (!contains(command, "$$FName"))
1124 command = "( " + command + " ) < $$FName";
1125 command = subst(command, "$$FName", filename);
1127 // Execute the command in the background
1129 call.startscript(Systemcall::DontWait, command);
1133 case LFUN_BUFFER_PRINT: {
1134 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1135 // FIXME: cmd.getArg() might fail if one of the arguments
1136 // contains double quotes
1137 string target = cmd.getArg(0);
1138 string target_name = cmd.getArg(1);
1139 string command = cmd.getArg(2);
1142 || target_name.empty()
1143 || command.empty()) {
1144 lyxerr << "Unable to parse \""
1145 << argument << '"' << endl;
1148 if (target != "printer" && target != "file") {
1149 lyxerr << "Unrecognized target \""
1150 << target << '"' << endl;
1154 Buffer * buffer = lyx_view_->buffer();
1156 if (!buffer->doExport("dvi", true)) {
1157 showPrintError(buffer->absFileName());
1161 // Push directory path.
1162 string const path = buffer->temppath();
1163 // Prevent the compiler from optimizing away p
1165 support::PathChanger p(pp);
1167 // there are three cases here:
1168 // 1. we print to a file
1169 // 2. we print directly to a printer
1170 // 3. we print using a spool command (print to file first)
1173 string const dviname =
1174 changeExtension(buffer->latexName(true), "dvi");
1176 if (target == "printer") {
1177 if (!lyxrc.print_spool_command.empty()) {
1178 // case 3: print using a spool
1179 string const psname =
1180 changeExtension(dviname,".ps");
1181 command += ' ' + lyxrc.print_to_file
1184 + quoteName(dviname);
1187 lyxrc.print_spool_command + ' ';
1188 if (target_name != "default") {
1189 command2 += lyxrc.print_spool_printerprefix
1193 command2 += quoteName(psname);
1195 // If successful, then spool command
1196 res = one.startscript(
1201 res = one.startscript(
1202 Systemcall::DontWait,
1205 // case 2: print directly to a printer
1206 if (target_name != "default")
1207 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1208 res = one.startscript(
1209 Systemcall::DontWait,
1210 command + quoteName(dviname));
1214 // case 1: print to a file
1215 FileName const filename(makeAbsPath(target_name,
1216 lyx_view_->buffer()->filePath()));
1217 FileName const dvifile(makeAbsPath(dviname, path));
1218 if (filename.exists()) {
1219 docstring text = bformat(
1220 _("The file %1$s already exists.\n\n"
1221 "Do you want to overwrite that file?"),
1222 makeDisplayPath(filename.absFilename()));
1223 if (Alert::prompt(_("Overwrite file?"),
1224 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1227 command += ' ' + lyxrc.print_to_file
1228 + quoteName(filename.toFilesystemEncoding())
1230 + quoteName(dvifile.toFilesystemEncoding());
1231 res = one.startscript(Systemcall::DontWait,
1236 showPrintError(buffer->absFileName());
1240 case LFUN_BUFFER_IMPORT:
1245 // quitting is triggered by the gui code
1246 // (leaving the event loop).
1247 lyx_view_->message(from_utf8(N_("Exiting.")));
1248 if (theBufferList().quitWriteAll())
1249 theApp()->closeAllViews();
1252 case LFUN_BUFFER_AUTO_SAVE:
1253 lyx_view_->buffer()->autoSave();
1256 case LFUN_RECONFIGURE:
1257 BOOST_ASSERT(lyx_view_);
1258 // argument is any additional parameter to the configure.py command
1259 reconfigure(*lyx_view_, argument);
1262 case LFUN_HELP_OPEN: {
1263 BOOST_ASSERT(lyx_view_);
1264 string const arg = argument;
1266 setErrorMessage(from_ascii(N_("Missing argument")));
1269 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1270 if (fname.empty()) {
1271 lyxerr << "LyX: unable to find documentation file `"
1272 << arg << "'. Bad installation?" << endl;
1275 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1276 makeDisplayPath(fname.absFilename())));
1277 Buffer * buf = loadAndViewFile(fname, false);
1280 lyx_view_->setBuffer(buf);
1281 lyx_view_->errors("Parse");
1283 updateFlags = Update::None;
1287 // --- version control -------------------------------
1288 case LFUN_VC_REGISTER:
1289 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1290 if (!ensureBufferClean(view()))
1292 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1293 lyx_view_->buffer()->lyxvc().registrer();
1296 updateFlags = Update::Force;
1299 case LFUN_VC_CHECK_IN:
1300 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1301 if (!ensureBufferClean(view()))
1303 if (lyx_view_->buffer()->lyxvc().inUse()
1304 && !lyx_view_->buffer()->isReadonly()) {
1305 lyx_view_->buffer()->lyxvc().checkIn();
1310 case LFUN_VC_CHECK_OUT:
1311 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1312 if (!ensureBufferClean(view()))
1314 if (lyx_view_->buffer()->lyxvc().inUse()
1315 && lyx_view_->buffer()->isReadonly()) {
1316 lyx_view_->buffer()->lyxvc().checkOut();
1321 case LFUN_VC_REVERT:
1322 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1323 lyx_view_->buffer()->lyxvc().revert();
1327 case LFUN_VC_UNDO_LAST:
1328 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1329 lyx_view_->buffer()->lyxvc().undoLast();
1333 // --- buffers ----------------------------------------
1334 case LFUN_BUFFER_SWITCH:
1335 BOOST_ASSERT(lyx_view_);
1336 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1337 updateFlags = Update::None;
1340 case LFUN_BUFFER_NEXT:
1341 BOOST_ASSERT(lyx_view_);
1342 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1343 updateFlags = Update::None;
1346 case LFUN_BUFFER_PREVIOUS:
1347 BOOST_ASSERT(lyx_view_);
1348 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1349 updateFlags = Update::None;
1352 case LFUN_FILE_NEW: {
1353 BOOST_ASSERT(lyx_view_);
1355 string tmpname = split(argument, name, ':'); // Split filename
1356 Buffer * const b = newFile(name, tmpname);
1358 lyx_view_->setBuffer(b);
1359 updateFlags = Update::None;
1363 case LFUN_FILE_OPEN:
1364 BOOST_ASSERT(lyx_view_);
1366 updateFlags = Update::None;
1369 // --- lyxserver commands ----------------------------
1370 case LFUN_SERVER_GET_NAME:
1371 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1372 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1373 LYXERR(Debug::INFO, "FNAME["
1374 << lyx_view_->buffer()->absFileName() << ']');
1377 case LFUN_SERVER_NOTIFY:
1378 dispatch_buffer = keyseq.print(KeySequence::Portable);
1379 theServer().notifyClient(to_utf8(dispatch_buffer));
1382 case LFUN_SERVER_GOTO_FILE_ROW: {
1383 BOOST_ASSERT(lyx_view_);
1386 istringstream is(argument);
1387 is >> file_name >> row;
1389 bool loaded = false;
1390 if (prefixIs(file_name, package().temp_dir().absFilename()))
1391 // Needed by inverse dvi search. If it is a file
1392 // in tmpdir, call the apropriated function
1393 buf = theBufferList().getBufferFromTmp(file_name);
1395 // Must replace extension of the file to be .lyx
1396 // and get full path
1397 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1398 // Either change buffer or load the file
1399 if (theBufferList().exists(s.absFilename()))
1400 buf = theBufferList().getBuffer(s.absFilename());
1402 buf = loadAndViewFile(s);
1408 updateFlags = Update::None;
1413 lyx_view_->setBuffer(buf);
1414 view()->setCursorFromRow(row);
1416 lyx_view_->errors("Parse");
1417 updateFlags = Update::FitCursor;
1421 case LFUN_DIALOG_SHOW: {
1422 BOOST_ASSERT(lyx_view_);
1423 string const name = cmd.getArg(0);
1424 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1426 if (name == "character") {
1427 data = freefont2string();
1429 lyx_view_->showDialog("character", data);
1430 } else if (name == "latexlog") {
1431 Buffer::LogType type;
1432 string const logfile = lyx_view_->buffer()->logName(&type);
1434 case Buffer::latexlog:
1437 case Buffer::buildlog:
1441 data += Lexer::quoteString(logfile);
1442 lyx_view_->showDialog("log", data);
1443 } else if (name == "vclog") {
1444 string const data = "vc " +
1445 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1446 lyx_view_->showDialog("log", data);
1448 lyx_view_->showDialog(name, data);
1452 case LFUN_DIALOG_SHOW_NEW_INSET: {
1453 BOOST_ASSERT(lyx_view_);
1454 string const name = cmd.getArg(0);
1455 InsetCode code = insetCode(name);
1456 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1457 bool insetCodeOK = true;
1466 case HYPERLINK_CODE: {
1467 InsetCommandParams p(code);
1468 data = InsetCommandMailer::params2string(name, p);
1471 case INCLUDE_CODE: {
1472 // data is the include type: one of "include",
1473 // "input", "verbatiminput" or "verbatiminput*"
1475 // default type is requested
1477 InsetCommandParams p(INCLUDE_CODE, data);
1478 data = InsetCommandMailer::params2string("include", p);
1482 // \c data == "Boxed" || "Frameless" etc
1483 InsetBoxParams p(data);
1484 data = InsetBoxMailer::params2string(p);
1488 InsetBranchParams p;
1489 data = InsetBranchMailer::params2string(p);
1493 InsetCommandParams p(CITE_CODE);
1494 data = InsetCommandMailer::params2string(name, p);
1498 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1501 case EXTERNAL_CODE: {
1502 InsetExternalParams p;
1503 Buffer const & buffer = *lyx_view_->buffer();
1504 data = InsetExternalMailer::params2string(p, buffer);
1509 data = InsetFloatMailer::params2string(p);
1512 case LISTINGS_CODE: {
1513 InsetListingsParams p;
1514 data = InsetListingsMailer::params2string(p);
1517 case GRAPHICS_CODE: {
1518 InsetGraphicsParams p;
1519 Buffer const & buffer = *lyx_view_->buffer();
1520 data = InsetGraphicsMailer::params2string(p, buffer);
1525 data = InsetNoteMailer::params2string(p);
1530 data = InsetVSpaceMailer::params2string(space);
1535 data = InsetWrapMailer::params2string(p);
1539 lyxerr << "Inset type '" << name <<
1540 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1541 insetCodeOK = false;
1543 } // end switch(code)
1545 lyx_view_->showDialog(name, data, 0);
1549 case LFUN_DIALOG_UPDATE: {
1550 BOOST_ASSERT(lyx_view_);
1551 string const & name = argument;
1552 // Can only update a dialog connected to an existing inset
1553 Inset * inset = lyx_view_->getOpenInset(name);
1555 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1556 inset->dispatch(view()->cursor(), fr);
1557 } else if (name == "paragraph") {
1558 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1559 } else if (name == "prefs") {
1560 lyx_view_->updateDialog(name, string());
1565 case LFUN_DIALOG_HIDE: {
1566 if (quitting || !use_gui)
1568 theApp()->hideDialogs(argument, 0);
1572 case LFUN_DIALOG_TOGGLE: {
1573 BOOST_ASSERT(lyx_view_);
1574 if (lyx_view_->isDialogVisible(cmd.getArg(0)))
1575 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1577 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1581 case LFUN_DIALOG_DISCONNECT_INSET:
1582 BOOST_ASSERT(lyx_view_);
1583 lyx_view_->disconnectDialog(argument);
1587 case LFUN_CITATION_INSERT: {
1588 BOOST_ASSERT(lyx_view_);
1589 if (!argument.empty()) {
1590 // we can have one optional argument, delimited by '|'
1591 // citation-insert <key>|<text_before>
1592 // this should be enhanced to also support text_after
1593 // and citation style
1594 string arg = argument;
1596 if (contains(argument, "|")) {
1597 arg = token(argument, '|', 0);
1598 opt1 = token(argument, '|', 1);
1600 InsetCommandParams icp(CITE_CODE);
1601 icp["key"] = from_utf8(arg);
1603 icp["before"] = from_utf8(opt1);
1604 string icstr = InsetCommandMailer::params2string("citation", icp);
1605 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1608 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1612 case LFUN_BUFFER_CHILD_OPEN: {
1613 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1614 Buffer * parent = lyx_view_->buffer();
1615 FileName filename = makeAbsPath(argument, parent->filePath());
1616 view()->saveBookmark(false);
1618 bool parsed = false;
1619 if (theBufferList().exists(filename.absFilename())) {
1620 child = theBufferList().getBuffer(filename.absFilename());
1622 setMessage(bformat(_("Opening child document %1$s..."),
1623 makeDisplayPath(filename.absFilename())));
1624 child = loadAndViewFile(filename, true);
1628 // Set the parent name of the child document.
1629 // This makes insertion of citations and references in the child work,
1630 // when the target is in the parent or another child document.
1631 child->setParentName(parent->absFileName());
1632 updateLabels(*child->masterBuffer());
1633 lyx_view_->setBuffer(child);
1635 lyx_view_->errors("Parse");
1638 // If a screen update is required (in case where auto_open is false),
1639 // setBuffer() would have taken care of it already. Otherwise we shall
1640 // reset the update flag because it can cause a circular problem.
1642 updateFlags = Update::None;
1646 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1647 BOOST_ASSERT(lyx_view_);
1648 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1651 case LFUN_KEYMAP_OFF:
1652 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1653 lyx_view_->view()->getIntl().keyMapOn(false);
1656 case LFUN_KEYMAP_PRIMARY:
1657 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1658 lyx_view_->view()->getIntl().keyMapPrim();
1661 case LFUN_KEYMAP_SECONDARY:
1662 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1663 lyx_view_->view()->getIntl().keyMapSec();
1666 case LFUN_KEYMAP_TOGGLE:
1667 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1668 lyx_view_->view()->getIntl().toggleKeyMap();
1674 string rest = split(argument, countstr, ' ');
1675 istringstream is(countstr);
1678 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1679 for (int i = 0; i < count; ++i)
1680 dispatch(lyxaction.lookupFunc(rest));
1684 case LFUN_COMMAND_SEQUENCE: {
1685 // argument contains ';'-terminated commands
1686 string arg = argument;
1687 while (!arg.empty()) {
1689 arg = split(arg, first, ';');
1690 FuncRequest func(lyxaction.lookupFunc(first));
1691 func.origin = cmd.origin;
1699 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1700 func.origin = cmd.origin;
1702 LyX::ref().topLevelCmdDef().release(argument);
1704 if (func.action == LFUN_UNKNOWN_ACTION) {
1705 // unknown command definition
1706 lyxerr << "Warning: unknown command definition `"
1710 // recursion detected
1711 lyxerr << "Warning: Recursion in the command definition `"
1712 << argument << "' detected"
1719 case LFUN_PREFERENCES_SAVE: {
1720 lyxrc.write(makeAbsPath("preferences",
1721 package().user_support().absFilename()),
1726 case LFUN_SCREEN_FONT_UPDATE:
1727 BOOST_ASSERT(lyx_view_);
1728 // handle the screen font changes.
1729 theFontLoader().update();
1730 /// FIXME: only the current view will be updated. the Gui
1731 /// class is able to furnish the list of views.
1732 updateFlags = Update::Force;
1735 case LFUN_SET_COLOR: {
1737 string const x11_name = split(argument, lyx_name, ' ');
1738 if (lyx_name.empty() || x11_name.empty()) {
1739 setErrorMessage(from_ascii(N_(
1740 "Syntax: set-color <lyx_name>"
1745 bool const graphicsbg_changed =
1746 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1747 x11_name != lcolor.getX11Name(Color_graphicsbg));
1749 if (!lcolor.setColor(lyx_name, x11_name)) {
1751 bformat(_("Set-color \"%1$s\" failed "
1752 "- color is undefined or "
1753 "may not be redefined"),
1754 from_utf8(lyx_name)));
1758 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1760 if (graphicsbg_changed) {
1761 // FIXME: The graphics cache no longer has a changeDisplay method.
1763 graphics::GCache::get().changeDisplay(true);
1770 BOOST_ASSERT(lyx_view_);
1771 lyx_view_->message(from_utf8(argument));
1774 case LFUN_EXTERNAL_EDIT: {
1775 BOOST_ASSERT(lyx_view_);
1776 FuncRequest fr(action, argument);
1777 InsetExternal().dispatch(view()->cursor(), fr);
1781 case LFUN_GRAPHICS_EDIT: {
1782 FuncRequest fr(action, argument);
1783 InsetGraphics().dispatch(view()->cursor(), fr);
1787 case LFUN_INSET_APPLY: {
1788 BOOST_ASSERT(lyx_view_);
1789 string const name = cmd.getArg(0);
1790 Inset * inset = lyx_view_->getOpenInset(name);
1792 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1793 inset->dispatch(view()->cursor(), fr);
1795 FuncRequest fr(LFUN_INSET_INSERT, argument);
1798 // ideally, the update flag should be set by the insets,
1799 // but this is not possible currently
1800 updateFlags = Update::Force | Update::FitCursor;
1804 case LFUN_ALL_INSETS_TOGGLE: {
1805 BOOST_ASSERT(lyx_view_);
1807 string const name = split(argument, action, ' ');
1808 InsetCode const inset_code = insetCode(name);
1810 Cursor & cur = view()->cursor();
1811 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1813 Inset & inset = lyx_view_->buffer()->inset();
1814 InsetIterator it = inset_iterator_begin(inset);
1815 InsetIterator const end = inset_iterator_end(inset);
1816 for (; it != end; ++it) {
1817 if (!it->asInsetMath()
1818 && (inset_code == NO_CODE
1819 || inset_code == it->lyxCode())) {
1820 Cursor tmpcur = cur;
1821 tmpcur.pushBackward(*it);
1822 it->dispatch(tmpcur, fr);
1825 updateFlags = Update::Force | Update::FitCursor;
1829 case LFUN_BUFFER_LANGUAGE: {
1830 BOOST_ASSERT(lyx_view_);
1831 Buffer & buffer = *lyx_view_->buffer();
1832 Language const * oldL = buffer.params().language;
1833 Language const * newL = languages.getLanguage(argument);
1834 if (!newL || oldL == newL)
1837 if (oldL->rightToLeft() == newL->rightToLeft()
1838 && !buffer.isMultiLingual())
1839 buffer.changeLanguage(oldL, newL);
1843 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1844 string const fname =
1845 addName(addPath(package().user_support().absFilename(), "templates/"),
1847 Buffer defaults(fname);
1849 istringstream ss(argument);
1852 int const unknown_tokens = defaults.readHeader(lex);
1854 if (unknown_tokens != 0) {
1855 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1856 << unknown_tokens << " unknown token"
1857 << (unknown_tokens == 1 ? "" : "s")
1861 if (defaults.writeFile(FileName(defaults.absFileName())))
1862 setMessage(bformat(_("Document defaults saved in %1$s"),
1863 makeDisplayPath(fname)));
1865 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1869 case LFUN_BUFFER_PARAMS_APPLY: {
1870 BOOST_ASSERT(lyx_view_);
1871 biblio::CiteEngine const oldEngine =
1872 lyx_view_->buffer()->params().getEngine();
1874 Buffer * buffer = lyx_view_->buffer();
1876 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1878 Cursor & cur = view()->cursor();
1879 cur.recordUndoFullDocument();
1881 istringstream ss(argument);
1884 int const unknown_tokens = buffer->readHeader(lex);
1886 if (unknown_tokens != 0) {
1887 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1888 << unknown_tokens << " unknown token"
1889 << (unknown_tokens == 1 ? "" : "s")
1893 updateLayout(oldClass, buffer);
1895 biblio::CiteEngine const newEngine =
1896 lyx_view_->buffer()->params().getEngine();
1898 if (oldEngine != newEngine) {
1899 FuncRequest fr(LFUN_INSET_REFRESH);
1901 Inset & inset = lyx_view_->buffer()->inset();
1902 InsetIterator it = inset_iterator_begin(inset);
1903 InsetIterator const end = inset_iterator_end(inset);
1904 for (; it != end; ++it)
1905 if (it->lyxCode() == CITE_CODE)
1906 it->dispatch(cur, fr);
1909 updateFlags = Update::Force | Update::FitCursor;
1913 case LFUN_LAYOUT_MODULES_CLEAR: {
1914 BOOST_ASSERT(lyx_view_);
1915 Buffer * buffer = lyx_view_->buffer();
1916 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1917 view()->cursor().recordUndoFullDocument();
1918 buffer->params().clearLayoutModules();
1919 updateLayout(oldClass, buffer);
1920 updateFlags = Update::Force | Update::FitCursor;
1924 case LFUN_LAYOUT_MODULE_ADD: {
1925 BOOST_ASSERT(lyx_view_);
1926 Buffer * buffer = lyx_view_->buffer();
1927 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1928 view()->cursor().recordUndoFullDocument();
1929 buffer->params().addLayoutModule(argument);
1930 updateLayout(oldClass, buffer);
1931 updateFlags = Update::Force | Update::FitCursor;
1935 case LFUN_TEXTCLASS_APPLY: {
1936 BOOST_ASSERT(lyx_view_);
1937 Buffer * buffer = lyx_view_->buffer();
1939 loadTextClass(argument);
1941 std::pair<bool, textclass_type> const tc_pair =
1942 textclasslist.numberOfClass(argument);
1947 textclass_type const old_class = buffer->params().getBaseClass();
1948 textclass_type const new_class = tc_pair.second;
1950 if (old_class == new_class)
1954 //Save the old, possibly modular, layout for use in conversion.
1955 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1956 view()->cursor().recordUndoFullDocument();
1957 buffer->params().setBaseClass(new_class);
1958 updateLayout(oldClass, buffer);
1959 updateFlags = Update::Force | Update::FitCursor;
1963 case LFUN_LAYOUT_RELOAD: {
1964 BOOST_ASSERT(lyx_view_);
1965 Buffer * buffer = lyx_view_->buffer();
1966 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1967 textclass_type const tc = buffer->params().getBaseClass();
1968 textclasslist.reset(tc);
1969 buffer->params().setBaseClass(tc);
1970 updateLayout(oldClass, buffer);
1971 updateFlags = Update::Force | Update::FitCursor;
1975 case LFUN_TEXTCLASS_LOAD:
1976 loadTextClass(argument);
1979 case LFUN_LYXRC_APPLY: {
1980 LyXRC const lyxrc_orig = lyxrc;
1982 istringstream ss(argument);
1983 bool const success = lyxrc.read(ss) == 0;
1986 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1987 << "Unable to read lyxrc data"
1992 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1994 if (lyx_view_ && lyx_view_->buffer())
1995 lyx_view_->updateLayoutChoice(true);
1997 /// We force the redraw in any case because there might be
1998 /// some screen font changes.
1999 /// FIXME: only the current view will be updated. the Gui
2000 /// class is able to furnish the list of views.
2001 updateFlags = Update::Force;
2005 case LFUN_WINDOW_NEW:
2006 LyX::ref().newLyXView();
2009 case LFUN_WINDOW_CLOSE:
2010 BOOST_ASSERT(lyx_view_);
2011 BOOST_ASSERT(theApp());
2012 // update bookmark pit of the current buffer before window close
2013 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2014 gotoBookmark(i+1, false, false);
2015 // ask the user for saving changes or cancel quit
2016 if (!theBufferList().quitWriteAll())
2021 case LFUN_BOOKMARK_GOTO:
2022 // go to bookmark, open unopened file and switch to buffer if necessary
2023 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2026 case LFUN_BOOKMARK_CLEAR:
2027 LyX::ref().session().bookmarks().clear();
2031 BOOST_ASSERT(lyx_view_);
2032 view()->cursor().dispatch(cmd);
2033 updateFlags = view()->cursor().result().update();
2034 if (!view()->cursor().result().dispatched())
2035 updateFlags = view()->dispatch(cmd);
2040 if (lyx_view_ && lyx_view_->buffer()) {
2041 // BufferView::update() updates the ViewMetricsInfo and
2042 // also initializes the position cache for all insets in
2043 // (at least partially) visible top-level paragraphs.
2044 // We will redraw the screen only if needed.
2045 view()->processUpdateFlags(updateFlags);
2046 lyx_view_->updateStatusBar();
2048 // if we executed a mutating lfun, mark the buffer as dirty
2050 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2051 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2052 lyx_view_->buffer()->markDirty();
2054 //Do we have a selection?
2055 theSelection().haveSelection(view()->cursor().selection());
2057 if (view()->cursor().inTexted()) {
2058 lyx_view_->updateLayoutChoice(false);
2062 if (!quitting && lyx_view_) {
2063 lyx_view_->updateToolbars();
2064 // Some messages may already be translated, so we cannot use _()
2065 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2070 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2072 const bool verbose = (cmd.origin == FuncRequest::MENU
2073 || cmd.origin == FuncRequest::TOOLBAR
2074 || cmd.origin == FuncRequest::COMMANDBUFFER);
2076 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2077 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
2079 lyx_view_->message(msg);
2083 docstring dispatch_msg = msg;
2084 if (!dispatch_msg.empty())
2085 dispatch_msg += ' ';
2087 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2089 bool argsadded = false;
2091 if (!cmd.argument().empty()) {
2092 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2093 comname += ' ' + cmd.argument();
2098 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2100 if (!shortcuts.empty())
2101 comname += ": " + shortcuts;
2102 else if (!argsadded && !cmd.argument().empty())
2103 comname += ' ' + cmd.argument();
2105 if (!comname.empty()) {
2106 comname = rtrim(comname);
2107 dispatch_msg += '(' + rtrim(comname) + ')';
2110 LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
2111 if (!dispatch_msg.empty())
2112 lyx_view_->message(dispatch_msg);
2116 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2118 // FIXME: initpath is not used. What to do?
2119 string initpath = lyxrc.document_path;
2120 string filename(name);
2122 if (lyx_view_->buffer()) {
2123 string const trypath = lyx_view_->buffer()->filePath();
2124 // If directory is writeable, use this as default.
2125 if (FileName(trypath).isDirWritable())
2129 static int newfile_number;
2131 if (filename.empty()) {
2132 filename = addName(lyxrc.document_path,
2133 "newfile" + convert<string>(++newfile_number) + ".lyx");
2134 while (theBufferList().exists(filename) ||
2135 FileName(filename).isReadable()) {
2137 filename = addName(lyxrc.document_path,
2138 "newfile" + convert<string>(newfile_number) +
2143 // The template stuff
2146 FileDialog dlg(_("Select template file"));
2147 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2148 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2150 FileDialog::Result result =
2151 dlg.open(from_utf8(lyxrc.template_path),
2152 FileFilterList(_("LyX Documents (*.lyx)")),
2155 if (result.first == FileDialog::Later)
2157 if (result.second.empty())
2159 templname = to_utf8(result.second);
2162 Buffer * const b = newFile(filename, templname, !name.empty());
2164 lyx_view_->setBuffer(b);
2168 Buffer * LyXFunc::loadAndViewFile(FileName const & filename, bool tolastfiles)
2170 lyx_view_->setBusy(true);
2172 Buffer * newBuffer = checkAndLoadLyXFile(filename);
2175 lyx_view_->message(_("Document not loaded."));
2176 lyx_view_->updateStatusBar();
2177 lyx_view_->setBusy(false);
2181 lyx_view_->setBuffer(newBuffer);
2183 // scroll to the position when the file was last closed
2184 if (lyxrc.use_lastfilepos) {
2185 LastFilePosSection::FilePos filepos =
2186 LyX::ref().session().lastFilePos().load(filename);
2187 lyx_view_->view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
2191 LyX::ref().session().lastFiles().add(filename);
2193 lyx_view_->setBusy(false);
2198 void LyXFunc::open(string const & fname)
2200 string initpath = lyxrc.document_path;
2202 if (lyx_view_->buffer()) {
2203 string const trypath = lyx_view_->buffer()->filePath();
2204 // If directory is writeable, use this as default.
2205 if (FileName(trypath).isDirWritable())
2211 if (fname.empty()) {
2212 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2213 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2214 dlg.setButton2(_("Examples|#E#e"),
2215 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2217 FileDialog::Result result =
2218 dlg.open(from_utf8(initpath),
2219 FileFilterList(_("LyX Documents (*.lyx)")),
2222 if (result.first == FileDialog::Later)
2225 filename = to_utf8(result.second);
2227 // check selected filename
2228 if (filename.empty()) {
2229 lyx_view_->message(_("Canceled."));
2235 // get absolute path of file and add ".lyx" to the filename if
2237 FileName const fullname = fileSearch(string(), filename, "lyx");
2238 if (!fullname.empty())
2239 filename = fullname.absFilename();
2241 // if the file doesn't exist, let the user create one
2242 if (!fullname.exists()) {
2243 // the user specifically chose this name. Believe him.
2244 Buffer * const b = newFile(filename, string(), true);
2246 lyx_view_->setBuffer(b);
2250 docstring const disp_fn = makeDisplayPath(filename);
2251 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2254 Buffer * buf = loadAndViewFile(fullname);
2257 lyx_view_->setBuffer(buf);
2258 lyx_view_->errors("Parse");
2259 str2 = bformat(_("Document %1$s opened."), disp_fn);
2261 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2263 lyx_view_->message(str2);
2267 void LyXFunc::doImport(string const & argument)
2270 string filename = split(argument, format, ' ');
2272 LYXERR(Debug::INFO, "LyXFunc::doImport: " << format
2273 << " file: " << filename);
2275 // need user interaction
2276 if (filename.empty()) {
2277 string initpath = lyxrc.document_path;
2279 if (lyx_view_->buffer()) {
2280 string const trypath = lyx_view_->buffer()->filePath();
2281 // If directory is writeable, use this as default.
2282 if (FileName(trypath).isDirWritable())
2286 docstring const text = bformat(_("Select %1$s file to import"),
2287 formats.prettyName(format));
2289 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2290 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2291 dlg.setButton2(_("Examples|#E#e"),
2292 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2294 docstring filter = formats.prettyName(format);
2297 filter += from_utf8(formats.extension(format));
2300 FileDialog::Result result =
2301 dlg.open(from_utf8(initpath),
2302 FileFilterList(filter),
2305 if (result.first == FileDialog::Later)
2308 filename = to_utf8(result.second);
2310 // check selected filename
2311 if (filename.empty())
2312 lyx_view_->message(_("Canceled."));
2315 if (filename.empty())
2318 // get absolute path of file
2319 FileName const fullname(makeAbsPath(filename));
2321 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2323 // Check if the document already is open
2324 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2325 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2326 lyx_view_->message(_("Canceled."));
2331 // if the file exists already, and we didn't do
2332 // -i lyx thefile.lyx, warn
2333 if (lyxfile.exists() && fullname != lyxfile) {
2334 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2336 docstring text = bformat(_("The document %1$s already exists.\n\n"
2337 "Do you want to overwrite that document?"), file);
2338 int const ret = Alert::prompt(_("Overwrite document?"),
2339 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2342 lyx_view_->message(_("Canceled."));
2347 ErrorList errorList;
2348 import(lyx_view_, fullname, format, errorList);
2349 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2353 void LyXFunc::closeBuffer()
2355 // goto bookmark to update bookmark pit.
2356 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2357 gotoBookmark(i+1, false, false);
2359 theBufferList().close(lyx_view_->buffer(), true);
2363 void LyXFunc::reloadBuffer()
2365 FileName filename(lyx_view_->buffer()->absFileName());
2366 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2369 Buffer * buf = loadAndViewFile(filename);
2372 lyx_view_->setBuffer(buf);
2373 lyx_view_->errors("Parse");
2374 str = bformat(_("Document %1$s reloaded."), disp_fn);
2376 str = bformat(_("Could not reload document %1$s"), disp_fn);
2378 lyx_view_->message(str);
2381 // Each "lyx_view_" should have it's own message method. lyxview and
2382 // the minibuffer would use the minibuffer, but lyxserver would
2383 // send an ERROR signal to its client. Alejandro 970603
2384 // This function is bit problematic when it comes to NLS, to make the
2385 // lyx servers client be language indepenent we must not translate
2386 // strings sent to this func.
2387 void LyXFunc::setErrorMessage(docstring const & m) const
2389 dispatch_buffer = m;
2394 void LyXFunc::setMessage(docstring const & m) const
2396 dispatch_buffer = m;
2400 docstring const LyXFunc::viewStatusMessage()
2402 // When meta-fake key is pressed, show the key sequence so far + "M-".
2404 return keyseq.print(KeySequence::ForGui) + "M-";
2406 // Else, when a non-complete key sequence is pressed,
2407 // show the available options.
2408 if (keyseq.length() > 0 && !keyseq.deleted())
2409 return keyseq.printOptions(true);
2411 BOOST_ASSERT(lyx_view_);
2412 if (!lyx_view_->buffer())
2413 return _("Welcome to LyX!");
2415 return view()->cursor().currentState();
2419 BufferView * LyXFunc::view() const
2421 BOOST_ASSERT(lyx_view_);
2422 return lyx_view_->view();
2426 bool LyXFunc::wasMetaKey() const
2428 return (meta_fake_bit != NoModifier);
2432 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2435 lyx_view_->message(_("Converting document to new document class..."));
2437 StableDocIterator backcur(view()->cursor());
2438 ErrorList & el = buffer->errorList("Class Switch");
2439 cap::switchBetweenClasses(
2440 oldlayout, buffer->params().getTextClassPtr(),
2441 static_cast<InsetText &>(buffer->inset()), el);
2443 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2445 buffer->errors("Class Switch");
2446 updateLabels(*buffer);
2452 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2454 // Why the switch you might ask. It is a trick to ensure that all
2455 // the elements in the LyXRCTags enum is handled. As you can see
2456 // there are no breaks at all. So it is just a huge fall-through.
2457 // The nice thing is that we will get a warning from the compiler
2458 // if we forget an element.
2459 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2461 case LyXRC::RC_ACCEPT_COMPOUND:
2462 case LyXRC::RC_ALT_LANG:
2463 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2464 case LyXRC::RC_PLAINTEXT_LINELEN:
2465 case LyXRC::RC_AUTOREGIONDELETE:
2466 case LyXRC::RC_AUTORESET_OPTIONS:
2467 case LyXRC::RC_AUTOSAVE:
2468 case LyXRC::RC_AUTO_NUMBER:
2469 case LyXRC::RC_BACKUPDIR_PATH:
2470 case LyXRC::RC_BIBTEX_COMMAND:
2471 case LyXRC::RC_BINDFILE:
2472 case LyXRC::RC_CHECKLASTFILES:
2473 case LyXRC::RC_USELASTFILEPOS:
2474 case LyXRC::RC_LOADSESSION:
2475 case LyXRC::RC_CHKTEX_COMMAND:
2476 case LyXRC::RC_CONVERTER:
2477 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2478 case LyXRC::RC_COPIER:
2479 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2480 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2481 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2482 case LyXRC::RC_DATE_INSERT_FORMAT:
2483 case LyXRC::RC_DEFAULT_LANGUAGE:
2484 case LyXRC::RC_DEFAULT_PAPERSIZE:
2485 case LyXRC::RC_DEFFILE:
2486 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2487 case LyXRC::RC_DISPLAY_GRAPHICS:
2488 case LyXRC::RC_DOCUMENTPATH:
2489 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2490 FileName path(lyxrc_new.document_path);
2491 if (path.exists() && path.isDirectory())
2492 support::package().document_dir() = FileName(lyxrc.document_path);
2494 case LyXRC::RC_ESC_CHARS:
2495 case LyXRC::RC_FONT_ENCODING:
2496 case LyXRC::RC_FORMAT:
2497 case LyXRC::RC_INDEX_COMMAND:
2498 case LyXRC::RC_INPUT:
2499 case LyXRC::RC_KBMAP:
2500 case LyXRC::RC_KBMAP_PRIMARY:
2501 case LyXRC::RC_KBMAP_SECONDARY:
2502 case LyXRC::RC_LABEL_INIT_LENGTH:
2503 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2504 case LyXRC::RC_LANGUAGE_AUTO_END:
2505 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2506 case LyXRC::RC_LANGUAGE_COMMAND_END:
2507 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2508 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2509 case LyXRC::RC_LANGUAGE_PACKAGE:
2510 case LyXRC::RC_LANGUAGE_USE_BABEL:
2511 case LyXRC::RC_MAKE_BACKUP:
2512 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2513 case LyXRC::RC_NUMLASTFILES:
2514 case LyXRC::RC_PATH_PREFIX:
2515 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2516 support::prependEnvPath("PATH", lyxrc.path_prefix);
2518 case LyXRC::RC_PERS_DICT:
2519 case LyXRC::RC_PREVIEW:
2520 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2521 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2522 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2523 case LyXRC::RC_PRINTCOPIESFLAG:
2524 case LyXRC::RC_PRINTER:
2525 case LyXRC::RC_PRINTEVENPAGEFLAG:
2526 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2527 case LyXRC::RC_PRINTFILEEXTENSION:
2528 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2529 case LyXRC::RC_PRINTODDPAGEFLAG:
2530 case LyXRC::RC_PRINTPAGERANGEFLAG:
2531 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2532 case LyXRC::RC_PRINTPAPERFLAG:
2533 case LyXRC::RC_PRINTREVERSEFLAG:
2534 case LyXRC::RC_PRINTSPOOL_COMMAND:
2535 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2536 case LyXRC::RC_PRINTTOFILE:
2537 case LyXRC::RC_PRINTTOPRINTER:
2538 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2539 case LyXRC::RC_PRINT_COMMAND:
2540 case LyXRC::RC_RTL_SUPPORT:
2541 case LyXRC::RC_SCREEN_DPI:
2542 case LyXRC::RC_SCREEN_FONT_ROMAN:
2543 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2544 case LyXRC::RC_SCREEN_FONT_SANS:
2545 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2546 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2547 case LyXRC::RC_SCREEN_FONT_SIZES:
2548 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2549 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2550 case LyXRC::RC_GEOMETRY_SESSION:
2551 case LyXRC::RC_SCREEN_ZOOM:
2552 case LyXRC::RC_SERVERPIPE:
2553 case LyXRC::RC_SET_COLOR:
2554 case LyXRC::RC_SHOW_BANNER:
2555 case LyXRC::RC_SPELL_COMMAND:
2556 case LyXRC::RC_TEMPDIRPATH:
2557 case LyXRC::RC_TEMPLATEPATH:
2558 case LyXRC::RC_TEX_ALLOWS_SPACES:
2559 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2560 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2561 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2563 case LyXRC::RC_UIFILE:
2564 case LyXRC::RC_USER_EMAIL:
2565 case LyXRC::RC_USER_NAME:
2566 case LyXRC::RC_USETEMPDIR:
2567 case LyXRC::RC_USE_ALT_LANG:
2568 case LyXRC::RC_USE_CONVERTER_CACHE:
2569 case LyXRC::RC_USE_ESC_CHARS:
2570 case LyXRC::RC_USE_INP_ENC:
2571 case LyXRC::RC_USE_PERS_DICT:
2572 case LyXRC::RC_USE_PIXMAP_CACHE:
2573 case LyXRC::RC_USE_SPELL_LIB:
2574 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2575 case LyXRC::RC_SORT_LAYOUTS:
2576 case LyXRC::RC_VIEWER:
2577 case LyXRC::RC_LAST: