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.
24 #include "LayoutFile.h"
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"
36 #include "DispatchResult.h"
38 #include "ErrorList.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
42 #include "InsetIterator.h"
47 #include "LyXAction.h"
52 #include "Paragraph.h"
53 #include "ParagraphParameters.h"
54 #include "ParIterator.h"
59 #include "insets/InsetBox.h"
60 #include "insets/InsetBranch.h"
61 #include "insets/InsetCommand.h"
62 #include "insets/InsetERT.h"
63 #include "insets/InsetExternal.h"
64 #include "insets/InsetFloat.h"
65 #include "insets/InsetGraphics.h"
66 #include "insets/InsetInclude.h"
67 #include "insets/InsetListings.h"
68 #include "insets/InsetNote.h"
69 #include "insets/InsetSpace.h"
70 #include "insets/InsetTabular.h"
71 #include "insets/InsetVSpace.h"
72 #include "insets/InsetWrap.h"
74 #include "frontends/alert.h"
75 #include "frontends/Application.h"
76 #include "frontends/KeySymbol.h"
77 #include "frontends/LyXView.h"
78 #include "frontends/Selection.h"
80 #include "support/debug.h"
81 #include "support/environment.h"
82 #include "support/FileName.h"
83 #include "support/filetools.h"
84 #include "support/gettext.h"
85 #include "support/lstrings.h"
86 #include "support/Path.h"
87 #include "support/Package.h"
88 #include "support/Systemcall.h"
89 #include "support/convert.h"
90 #include "support/os.h"
96 using namespace lyx::support
;
100 using frontend::LyXView
;
102 namespace Alert
= frontend::Alert
;
107 // This function runs "configure" and then rereads lyx.defaults to
108 // reconfigure the automatic settings.
109 void reconfigure(LyXView
* lv
, string
const & option
)
111 // emit message signal.
113 lv
->message(_("Running configure..."));
115 // Run configure in user lyx directory
116 PathChanger
p(package().user_support());
117 string configure_command
= package().configure_command();
118 configure_command
+= option
;
120 int ret
= one
.startscript(Systemcall::Wait
, configure_command
);
122 // emit message signal.
124 lv
->message(_("Reloading configuration..."));
125 lyxrc
.read(libFileSearch(string(), "lyxrc.defaults"));
126 // Re-read packages.lst
127 LaTeXFeatures::getAvailable();
130 Alert::information(_("System reconfiguration failed"),
131 _("The system reconfiguration has failed.\n"
132 "Default textclass is used but LyX may "
133 "not be able to work properly.\n"
134 "Please reconfigure again if needed."));
137 Alert::information(_("System reconfigured"),
138 _("The system has been reconfigured.\n"
139 "You need to restart LyX to make use of any\n"
140 "updated document class specifications."));
144 bool getLocalStatus(Cursor cursor
, FuncRequest
const & cmd
, FuncStatus
& status
)
146 // Try to fix cursor in case it is broken.
147 cursor
.fixIfBroken();
149 // This is, of course, a mess. Better create a new doc iterator and use
150 // this in Inset::getStatus. This might require an additional
151 // BufferView * arg, though (which should be avoided)
152 //Cursor safe = *this;
154 for ( ; cursor
.depth(); cursor
.pop()) {
155 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
156 LASSERT(cursor
.idx() <= cursor
.lastidx(), /**/);
157 LASSERT(cursor
.pit() <= cursor
.lastpit(), /**/);
158 LASSERT(cursor
.pos() <= cursor
.lastpos(), /**/);
160 // The inset's getStatus() will return 'true' if it made
161 // a definitive decision on whether it want to handle the
162 // request or not. The result of this decision is put into
163 // the 'status' parameter.
164 if (cursor
.inset().getStatus(cursor
, cmd
, status
)) {
173 /** Return the change status at cursor position, taking in account the
174 * status at each level of the document iterator (a table in a deleted
175 * footnote is deleted).
176 * When \param outer is true, the top slice is not looked at.
178 Change::Type
lookupChangeType(DocIterator
const & dit
, bool outer
= false)
180 size_t const depth
= dit
.depth() - (outer
? 1 : 0);
182 for (size_t i
= 0 ; i
< depth
; ++i
) {
183 CursorSlice
const & slice
= dit
[i
];
184 if (!slice
.inset().inMathed()
185 && slice
.pos() < slice
.paragraph().size()) {
186 Change::Type
const ch
= slice
.paragraph().lookupChange(slice
.pos()).type
;
187 if (ch
!= Change::UNCHANGED
)
191 return Change::UNCHANGED
;
198 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier
)
203 void LyXFunc::initKeySequences(KeyMap
* kb
)
205 keyseq
= KeySequence(kb
, kb
);
206 cancel_meta_seq
= KeySequence(kb
, kb
);
210 void LyXFunc::setLyXView(LyXView
* lv
)
212 if (lyx_view_
&& lyx_view_
->view() && lyx_view_
!= lv
)
213 // save current selection to the selection buffer to allow
214 // middle-button paste in another window
215 cap::saveSelection(lyx_view_
->view()->cursor());
220 void LyXFunc::handleKeyFunc(FuncCode action
)
222 char_type c
= encoded_last_key
;
227 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
228 lyx_view_
->view()->getIntl().getTransManager().deadkey(
229 c
, get_accent(action
).accent
, view()->cursor().innerText(), view()->cursor());
230 // Need to clear, in case the minibuffer calls these
233 // copied verbatim from do_accent_char
234 view()->cursor().resetAnchor();
235 view()->processUpdateFlags(Update::FitCursor
);
238 //FIXME: bookmark handling is a frontend issue. This code should be transferred
239 // to GuiView and be GuiView and be window dependent.
240 void LyXFunc::gotoBookmark(unsigned int idx
, bool openFile
, bool switchToBuffer
)
242 LASSERT(lyx_view_
, /**/);
243 if (!theSession().bookmarks().isValid(idx
))
245 BookmarksSection::Bookmark
const & bm
= theSession().bookmarks().bookmark(idx
);
246 LASSERT(!bm
.filename
.empty(), /**/);
247 string
const file
= bm
.filename
.absFilename();
248 // if the file is not opened, open it.
249 if (!theBufferList().exists(bm
.filename
)) {
251 dispatch(FuncRequest(LFUN_FILE_OPEN
, file
));
255 // open may fail, so we need to test it again
256 if (!theBufferList().exists(bm
.filename
))
259 // if the current buffer is not that one, switch to it.
260 if (lyx_view_
->buffer()->fileName() != bm
.filename
) {
263 dispatch(FuncRequest(LFUN_BUFFER_SWITCH
, file
));
265 // moveToPosition try paragraph id first and then paragraph (pit, pos).
266 if (!view()->moveToPosition(bm
.bottom_pit
, bm
.bottom_pos
,
267 bm
.top_id
, bm
.top_pos
))
270 // Cursor jump succeeded!
271 Cursor
const & cur
= view()->cursor();
272 pit_type new_pit
= cur
.pit();
273 pos_type new_pos
= cur
.pos();
274 int new_id
= cur
.paragraph().id();
276 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
277 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
278 if (bm
.bottom_pit
!= new_pit
|| bm
.bottom_pos
!= new_pos
279 || bm
.top_id
!= new_id
) {
280 const_cast<BookmarksSection::Bookmark
&>(bm
).updatePos(
281 new_pit
, new_pos
, new_id
);
286 void LyXFunc::processKeySym(KeySymbol
const & keysym
, KeyModifier state
)
288 LYXERR(Debug::KEY
, "KeySym is " << keysym
.getSymbolName());
290 // Do nothing if we have nothing (JMarc)
291 if (!keysym
.isOK()) {
292 LYXERR(Debug::KEY
, "Empty kbd action (probably composing)");
293 lyx_view_
->restartCursor();
297 if (keysym
.isModifier()) {
298 LYXERR(Debug::KEY
, "isModifier true");
300 lyx_view_
->restartCursor();
304 //Encoding const * encoding = view()->cursor().getEncoding();
305 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
306 // FIXME: encoded_last_key shadows the member variable of the same
307 // name. Is that intended?
308 char_type encoded_last_key
= keysym
.getUCSEncoded();
310 // Do a one-deep top-level lookup for
311 // cancel and meta-fake keys. RVDK_PATCH_5
312 cancel_meta_seq
.reset();
314 FuncRequest func
= cancel_meta_seq
.addkey(keysym
, state
);
315 LYXERR(Debug::KEY
, "action first set to [" << func
.action
<< ']');
317 // When not cancel or meta-fake, do the normal lookup.
318 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
319 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
320 if ((func
.action
!= LFUN_CANCEL
) && (func
.action
!= LFUN_META_PREFIX
)) {
321 // remove Caps Lock and Mod2 as a modifiers
322 func
= keyseq
.addkey(keysym
, (state
| meta_fake_bit
));
323 LYXERR(Debug::KEY
, "action now set to [" << func
.action
<< ']');
326 // Dont remove this unless you know what you are doing.
327 meta_fake_bit
= NoModifier
;
329 // Can this happen now ?
330 if (func
.action
== LFUN_NOACTION
)
331 func
= FuncRequest(LFUN_COMMAND_PREFIX
);
333 LYXERR(Debug::KEY
, " Key [action=" << func
.action
<< "]["
334 << keyseq
.print(KeySequence::Portable
) << ']');
336 // already here we know if it any point in going further
337 // why not return already here if action == -1 and
338 // num_bytes == 0? (Lgb)
340 if (keyseq
.length() > 1)
341 lyx_view_
->message(keyseq
.print(KeySequence::ForGui
));
344 // Maybe user can only reach the key via holding down shift.
345 // Let's see. But only if shift is the only modifier
346 if (func
.action
== LFUN_UNKNOWN_ACTION
&& state
== ShiftModifier
) {
347 LYXERR(Debug::KEY
, "Trying without shift");
348 func
= keyseq
.addkey(keysym
, NoModifier
);
349 LYXERR(Debug::KEY
, "Action now " << func
.action
);
352 if (func
.action
== LFUN_UNKNOWN_ACTION
) {
353 // Hmm, we didn't match any of the keysequences. See
354 // if it's normal insertable text not already covered
356 if (keysym
.isText() && keyseq
.length() == 1) {
357 LYXERR(Debug::KEY
, "isText() is true, inserting.");
358 func
= FuncRequest(LFUN_SELF_INSERT
,
359 FuncRequest::KEYBOARD
);
361 LYXERR(Debug::KEY
, "Unknown, !isText() - giving up");
362 lyx_view_
->message(_("Unknown function."));
363 lyx_view_
->restartCursor();
368 if (func
.action
== LFUN_SELF_INSERT
) {
369 if (encoded_last_key
!= 0) {
370 docstring
const arg(1, encoded_last_key
);
371 dispatch(FuncRequest(LFUN_SELF_INSERT
, arg
,
372 FuncRequest::KEYBOARD
));
373 LYXERR(Debug::KEY
, "SelfInsert arg[`" << to_utf8(arg
) << "']");
383 FuncStatus
LyXFunc::getStatus(FuncRequest
const & cmd
) const
385 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
388 Buffer
* buf
= lyx_view_
? lyx_view_
->buffer() : 0;
390 if (cmd
.action
== LFUN_NOACTION
) {
391 flag
.message(from_utf8(N_("Nothing to do")));
392 flag
.setEnabled(false);
396 switch (cmd
.action
) {
397 case LFUN_UNKNOWN_ACTION
:
398 #if !defined(HAVE_LIBMYTHES) && !defined(HAVE_LIBAIKSAURUS)
399 case LFUN_THESAURUS_ENTRY
:
402 flag
.setEnabled(false);
409 if (flag
.unknown()) {
410 flag
.message(from_utf8(N_("Unknown action")));
414 if (!flag
.enabled()) {
415 if (flag
.message().empty())
416 flag
.message(from_utf8(N_("Command disabled")));
420 // Check whether we need a buffer
421 if (!lyxaction
.funcHasFlag(cmd
.action
, LyXAction::NoBuffer
) && !buf
) {
423 flag
.message(from_utf8(N_("Command not allowed with"
424 "out any document open")));
425 flag
.setEnabled(false);
429 // I would really like to avoid having this switch and rather try to
430 // encode this in the function itself.
431 // -- And I'd rather let an inset decide which LFUNs it is willing
432 // to handle (Andre')
434 switch (cmd
.action
) {
436 case LFUN_BUFFER_TOGGLE_READ_ONLY
:
437 flag
.setOnOff(buf
->isReadonly());
440 case LFUN_BUFFER_SWITCH
:
441 // toggle on the current buffer, but do not toggle off
442 // the other ones (is that a good idea?)
443 if (buf
&& to_utf8(cmd
.argument()) == buf
->absFileName())
447 case LFUN_BUFFER_EXPORT
:
448 enable
= cmd
.argument() == "custom"
449 || buf
->isExportable(to_utf8(cmd
.argument()));
452 case LFUN_BUFFER_CHKTEX
:
453 enable
= buf
->isLatex() && !lyxrc
.chktex_command
.empty();
456 case LFUN_BUILD_PROGRAM
:
457 enable
= buf
->isExportable("program");
460 case LFUN_VC_REGISTER
:
461 enable
= !buf
->lyxvc().inUse() && !buf
->isUnnamed();
463 case LFUN_VC_CHECK_IN
:
464 enable
= buf
->lyxvc().checkInEnabled();
466 case LFUN_VC_CHECK_OUT
:
467 enable
= buf
->lyxvc().checkOutEnabled();
470 enable
= buf
->lyxvc().inUse();
472 case LFUN_VC_UNDO_LAST
:
473 enable
= buf
->lyxvc().undoLastEnabled();
475 case LFUN_BUFFER_RELOAD
:
476 enable
= !buf
->isUnnamed() && buf
->fileName().exists()
477 && (!buf
->isClean() || buf
->isExternallyModified(Buffer::timestamp_method
));
480 case LFUN_CITATION_INSERT
: {
481 FuncRequest
fr(LFUN_INSET_INSERT
, "citation");
482 enable
= getStatus(fr
).enabled();
486 // This could be used for the no-GUI version. The GUI version is handled in
487 // LyXView::getStatus(). See above.
489 case LFUN_BUFFER_WRITE:
490 case LFUN_BUFFER_WRITE_AS: {
491 Buffer * b = theBufferList().getBuffer(FileName(cmd.getArg(0)));
492 enable = b && (b->isUnnamed() || !b->isClean());
497 case LFUN_BUFFER_WRITE_ALL
: {
498 // We enable the command only if there are some modified buffers
499 Buffer
* first
= theBufferList().first();
504 // We cannot use a for loop as the buffer list is a cycle.
510 b
= theBufferList().next(b
);
511 } while (b
!= first
);
515 case LFUN_BOOKMARK_GOTO
: {
516 const unsigned int num
= convert
<unsigned int>(to_utf8(cmd
.argument()));
517 enable
= theSession().bookmarks().isValid(num
);
521 case LFUN_BOOKMARK_CLEAR
:
522 enable
= theSession().bookmarks().size() > 0;
525 // this one is difficult to get right. As a half-baked
526 // solution, we consider only the first action of the sequence
527 case LFUN_COMMAND_SEQUENCE
: {
528 // argument contains ';'-terminated commands
529 string
const firstcmd
= token(to_utf8(cmd
.argument()), ';', 0);
530 FuncRequest
func(lyxaction
.lookupFunc(firstcmd
));
531 func
.origin
= cmd
.origin
;
532 flag
= getStatus(func
);
536 // we want to check if at least one of these is enabled
537 case LFUN_COMMAND_ALTERNATIVES
: {
538 // argument contains ';'-terminated commands
539 string arg
= to_utf8(cmd
.argument());
540 while (!arg
.empty()) {
542 arg
= split(arg
, first
, ';');
543 FuncRequest
func(lyxaction
.lookupFunc(first
));
544 func
.origin
= cmd
.origin
;
545 flag
= getStatus(func
);
546 // if this one is enabled, the whole thing is
555 string name
= to_utf8(cmd
.argument());
556 if (theTopLevelCmdDef().lock(name
, func
)) {
557 func
.origin
= cmd
.origin
;
558 flag
= getStatus(func
);
559 theTopLevelCmdDef().release(name
);
561 // catch recursion or unknown command definiton
562 // all operations until the recursion or unknown command
563 // definiton occures are performed, so set the state to enabled
569 case LFUN_WORD_FIND_FORWARD
:
570 case LFUN_WORD_FIND_BACKWARD
:
571 case LFUN_WORD_FINDADV
:
572 case LFUN_COMMAND_PREFIX
:
573 case LFUN_COMMAND_EXECUTE
:
575 case LFUN_META_PREFIX
:
576 case LFUN_BUFFER_CLOSE
:
577 case LFUN_BUFFER_UPDATE
:
578 case LFUN_BUFFER_VIEW
:
579 case LFUN_MASTER_BUFFER_UPDATE
:
580 case LFUN_MASTER_BUFFER_VIEW
:
581 case LFUN_BUFFER_IMPORT
:
582 case LFUN_BUFFER_AUTO_SAVE
:
583 case LFUN_RECONFIGURE
:
585 case LFUN_DROP_LAYOUTS_CHOICE
:
587 case LFUN_SERVER_GET_FILENAME
:
588 case LFUN_SERVER_NOTIFY
:
589 case LFUN_SERVER_GOTO_FILE_ROW
:
590 case LFUN_DIALOG_HIDE
:
591 case LFUN_DIALOG_DISCONNECT_INSET
:
592 case LFUN_BUFFER_CHILD_OPEN
:
593 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE
:
594 case LFUN_KEYMAP_OFF
:
595 case LFUN_KEYMAP_PRIMARY
:
596 case LFUN_KEYMAP_SECONDARY
:
597 case LFUN_KEYMAP_TOGGLE
:
599 case LFUN_BUFFER_EXPORT_CUSTOM
:
600 case LFUN_BUFFER_PRINT
:
601 case LFUN_PREFERENCES_SAVE
:
603 case LFUN_INSET_EDIT
:
604 case LFUN_BUFFER_LANGUAGE
:
605 case LFUN_TEXTCLASS_APPLY
:
606 case LFUN_TEXTCLASS_LOAD
:
607 case LFUN_BUFFER_SAVE_AS_DEFAULT
:
608 case LFUN_BUFFER_PARAMS_APPLY
:
609 case LFUN_LAYOUT_MODULES_CLEAR
:
610 case LFUN_LAYOUT_MODULE_ADD
:
611 case LFUN_LAYOUT_RELOAD
:
612 case LFUN_LYXRC_APPLY
:
613 case LFUN_BUFFER_NEXT
:
614 case LFUN_BUFFER_PREVIOUS
:
615 // these are handled in our dispatch()
623 if (theApp()->getStatus(cmd
, flag
))
626 // Does the view know something?
631 if (lyx_view_
->getStatus(cmd
, flag
))
634 // If we have a BufferView, try cursor position and
635 // then the BufferView.
640 if (!getLocalStatus(view()->cursor(), cmd
, flag
))
641 flag
= view()->getStatus(cmd
);
645 flag
.setEnabled(false);
647 // Can we use a readonly buffer?
648 if (buf
&& buf
->isReadonly()
649 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::ReadOnly
)
650 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::NoBuffer
)) {
651 flag
.message(from_utf8(N_("Document is read-only")));
652 flag
.setEnabled(false);
655 // Are we in a DELETED change-tracking region?
657 && lookupChangeType(view()->cursor(), true) == Change::DELETED
658 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::ReadOnly
)
659 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::NoBuffer
)) {
660 flag
.message(from_utf8(N_("This portion of the document is deleted.")));
661 flag
.setEnabled(false);
664 // the default error message if we disable the command
665 if (!flag
.enabled() && flag
.message().empty())
666 flag
.message(from_utf8(N_("Command disabled")));
672 bool LyXFunc::ensureBufferClean(BufferView
* bv
)
674 Buffer
& buf
= bv
->buffer();
678 docstring
const file
= buf
.fileName().displayName(30);
679 docstring text
= bformat(_("The document %1$s has unsaved "
680 "changes.\n\nDo you want to save "
681 "the document?"), file
);
682 int const ret
= Alert::prompt(_("Save changed document?"),
683 text
, 0, 1, _("&Save"),
687 dispatch(FuncRequest(LFUN_BUFFER_WRITE
));
689 return buf
.isClean();
695 void showPrintError(string
const & name
)
697 docstring str
= bformat(_("Could not print the document %1$s.\n"
698 "Check that your printer is set up correctly."),
699 makeDisplayPath(name
, 50));
700 Alert::error(_("Print document failed"), str
);
704 bool loadLayoutFile(string
const & name
, string
const & buf_path
)
706 if (!LayoutFileList::get().haveClass(name
)) {
707 lyxerr
<< "Document class \"" << name
708 << "\" does not exist."
713 LayoutFile
& tc
= LayoutFileList::get()[name
];
714 if (!tc
.load(buf_path
)) {
715 docstring s
= bformat(_("The document class %1$s "
716 "could not be loaded."), from_utf8(name
));
717 Alert::error(_("Could not load class"), s
);
724 void actOnUpdatedPrefs(LyXRC
const & lyxrc_orig
, LyXRC
const & lyxrc_new
);
729 void LyXFunc::dispatch(FuncRequest
const & cmd
)
731 string
const argument
= to_utf8(cmd
.argument());
732 FuncCode
const action
= cmd
.action
;
734 LYXERR(Debug::ACTION
, "\nLyXFunc::dispatch: cmd: " << cmd
);
735 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
737 // we have not done anything wrong yet.
739 dispatch_buffer
.erase();
741 // redraw the screen at the end (first of the two drawing steps).
742 //This is done unless explicitely requested otherwise
743 Update::flags updateFlags
= Update::FitCursor
;
745 FuncStatus
const flag
= getStatus(cmd
);
746 if (!flag
.enabled()) {
747 // We cannot use this function here
748 LYXERR(Debug::ACTION
, "LyXFunc::dispatch: "
749 << lyxaction
.getActionName(action
)
750 << " [" << action
<< "] is disabled at this location");
751 setErrorMessage(flag
.message());
753 lyx_view_
->restartCursor();
755 Buffer
* buffer
= lyx_view_
? lyx_view_
->buffer() : 0;
758 case LFUN_WORD_FIND_FORWARD
:
759 case LFUN_WORD_FIND_BACKWARD
: {
760 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
761 static docstring last_search
;
762 docstring searched_string
;
764 if (!cmd
.argument().empty()) {
765 last_search
= cmd
.argument();
766 searched_string
= cmd
.argument();
768 searched_string
= last_search
;
771 if (searched_string
.empty())
774 bool const fw
= action
== LFUN_WORD_FIND_FORWARD
;
775 docstring
const data
=
776 find2string(searched_string
, true, false, fw
);
777 find(view(), FuncRequest(LFUN_WORD_FIND
, data
));
781 case LFUN_COMMAND_PREFIX
:
782 LASSERT(lyx_view_
, /**/);
783 lyx_view_
->message(keyseq
.printOptions(true));
787 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
789 meta_fake_bit
= NoModifier
;
791 // cancel any selection
792 dispatch(FuncRequest(LFUN_MARK_OFF
));
793 setMessage(from_ascii(N_("Cancel")));
796 case LFUN_META_PREFIX
:
797 meta_fake_bit
= AltModifier
;
798 setMessage(keyseq
.print(KeySequence::ForGui
));
801 case LFUN_BUFFER_TOGGLE_READ_ONLY
: {
802 LASSERT(lyx_view_
&& lyx_view_
->view() && buffer
, /**/);
803 if (buffer
->lyxvc().inUse())
804 buffer
->lyxvc().toggleReadOnly();
806 buffer
->setReadonly(!buffer
->isReadonly());
810 // --- Menus -----------------------------------------------
811 case LFUN_BUFFER_CLOSE
:
812 lyx_view_
->closeBuffer();
814 updateFlags
= Update::None
;
817 case LFUN_BUFFER_RELOAD
: {
818 LASSERT(lyx_view_
&& buffer
, /**/);
819 docstring
const file
= makeDisplayPath(buffer
->absFileName(), 20);
820 docstring text
= bformat(_("Any changes will be lost. Are you sure "
821 "you want to revert to the saved version of the document %1$s?"), file
);
822 int const ret
= Alert::prompt(_("Revert to saved document?"),
823 text
, 1, 1, _("&Revert"), _("&Cancel"));
830 case LFUN_BUFFER_UPDATE
:
831 LASSERT(lyx_view_
&& buffer
, /**/);
832 buffer
->doExport(argument
, true);
835 case LFUN_BUFFER_VIEW
:
836 LASSERT(lyx_view_
&& buffer
, /**/);
837 buffer
->preview(argument
);
840 case LFUN_MASTER_BUFFER_UPDATE
:
841 LASSERT(lyx_view_
&& buffer
&& buffer
->masterBuffer(), /**/);
842 buffer
->masterBuffer()->doExport(argument
, true);
845 case LFUN_MASTER_BUFFER_VIEW
:
846 LASSERT(lyx_view_
&& buffer
&& buffer
->masterBuffer(), /**/);
847 buffer
->masterBuffer()->preview(argument
);
850 case LFUN_BUILD_PROGRAM
:
851 LASSERT(lyx_view_
&& buffer
, /**/);
852 buffer
->doExport("program", true);
855 case LFUN_BUFFER_CHKTEX
:
856 LASSERT(lyx_view_
&& buffer
, /**/);
860 case LFUN_BUFFER_EXPORT
:
861 LASSERT(lyx_view_
&& buffer
, /**/);
862 if (argument
== "custom")
863 dispatch(FuncRequest(LFUN_DIALOG_SHOW
, "sendto"));
865 buffer
->doExport(argument
, false);
868 case LFUN_BUFFER_EXPORT_CUSTOM
: {
869 LASSERT(lyx_view_
&& buffer
, /**/);
871 string command
= split(argument
, format_name
, ' ');
872 Format
const * format
= formats
.getFormat(format_name
);
874 lyxerr
<< "Format \"" << format_name
875 << "\" not recognized!"
880 // The name of the file created by the conversion process
883 // Output to filename
884 if (format
->name() == "lyx") {
885 string
const latexname
= buffer
->latexName(false);
886 filename
= changeExtension(latexname
,
887 format
->extension());
888 filename
= addName(buffer
->temppath(), filename
);
890 if (!buffer
->writeFile(FileName(filename
)))
894 buffer
->doExport(format_name
, true, filename
);
897 // Substitute $$FName for filename
898 if (!contains(command
, "$$FName"))
899 command
= "( " + command
+ " ) < $$FName";
900 command
= subst(command
, "$$FName", filename
);
902 // Execute the command in the background
904 call
.startscript(Systemcall::DontWait
, command
);
908 case LFUN_BUFFER_PRINT
: {
909 LASSERT(lyx_view_
&& buffer
, /**/);
910 // FIXME: cmd.getArg() might fail if one of the arguments
911 // contains double quotes
912 string target
= cmd
.getArg(0);
913 string target_name
= cmd
.getArg(1);
914 string command
= cmd
.getArg(2);
917 || target_name
.empty()
918 || command
.empty()) {
919 lyxerr
<< "Unable to parse \""
920 << argument
<< '"' << endl
;
923 if (target
!= "printer" && target
!= "file") {
924 lyxerr
<< "Unrecognized target \""
925 << target
<< '"' << endl
;
929 if (!buffer
->doExport("dvi", true)) {
930 showPrintError(buffer
->absFileName());
934 // Push directory path.
935 string
const path
= buffer
->temppath();
936 // Prevent the compiler from optimizing away p
940 // there are three cases here:
941 // 1. we print to a file
942 // 2. we print directly to a printer
943 // 3. we print using a spool command (print to file first)
946 string
const dviname
=
947 changeExtension(buffer
->latexName(true), "dvi");
949 if (target
== "printer") {
950 if (!lyxrc
.print_spool_command
.empty()) {
951 // case 3: print using a spool
952 string
const psname
=
953 changeExtension(dviname
,".ps");
954 command
+= ' ' + lyxrc
.print_to_file
957 + quoteName(dviname
);
960 lyxrc
.print_spool_command
+ ' ';
961 if (target_name
!= "default") {
962 command2
+= lyxrc
.print_spool_printerprefix
966 command2
+= quoteName(psname
);
968 // If successful, then spool command
969 res
= one
.startscript(
974 res
= one
.startscript(
975 Systemcall::DontWait
,
978 // case 2: print directly to a printer
979 if (target_name
!= "default")
980 command
+= ' ' + lyxrc
.print_to_printer
+ target_name
+ ' ';
981 res
= one
.startscript(
982 Systemcall::DontWait
,
983 command
+ quoteName(dviname
));
987 // case 1: print to a file
988 FileName
const filename(makeAbsPath(target_name
,
989 buffer
->filePath()));
990 FileName
const dvifile(makeAbsPath(dviname
, path
));
991 if (filename
.exists()) {
992 docstring text
= bformat(
993 _("The file %1$s already exists.\n\n"
994 "Do you want to overwrite that file?"),
995 makeDisplayPath(filename
.absFilename()));
996 if (Alert::prompt(_("Overwrite file?"),
997 text
, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1000 command
+= ' ' + lyxrc
.print_to_file
1001 + quoteName(filename
.toFilesystemEncoding())
1003 + quoteName(dvifile
.toFilesystemEncoding());
1004 res
= one
.startscript(Systemcall::DontWait
,
1009 showPrintError(buffer
->absFileName());
1013 // FIXME: There is need for a command-line import.
1015 case LFUN_BUFFER_IMPORT:
1020 case LFUN_BUFFER_AUTO_SAVE
:
1024 case LFUN_RECONFIGURE
:
1025 // argument is any additional parameter to the configure.py command
1026 reconfigure(lyx_view_
, argument
);
1029 case LFUN_HELP_OPEN
: {
1031 theApp()->dispatch(FuncRequest(LFUN_WINDOW_NEW
));
1032 string
const arg
= argument
;
1034 setErrorMessage(from_ascii(N_("Missing argument")));
1037 FileName
const fname
= i18nLibFileSearch("doc", arg
, "lyx");
1038 if (fname
.empty()) {
1039 lyxerr
<< "LyX: unable to find documentation file `"
1040 << arg
<< "'. Bad installation?" << endl
;
1043 lyx_view_
->message(bformat(_("Opening help file %1$s..."),
1044 makeDisplayPath(fname
.absFilename())));
1045 Buffer
* buf
= lyx_view_
->loadDocument(fname
, false);
1047 buf
->updateLabels();
1048 lyx_view_
->setBuffer(buf
);
1049 buf
->errors("Parse");
1051 updateFlags
= Update::None
;
1055 // --- version control -------------------------------
1056 case LFUN_VC_REGISTER
:
1057 LASSERT(lyx_view_
&& buffer
, /**/);
1058 if (!ensureBufferClean(view()) || buffer
->isUnnamed())
1060 if (!buffer
->lyxvc().inUse()) {
1061 buffer
->lyxvc().registrer();
1064 updateFlags
= Update::Force
;
1067 case LFUN_VC_CHECK_IN
:
1068 LASSERT(lyx_view_
&& buffer
, /**/);
1069 if (!ensureBufferClean(view()))
1071 if (buffer
->lyxvc().inUse()
1072 && !buffer
->isReadonly()) {
1073 setMessage(from_utf8(buffer
->lyxvc().checkIn()));
1078 case LFUN_VC_CHECK_OUT
:
1079 LASSERT(lyx_view_
&& buffer
, /**/);
1080 if (!ensureBufferClean(view()))
1082 if (buffer
->lyxvc().inUse()) {
1083 setMessage(from_utf8(buffer
->lyxvc().checkOut()));
1088 case LFUN_VC_REVERT
:
1089 LASSERT(lyx_view_
&& buffer
, /**/);
1090 buffer
->lyxvc().revert();
1094 case LFUN_VC_UNDO_LAST
:
1095 LASSERT(lyx_view_
&& buffer
, /**/);
1096 buffer
->lyxvc().undoLast();
1100 // --- lyxserver commands ----------------------------
1101 case LFUN_SERVER_GET_FILENAME
:
1102 LASSERT(lyx_view_
&& buffer
, /**/);
1103 setMessage(from_utf8(buffer
->absFileName()));
1104 LYXERR(Debug::INFO
, "FNAME["
1105 << buffer
->absFileName() << ']');
1108 case LFUN_SERVER_NOTIFY
:
1109 dispatch_buffer
= keyseq
.print(KeySequence::Portable
);
1110 theServer().notifyClient(to_utf8(dispatch_buffer
));
1113 case LFUN_SERVER_GOTO_FILE_ROW
: {
1114 LASSERT(lyx_view_
, /**/);
1117 istringstream
is(argument
);
1118 is
>> file_name
>> row
;
1120 bool loaded
= false;
1121 if (prefixIs(file_name
, package().temp_dir().absFilename()))
1122 // Needed by inverse dvi search. If it is a file
1123 // in tmpdir, call the apropriated function
1124 buf
= theBufferList().getBufferFromTmp(file_name
);
1126 // Must replace extension of the file to be .lyx
1127 // and get full path
1128 FileName
const s
= fileSearch(string(), changeExtension(file_name
, ".lyx"), "lyx");
1129 // Either change buffer or load the file
1130 if (theBufferList().exists(s
))
1131 buf
= theBufferList().getBuffer(s
);
1133 buf
= lyx_view_
->loadDocument(s
);
1139 updateFlags
= Update::None
;
1143 buf
->updateLabels();
1144 lyx_view_
->setBuffer(buf
);
1145 view()->setCursorFromRow(row
);
1147 buf
->errors("Parse");
1148 updateFlags
= Update::FitCursor
;
1153 case LFUN_DIALOG_SHOW_NEW_INSET
: {
1154 LASSERT(lyx_view_
, /**/);
1155 string
const name
= cmd
.getArg(0);
1156 InsetCode code
= insetCode(name
);
1157 string data
= trim(to_utf8(cmd
.argument()).substr(name
.size()));
1158 bool insetCodeOK
= true;
1167 case HYPERLINK_CODE
: {
1168 InsetCommandParams
p(code
);
1169 data
= InsetCommand::params2string(name
, p
);
1172 case INCLUDE_CODE
: {
1173 // data is the include type: one of "include",
1174 // "input", "verbatiminput" or "verbatiminput*"
1176 // default type is requested
1178 InsetCommandParams
p(INCLUDE_CODE
, data
);
1179 data
= InsetCommand::params2string("include", p
);
1183 // \c data == "Boxed" || "Frameless" etc
1184 InsetBoxParams
p(data
);
1185 data
= InsetBox::params2string(p
);
1189 InsetBranchParams p
;
1190 data
= InsetBranch::params2string(p
);
1194 InsetCommandParams
p(CITE_CODE
);
1195 data
= InsetCommand::params2string(name
, p
);
1199 data
= InsetERT::params2string(InsetCollapsable::Open
);
1202 case EXTERNAL_CODE
: {
1203 InsetExternalParams p
;
1204 data
= InsetExternal::params2string(p
, *buffer
);
1209 data
= InsetFloat::params2string(p
);
1212 case LISTINGS_CODE
: {
1213 InsetListingsParams p
;
1214 data
= InsetListings::params2string(p
);
1217 case GRAPHICS_CODE
: {
1218 InsetGraphicsParams p
;
1219 data
= InsetGraphics::params2string(p
, *buffer
);
1224 data
= InsetNote::params2string(p
);
1229 data
= InsetSpace::params2string(p
);
1234 data
= InsetVSpace::params2string(space
);
1239 data
= InsetWrap::params2string(p
);
1243 lyxerr
<< "Inset type '" << name
<<
1244 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << endl
;
1245 insetCodeOK
= false;
1247 } // end switch(code)
1249 dispatch(FuncRequest(LFUN_DIALOG_SHOW
, name
+ " " + data
));
1253 case LFUN_CITATION_INSERT
: {
1254 LASSERT(lyx_view_
, /**/);
1255 if (!argument
.empty()) {
1256 // we can have one optional argument, delimited by '|'
1257 // citation-insert <key>|<text_before>
1258 // this should be enhanced to also support text_after
1259 // and citation style
1260 string arg
= argument
;
1262 if (contains(argument
, "|")) {
1263 arg
= token(argument
, '|', 0);
1264 opt1
= token(argument
, '|', 1);
1266 InsetCommandParams
icp(CITE_CODE
);
1267 icp
["key"] = from_utf8(arg
);
1269 icp
["before"] = from_utf8(opt1
);
1270 string icstr
= InsetCommand::params2string("citation", icp
);
1271 FuncRequest
fr(LFUN_INSET_INSERT
, icstr
);
1274 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET
, "citation"));
1278 case LFUN_BUFFER_CHILD_OPEN
: {
1279 LASSERT(lyx_view_
&& buffer
, /**/);
1280 FileName filename
= makeAbsPath(argument
, buffer
->filePath());
1281 view()->saveBookmark(false);
1283 bool parsed
= false;
1284 if (theBufferList().exists(filename
)) {
1285 child
= theBufferList().getBuffer(filename
);
1287 setMessage(bformat(_("Opening child document %1$s..."),
1288 makeDisplayPath(filename
.absFilename())));
1289 child
= lyx_view_
->loadDocument(filename
, false);
1293 // Set the parent name of the child document.
1294 // This makes insertion of citations and references in the child work,
1295 // when the target is in the parent or another child document.
1296 child
->setParent(buffer
);
1297 child
->masterBuffer()->updateLabels();
1298 lyx_view_
->setBuffer(child
);
1300 child
->errors("Parse");
1303 // If a screen update is required (in case where auto_open is false),
1304 // setBuffer() would have taken care of it already. Otherwise we shall
1305 // reset the update flag because it can cause a circular problem.
1307 updateFlags
= Update::None
;
1311 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE
:
1312 LASSERT(lyx_view_
, /**/);
1313 lyxrc
.cursor_follows_scrollbar
= !lyxrc
.cursor_follows_scrollbar
;
1316 case LFUN_KEYMAP_OFF
:
1317 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1318 lyx_view_
->view()->getIntl().keyMapOn(false);
1321 case LFUN_KEYMAP_PRIMARY
:
1322 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1323 lyx_view_
->view()->getIntl().keyMapPrim();
1326 case LFUN_KEYMAP_SECONDARY
:
1327 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1328 lyx_view_
->view()->getIntl().keyMapSec();
1331 case LFUN_KEYMAP_TOGGLE
:
1332 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1333 lyx_view_
->view()->getIntl().toggleKeyMap();
1339 string rest
= split(argument
, countstr
, ' ');
1340 istringstream
is(countstr
);
1343 //lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1344 for (int i
= 0; i
< count
; ++i
)
1345 dispatch(lyxaction
.lookupFunc(rest
));
1349 case LFUN_COMMAND_SEQUENCE
: {
1350 // argument contains ';'-terminated commands
1351 string arg
= argument
;
1352 if (theBufferList().isLoaded(buffer
))
1353 buffer
->undo().beginUndoGroup();
1354 while (!arg
.empty()) {
1356 arg
= split(arg
, first
, ';');
1357 FuncRequest
func(lyxaction
.lookupFunc(first
));
1358 func
.origin
= cmd
.origin
;
1361 if (theBufferList().isLoaded(buffer
))
1362 buffer
->undo().endUndoGroup();
1366 case LFUN_COMMAND_ALTERNATIVES
: {
1367 // argument contains ';'-terminated commands
1368 string arg
= argument
;
1369 while (!arg
.empty()) {
1371 arg
= split(arg
, first
, ';');
1372 FuncRequest
func(lyxaction
.lookupFunc(first
));
1373 func
.origin
= cmd
.origin
;
1374 FuncStatus stat
= getStatus(func
);
1375 if (stat
.enabled()) {
1385 if (theTopLevelCmdDef().lock(argument
, func
)) {
1386 func
.origin
= cmd
.origin
;
1388 theTopLevelCmdDef().release(argument
);
1390 if (func
.action
== LFUN_UNKNOWN_ACTION
) {
1391 // unknown command definition
1392 lyxerr
<< "Warning: unknown command definition `"
1396 // recursion detected
1397 lyxerr
<< "Warning: Recursion in the command definition `"
1398 << argument
<< "' detected"
1405 case LFUN_PREFERENCES_SAVE
: {
1406 lyxrc
.write(makeAbsPath("preferences",
1407 package().user_support().absFilename()),
1413 LASSERT(lyx_view_
, /**/);
1414 lyx_view_
->message(from_utf8(argument
));
1417 case LFUN_BUFFER_LANGUAGE
: {
1418 LASSERT(lyx_view_
, /**/);
1419 Language
const * oldL
= buffer
->params().language
;
1420 Language
const * newL
= languages
.getLanguage(argument
);
1421 if (!newL
|| oldL
== newL
)
1424 if (oldL
->rightToLeft() == newL
->rightToLeft()
1425 && !buffer
->isMultiLingual())
1426 buffer
->changeLanguage(oldL
, newL
);
1430 case LFUN_BUFFER_SAVE_AS_DEFAULT
: {
1431 string
const fname
=
1432 addName(addPath(package().user_support().absFilename(), "templates/"),
1434 Buffer
defaults(fname
);
1436 istringstream
ss(argument
);
1439 int const unknown_tokens
= defaults
.readHeader(lex
);
1441 if (unknown_tokens
!= 0) {
1442 lyxerr
<< "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1443 << unknown_tokens
<< " unknown token"
1444 << (unknown_tokens
== 1 ? "" : "s")
1448 if (defaults
.writeFile(FileName(defaults
.absFileName())))
1449 setMessage(bformat(_("Document defaults saved in %1$s"),
1450 makeDisplayPath(fname
)));
1452 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1456 case LFUN_BUFFER_PARAMS_APPLY
: {
1457 LASSERT(lyx_view_
, /**/);
1459 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1460 Cursor
& cur
= view()->cursor();
1461 cur
.recordUndoFullDocument();
1463 istringstream
ss(argument
);
1466 int const unknown_tokens
= buffer
->readHeader(lex
);
1468 if (unknown_tokens
!= 0) {
1469 lyxerr
<< "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1470 << unknown_tokens
<< " unknown token"
1471 << (unknown_tokens
== 1 ? "" : "s")
1475 updateLayout(oldClass
, buffer
);
1477 updateFlags
= Update::Force
| Update::FitCursor
;
1478 // We are most certainly here because of a change in the document
1479 // It is then better to make sure that all dialogs are in sync with
1480 // current document settings. LyXView::restartCursor() achieve this.
1481 lyx_view_
->restartCursor();
1485 case LFUN_LAYOUT_MODULES_CLEAR
: {
1486 LASSERT(lyx_view_
, /**/);
1487 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1488 view()->cursor().recordUndoFullDocument();
1489 buffer
->params().clearLayoutModules();
1490 buffer
->params().makeDocumentClass();
1491 updateLayout(oldClass
, buffer
);
1492 updateFlags
= Update::Force
| Update::FitCursor
;
1496 case LFUN_LAYOUT_MODULE_ADD
: {
1497 LASSERT(lyx_view_
, /**/);
1498 BufferParams
const & params
= buffer
->params();
1499 if (!params
.moduleCanBeAdded(argument
)) {
1500 LYXERR0("Module `" << argument
<<
1501 "' cannot be added due to failed requirements or "
1502 "conflicts with installed modules.");
1505 DocumentClass
const * const oldClass
= params
.documentClassPtr();
1506 view()->cursor().recordUndoFullDocument();
1507 buffer
->params().addLayoutModule(argument
);
1508 buffer
->params().makeDocumentClass();
1509 updateLayout(oldClass
, buffer
);
1510 updateFlags
= Update::Force
| Update::FitCursor
;
1514 case LFUN_TEXTCLASS_APPLY
: {
1515 LASSERT(lyx_view_
, /**/);
1517 if (!loadLayoutFile(argument
, buffer
->temppath()) &&
1518 !loadLayoutFile(argument
, buffer
->filePath()))
1521 LayoutFile
const * old_layout
= buffer
->params().baseClass();
1522 LayoutFile
const * new_layout
= &(LayoutFileList::get()[argument
]);
1524 if (old_layout
== new_layout
)
1528 //Save the old, possibly modular, layout for use in conversion.
1529 DocumentClass
const * const oldDocClass
= buffer
->params().documentClassPtr();
1530 view()->cursor().recordUndoFullDocument();
1531 buffer
->params().setBaseClass(argument
);
1532 buffer
->params().makeDocumentClass();
1533 updateLayout(oldDocClass
, buffer
);
1534 updateFlags
= Update::Force
| Update::FitCursor
;
1538 case LFUN_LAYOUT_RELOAD
: {
1539 LASSERT(lyx_view_
, /**/);
1540 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1541 LayoutFileIndex bc
= buffer
->params().baseClassID();
1542 LayoutFileList::get().reset(bc
);
1543 buffer
->params().setBaseClass(bc
);
1544 buffer
->params().makeDocumentClass();
1545 updateLayout(oldClass
, buffer
);
1546 updateFlags
= Update::Force
| Update::FitCursor
;
1550 case LFUN_TEXTCLASS_LOAD
:
1551 loadLayoutFile(argument
, buffer
->temppath()) ||
1552 loadLayoutFile(argument
, buffer
->filePath());
1555 case LFUN_LYXRC_APPLY
: {
1556 LyXRC
const lyxrc_orig
= lyxrc
;
1558 istringstream
ss(argument
);
1559 bool const success
= lyxrc
.read(ss
) == 0;
1562 lyxerr
<< "Warning in LFUN_LYXRC_APPLY!\n"
1563 << "Unable to read lyxrc data"
1568 actOnUpdatedPrefs(lyxrc_orig
, lyxrc
);
1570 theApp()->resetGui();
1572 /// We force the redraw in any case because there might be
1573 /// some screen font changes.
1574 /// FIXME: only the current view will be updated. the Gui
1575 /// class is able to furnish the list of views.
1576 updateFlags
= Update::Force
;
1580 case LFUN_BOOKMARK_GOTO
:
1581 // go to bookmark, open unopened file and switch to buffer if necessary
1582 gotoBookmark(convert
<unsigned int>(to_utf8(cmd
.argument())), true, true);
1583 updateFlags
= Update::FitCursor
;
1586 case LFUN_BOOKMARK_CLEAR
:
1587 theSession().bookmarks().clear();
1591 LASSERT(theApp(), /**/);
1592 // Let the frontend dispatch its own actions.
1593 if (theApp()->dispatch(cmd
))
1594 // Nothing more to do.
1597 // Everything below is only for active lyx_view_
1601 // Start an undo group. This may be needed for
1602 // some stuff like inset-apply on labels.
1603 if (theBufferList().isLoaded(buffer
))
1604 buffer
->undo().beginUndoGroup();
1606 // Let the current LyXView dispatch its own actions.
1607 if (lyx_view_
->dispatch(cmd
)) {
1608 if (lyx_view_
->view()) {
1609 updateFlags
= lyx_view_
->view()->cursor().result().update();
1610 if (theBufferList().isLoaded(buffer
))
1611 buffer
->undo().endUndoGroup();
1616 LASSERT(lyx_view_
->view(), /**/);
1618 // Let the current BufferView dispatch its own actions.
1619 if (view()->dispatch(cmd
)) {
1620 // The BufferView took care of its own updates if needed.
1621 updateFlags
= Update::None
;
1622 if (theBufferList().isLoaded(buffer
))
1623 buffer
->undo().endUndoGroup();
1627 // Let the current Cursor dispatch its own actions.
1628 Cursor old
= view()->cursor();
1629 view()->cursor().getPos(cursorPosBeforeDispatchX_
,
1630 cursorPosBeforeDispatchY_
);
1631 view()->cursor().dispatch(cmd
);
1633 // notify insets we just left
1634 if (view()->cursor() != old
) {
1636 bool badcursor
= notifyCursorLeavesOrEnters(old
, view()->cursor());
1638 view()->cursor().fixIfBroken();
1641 if (theBufferList().isLoaded(buffer
))
1642 buffer
->undo().endUndoGroup();
1644 // update completion. We do it here and not in
1645 // processKeySym to avoid another redraw just for a
1646 // changed inline completion
1647 if (cmd
.origin
== FuncRequest::KEYBOARD
) {
1648 if (cmd
.action
== LFUN_SELF_INSERT
)
1649 lyx_view_
->updateCompletion(view()->cursor(), true, true);
1650 else if (cmd
.action
== LFUN_CHAR_DELETE_BACKWARD
)
1651 lyx_view_
->updateCompletion(view()->cursor(), false, true);
1653 lyx_view_
->updateCompletion(view()->cursor(), false, false);
1656 updateFlags
= view()->cursor().result().update();
1659 // if we executed a mutating lfun, mark the buffer as dirty
1660 if (theBufferList().isLoaded(buffer
) && flag
.enabled()
1661 && !lyxaction
.funcHasFlag(action
, LyXAction::NoBuffer
)
1662 && !lyxaction
.funcHasFlag(action
, LyXAction::ReadOnly
))
1663 buffer
->markDirty();
1665 if (lyx_view_
&& lyx_view_
->buffer()) {
1666 // BufferView::update() updates the ViewMetricsInfo and
1667 // also initializes the position cache for all insets in
1668 // (at least partially) visible top-level paragraphs.
1669 // We will redraw the screen only if needed.
1670 view()->processUpdateFlags(updateFlags
);
1672 // Do we have a selection?
1673 theSelection().haveSelection(view()->cursor().selection());
1676 lyx_view_
->restartCursor();
1680 // Some messages may already be translated, so we cannot use _()
1681 sendDispatchMessage(translateIfPossible(getMessage()), cmd
);
1686 void LyXFunc::sendDispatchMessage(docstring
const & msg
, FuncRequest
const & cmd
)
1688 const bool verbose
= (cmd
.origin
== FuncRequest::MENU
1689 || cmd
.origin
== FuncRequest::TOOLBAR
1690 || cmd
.origin
== FuncRequest::COMMANDBUFFER
);
1692 if (cmd
.action
== LFUN_SELF_INSERT
|| !verbose
) {
1693 LYXERR(Debug::ACTION
, "dispatch msg is " << to_utf8(msg
));
1695 lyx_view_
->message(msg
);
1699 docstring dispatch_msg
= msg
;
1700 if (!dispatch_msg
.empty())
1701 dispatch_msg
+= ' ';
1703 docstring comname
= from_utf8(lyxaction
.getActionName(cmd
.action
));
1705 bool argsadded
= false;
1707 if (!cmd
.argument().empty()) {
1708 if (cmd
.action
!= LFUN_UNKNOWN_ACTION
) {
1709 comname
+= ' ' + cmd
.argument();
1714 docstring
const shortcuts
= theTopLevelKeymap().printBindings(cmd
, KeySequence::ForGui
);
1716 if (!shortcuts
.empty())
1717 comname
+= ": " + shortcuts
;
1718 else if (!argsadded
&& !cmd
.argument().empty())
1719 comname
+= ' ' + cmd
.argument();
1721 if (!comname
.empty()) {
1722 comname
= rtrim(comname
);
1723 dispatch_msg
+= '(' + rtrim(comname
) + ')';
1726 LYXERR(Debug::ACTION
, "verbose dispatch msg " << to_utf8(dispatch_msg
));
1727 if (!dispatch_msg
.empty())
1728 lyx_view_
->message(dispatch_msg
);
1732 void LyXFunc::reloadBuffer()
1734 FileName filename
= lyx_view_
->buffer()->fileName();
1735 // The user has already confirmed that the changes, if any, should
1736 // be discarded. So we just release the Buffer and don't call closeBuffer();
1737 theBufferList().release(lyx_view_
->buffer());
1738 // if the lyx_view_ has been destroyed, create a new one
1740 theApp()->dispatch(FuncRequest(LFUN_WINDOW_NEW
));
1741 Buffer
* buf
= lyx_view_
->loadDocument(filename
);
1742 docstring
const disp_fn
= makeDisplayPath(filename
.absFilename());
1745 buf
->updateLabels();
1746 lyx_view_
->setBuffer(buf
);
1747 buf
->errors("Parse");
1748 str
= bformat(_("Document %1$s reloaded."), disp_fn
);
1750 str
= bformat(_("Could not reload document %1$s"), disp_fn
);
1752 lyx_view_
->message(str
);
1755 // Each "lyx_view_" should have it's own message method. lyxview and
1756 // the minibuffer would use the minibuffer, but lyxserver would
1757 // send an ERROR signal to its client. Alejandro 970603
1758 // This function is bit problematic when it comes to NLS, to make the
1759 // lyx servers client be language indepenent we must not translate
1760 // strings sent to this func.
1761 void LyXFunc::setErrorMessage(docstring
const & m
) const
1763 dispatch_buffer
= m
;
1768 void LyXFunc::setMessage(docstring
const & m
) const
1770 dispatch_buffer
= m
;
1774 docstring
LyXFunc::viewStatusMessage()
1776 // When meta-fake key is pressed, show the key sequence so far + "M-".
1778 return keyseq
.print(KeySequence::ForGui
) + "M-";
1780 // Else, when a non-complete key sequence is pressed,
1781 // show the available options.
1782 if (keyseq
.length() > 0 && !keyseq
.deleted())
1783 return keyseq
.printOptions(true);
1785 LASSERT(lyx_view_
, /**/);
1786 if (!lyx_view_
->buffer())
1787 return _("Welcome to LyX!");
1789 return view()->cursor().currentState();
1793 BufferView
* LyXFunc::view() const
1795 LASSERT(lyx_view_
, /**/);
1796 return lyx_view_
->view();
1800 bool LyXFunc::wasMetaKey() const
1802 return (meta_fake_bit
!= NoModifier
);
1806 void LyXFunc::updateLayout(DocumentClass
const * const oldlayout
, Buffer
* buf
)
1808 lyx_view_
->message(_("Converting document to new document class..."));
1810 StableDocIterator
backcur(view()->cursor());
1811 ErrorList
& el
= buf
->errorList("Class Switch");
1812 cap::switchBetweenClasses(
1813 oldlayout
, buf
->params().documentClassPtr(),
1814 static_cast<InsetText
&>(buf
->inset()), el
);
1816 view()->setCursor(backcur
.asDocIterator(buf
));
1818 buf
->errors("Class Switch");
1819 buf
->updateLabels();
1825 void actOnUpdatedPrefs(LyXRC
const & lyxrc_orig
, LyXRC
const & lyxrc_new
)
1827 // Why the switch you might ask. It is a trick to ensure that all
1828 // the elements in the LyXRCTags enum is handled. As you can see
1829 // there are no breaks at all. So it is just a huge fall-through.
1830 // The nice thing is that we will get a warning from the compiler
1831 // if we forget an element.
1832 LyXRC::LyXRCTags tag
= LyXRC::RC_LAST
;
1834 case LyXRC::RC_ACCEPT_COMPOUND
:
1835 case LyXRC::RC_ALT_LANG
:
1836 case LyXRC::RC_PLAINTEXT_LINELEN
:
1837 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND
:
1838 case LyXRC::RC_AUTOREGIONDELETE
:
1839 case LyXRC::RC_AUTORESET_OPTIONS
:
1840 case LyXRC::RC_AUTOSAVE
:
1841 case LyXRC::RC_AUTO_NUMBER
:
1842 case LyXRC::RC_BACKUPDIR_PATH
:
1843 case LyXRC::RC_BIBTEX_COMMAND
:
1844 case LyXRC::RC_BINDFILE
:
1845 case LyXRC::RC_CHECKLASTFILES
:
1846 case LyXRC::RC_COMPLETION_CURSOR_TEXT
:
1847 case LyXRC::RC_COMPLETION_INLINE_DELAY
:
1848 case LyXRC::RC_COMPLETION_INLINE_DOTS
:
1849 case LyXRC::RC_COMPLETION_INLINE_MATH
:
1850 case LyXRC::RC_COMPLETION_INLINE_TEXT
:
1851 case LyXRC::RC_COMPLETION_POPUP_AFTER_COMPLETE
:
1852 case LyXRC::RC_COMPLETION_POPUP_DELAY
:
1853 case LyXRC::RC_COMPLETION_POPUP_MATH
:
1854 case LyXRC::RC_COMPLETION_POPUP_TEXT
:
1855 case LyXRC::RC_USELASTFILEPOS
:
1856 case LyXRC::RC_LOADSESSION
:
1857 case LyXRC::RC_CHKTEX_COMMAND
:
1858 case LyXRC::RC_CONVERTER
:
1859 case LyXRC::RC_CONVERTER_CACHE_MAXAGE
:
1860 case LyXRC::RC_COPIER
:
1861 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR
:
1862 case LyXRC::RC_CUSTOM_EXPORT_COMMAND
:
1863 case LyXRC::RC_CUSTOM_EXPORT_FORMAT
:
1864 case LyXRC::RC_DATE_INSERT_FORMAT
:
1865 case LyXRC::RC_DEFAULT_LANGUAGE
:
1866 case LyXRC::RC_GUI_LANGUAGE
:
1867 case LyXRC::RC_DEFAULT_PAPERSIZE
:
1868 case LyXRC::RC_DEFFILE
:
1869 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN
:
1870 case LyXRC::RC_DISPLAY_GRAPHICS
:
1871 case LyXRC::RC_DOCUMENTPATH
:
1872 if (lyxrc_orig
.document_path
!= lyxrc_new
.document_path
) {
1873 FileName
path(lyxrc_new
.document_path
);
1874 if (path
.exists() && path
.isDirectory())
1875 package().document_dir() = FileName(lyxrc
.document_path
);
1877 case LyXRC::RC_ESC_CHARS
:
1878 case LyXRC::RC_EXAMPLEPATH
:
1879 case LyXRC::RC_FONT_ENCODING
:
1880 case LyXRC::RC_FORMAT
:
1881 case LyXRC::RC_GROUP_LAYOUTS
:
1882 case LyXRC::RC_INDEX_COMMAND
:
1883 case LyXRC::RC_NOMENCL_COMMAND
:
1884 case LyXRC::RC_INPUT
:
1885 case LyXRC::RC_KBMAP
:
1886 case LyXRC::RC_KBMAP_PRIMARY
:
1887 case LyXRC::RC_KBMAP_SECONDARY
:
1888 case LyXRC::RC_LABEL_INIT_LENGTH
:
1889 case LyXRC::RC_LANGUAGE_AUTO_BEGIN
:
1890 case LyXRC::RC_LANGUAGE_AUTO_END
:
1891 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN
:
1892 case LyXRC::RC_LANGUAGE_COMMAND_END
:
1893 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL
:
1894 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS
:
1895 case LyXRC::RC_LANGUAGE_PACKAGE
:
1896 case LyXRC::RC_LANGUAGE_USE_BABEL
:
1897 case LyXRC::RC_MAC_LIKE_WORD_MOVEMENT
:
1898 case LyXRC::RC_MACRO_EDIT_STYLE
:
1899 case LyXRC::RC_MAKE_BACKUP
:
1900 case LyXRC::RC_MARK_FOREIGN_LANGUAGE
:
1901 case LyXRC::RC_MOUSE_WHEEL_SPEED
:
1902 case LyXRC::RC_NUMLASTFILES
:
1903 case LyXRC::RC_PATH_PREFIX
:
1904 if (lyxrc_orig
.path_prefix
!= lyxrc_new
.path_prefix
) {
1905 prependEnvPath("PATH", lyxrc
.path_prefix
);
1907 case LyXRC::RC_PERS_DICT
:
1908 case LyXRC::RC_PREVIEW
:
1909 case LyXRC::RC_PREVIEW_HASHED_LABELS
:
1910 case LyXRC::RC_PREVIEW_SCALE_FACTOR
:
1911 case LyXRC::RC_PRINTCOLLCOPIESFLAG
:
1912 case LyXRC::RC_PRINTCOPIESFLAG
:
1913 case LyXRC::RC_PRINTER
:
1914 case LyXRC::RC_PRINTEVENPAGEFLAG
:
1915 case LyXRC::RC_PRINTEXSTRAOPTIONS
:
1916 case LyXRC::RC_PRINTFILEEXTENSION
:
1917 case LyXRC::RC_PRINTLANDSCAPEFLAG
:
1918 case LyXRC::RC_PRINTODDPAGEFLAG
:
1919 case LyXRC::RC_PRINTPAGERANGEFLAG
:
1920 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG
:
1921 case LyXRC::RC_PRINTPAPERFLAG
:
1922 case LyXRC::RC_PRINTREVERSEFLAG
:
1923 case LyXRC::RC_PRINTSPOOL_COMMAND
:
1924 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX
:
1925 case LyXRC::RC_PRINTTOFILE
:
1926 case LyXRC::RC_PRINTTOPRINTER
:
1927 case LyXRC::RC_PRINT_ADAPTOUTPUT
:
1928 case LyXRC::RC_PRINT_COMMAND
:
1929 case LyXRC::RC_RTL_SUPPORT
:
1930 case LyXRC::RC_SCREEN_DPI
:
1931 case LyXRC::RC_SCREEN_FONT_ROMAN
:
1932 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY
:
1933 case LyXRC::RC_SCREEN_FONT_SANS
:
1934 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY
:
1935 case LyXRC::RC_SCREEN_FONT_SCALABLE
:
1936 case LyXRC::RC_SCREEN_FONT_SIZES
:
1937 case LyXRC::RC_SCREEN_FONT_TYPEWRITER
:
1938 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY
:
1939 case LyXRC::RC_GEOMETRY_SESSION
:
1940 case LyXRC::RC_SCREEN_ZOOM
:
1941 case LyXRC::RC_SERVERPIPE
:
1942 case LyXRC::RC_SET_COLOR
:
1943 case LyXRC::RC_SHOW_BANNER
:
1944 case LyXRC::RC_OPEN_BUFFERS_IN_TABS
:
1945 case LyXRC::RC_SPELL_COMMAND
:
1946 case LyXRC::RC_TEMPDIRPATH
:
1947 case LyXRC::RC_TEMPLATEPATH
:
1948 case LyXRC::RC_TEX_ALLOWS_SPACES
:
1949 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS
:
1950 if (lyxrc_orig
.windows_style_tex_paths
!= lyxrc_new
.windows_style_tex_paths
) {
1951 os::windows_style_tex_paths(lyxrc_new
.windows_style_tex_paths
);
1953 case LyXRC::RC_THESAURUSDIRPATH
:
1954 case LyXRC::RC_UIFILE
:
1955 case LyXRC::RC_USER_EMAIL
:
1956 case LyXRC::RC_USER_NAME
:
1957 case LyXRC::RC_USETEMPDIR
:
1958 case LyXRC::RC_USE_ALT_LANG
:
1959 case LyXRC::RC_USE_CONVERTER_CACHE
:
1960 case LyXRC::RC_USE_ESC_CHARS
:
1961 case LyXRC::RC_USE_INP_ENC
:
1962 case LyXRC::RC_USE_PERS_DICT
:
1963 case LyXRC::RC_USE_TOOLTIP
:
1964 case LyXRC::RC_USE_PIXMAP_CACHE
:
1965 case LyXRC::RC_USE_SPELL_LIB
:
1966 case LyXRC::RC_VIEWDVI_PAPEROPTION
:
1967 case LyXRC::RC_SORT_LAYOUTS
:
1968 case LyXRC::RC_FULL_SCREEN_LIMIT
:
1969 case LyXRC::RC_FULL_SCREEN_SCROLLBAR
:
1970 case LyXRC::RC_FULL_SCREEN_TABBAR
:
1971 case LyXRC::RC_FULL_SCREEN_TOOLBARS
:
1972 case LyXRC::RC_FULL_SCREEN_WIDTH
:
1973 case LyXRC::RC_VISUAL_CURSOR
:
1974 case LyXRC::RC_VIEWER
:
1975 case LyXRC::RC_LAST
: