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 #ifndef 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_COMMAND_PREFIX
:
572 case LFUN_COMMAND_EXECUTE
:
574 case LFUN_META_PREFIX
:
575 case LFUN_BUFFER_CLOSE
:
576 case LFUN_BUFFER_UPDATE
:
577 case LFUN_BUFFER_VIEW
:
578 case LFUN_MASTER_BUFFER_UPDATE
:
579 case LFUN_MASTER_BUFFER_VIEW
:
580 case LFUN_BUFFER_IMPORT
:
581 case LFUN_BUFFER_AUTO_SAVE
:
582 case LFUN_RECONFIGURE
:
584 case LFUN_DROP_LAYOUTS_CHOICE
:
586 case LFUN_SERVER_GET_FILENAME
:
587 case LFUN_SERVER_NOTIFY
:
588 case LFUN_SERVER_GOTO_FILE_ROW
:
589 case LFUN_DIALOG_HIDE
:
590 case LFUN_DIALOG_DISCONNECT_INSET
:
591 case LFUN_BUFFER_CHILD_OPEN
:
592 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE
:
593 case LFUN_KEYMAP_OFF
:
594 case LFUN_KEYMAP_PRIMARY
:
595 case LFUN_KEYMAP_SECONDARY
:
596 case LFUN_KEYMAP_TOGGLE
:
598 case LFUN_BUFFER_EXPORT_CUSTOM
:
599 case LFUN_BUFFER_PRINT
:
600 case LFUN_PREFERENCES_SAVE
:
602 case LFUN_INSET_EDIT
:
603 case LFUN_BUFFER_LANGUAGE
:
604 case LFUN_TEXTCLASS_APPLY
:
605 case LFUN_TEXTCLASS_LOAD
:
606 case LFUN_BUFFER_SAVE_AS_DEFAULT
:
607 case LFUN_BUFFER_PARAMS_APPLY
:
608 case LFUN_LAYOUT_MODULES_CLEAR
:
609 case LFUN_LAYOUT_MODULE_ADD
:
610 case LFUN_LAYOUT_RELOAD
:
611 case LFUN_LYXRC_APPLY
:
612 case LFUN_BUFFER_NEXT
:
613 case LFUN_BUFFER_PREVIOUS
:
614 // these are handled in our dispatch()
622 if (theApp()->getStatus(cmd
, flag
))
625 // Does the view know something?
630 if (lyx_view_
->getStatus(cmd
, flag
))
633 // If we have a BufferView, try cursor position and
634 // then the BufferView.
639 if (!getLocalStatus(view()->cursor(), cmd
, flag
))
640 flag
= view()->getStatus(cmd
);
644 flag
.setEnabled(false);
646 // Can we use a readonly buffer?
647 if (buf
&& buf
->isReadonly()
648 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::ReadOnly
)
649 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::NoBuffer
)) {
650 flag
.message(from_utf8(N_("Document is read-only")));
651 flag
.setEnabled(false);
654 // Are we in a DELETED change-tracking region?
656 && lookupChangeType(view()->cursor(), true) == Change::DELETED
657 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::ReadOnly
)
658 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::NoBuffer
)) {
659 flag
.message(from_utf8(N_("This portion of the document is deleted.")));
660 flag
.setEnabled(false);
663 // the default error message if we disable the command
664 if (!flag
.enabled() && flag
.message().empty())
665 flag
.message(from_utf8(N_("Command disabled")));
671 bool LyXFunc::ensureBufferClean(BufferView
* bv
)
673 Buffer
& buf
= bv
->buffer();
677 docstring
const file
= buf
.fileName().displayName(30);
678 docstring text
= bformat(_("The document %1$s has unsaved "
679 "changes.\n\nDo you want to save "
680 "the document?"), file
);
681 int const ret
= Alert::prompt(_("Save changed document?"),
682 text
, 0, 1, _("&Save"),
686 dispatch(FuncRequest(LFUN_BUFFER_WRITE
));
688 return buf
.isClean();
694 void showPrintError(string
const & name
)
696 docstring str
= bformat(_("Could not print the document %1$s.\n"
697 "Check that your printer is set up correctly."),
698 makeDisplayPath(name
, 50));
699 Alert::error(_("Print document failed"), str
);
703 bool loadLayoutFile(string
const & name
, string
const & buf_path
)
705 if (!LayoutFileList::get().haveClass(name
)) {
706 lyxerr
<< "Document class \"" << name
707 << "\" does not exist."
712 LayoutFile
& tc
= LayoutFileList::get()[name
];
713 if (!tc
.load(buf_path
)) {
714 docstring s
= bformat(_("The document class %1$s "
715 "could not be loaded."), from_utf8(name
));
716 Alert::error(_("Could not load class"), s
);
723 void actOnUpdatedPrefs(LyXRC
const & lyxrc_orig
, LyXRC
const & lyxrc_new
);
728 void LyXFunc::dispatch(FuncRequest
const & cmd
)
730 string
const argument
= to_utf8(cmd
.argument());
731 FuncCode
const action
= cmd
.action
;
733 LYXERR(Debug::ACTION
, "\nLyXFunc::dispatch: cmd: " << cmd
);
734 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
736 // we have not done anything wrong yet.
738 dispatch_buffer
.erase();
740 // redraw the screen at the end (first of the two drawing steps).
741 //This is done unless explicitely requested otherwise
742 Update::flags updateFlags
= Update::FitCursor
;
744 FuncStatus
const flag
= getStatus(cmd
);
745 if (!flag
.enabled()) {
746 // We cannot use this function here
747 LYXERR(Debug::ACTION
, "LyXFunc::dispatch: "
748 << lyxaction
.getActionName(action
)
749 << " [" << action
<< "] is disabled at this location");
750 setErrorMessage(flag
.message());
752 lyx_view_
->restartCursor();
754 Buffer
* buffer
= lyx_view_
? lyx_view_
->buffer() : 0;
757 case LFUN_WORD_FIND_FORWARD
:
758 case LFUN_WORD_FIND_BACKWARD
: {
759 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
760 static docstring last_search
;
761 docstring searched_string
;
763 if (!cmd
.argument().empty()) {
764 last_search
= cmd
.argument();
765 searched_string
= cmd
.argument();
767 searched_string
= last_search
;
770 if (searched_string
.empty())
773 bool const fw
= action
== LFUN_WORD_FIND_FORWARD
;
774 docstring
const data
=
775 find2string(searched_string
, true, false, fw
);
776 find(view(), FuncRequest(LFUN_WORD_FIND
, data
));
780 case LFUN_COMMAND_PREFIX
:
781 LASSERT(lyx_view_
, /**/);
782 lyx_view_
->message(keyseq
.printOptions(true));
786 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
788 meta_fake_bit
= NoModifier
;
790 // cancel any selection
791 dispatch(FuncRequest(LFUN_MARK_OFF
));
792 setMessage(from_ascii(N_("Cancel")));
795 case LFUN_META_PREFIX
:
796 meta_fake_bit
= AltModifier
;
797 setMessage(keyseq
.print(KeySequence::ForGui
));
800 case LFUN_BUFFER_TOGGLE_READ_ONLY
: {
801 LASSERT(lyx_view_
&& lyx_view_
->view() && buffer
, /**/);
802 if (buffer
->lyxvc().inUse())
803 buffer
->lyxvc().toggleReadOnly();
805 buffer
->setReadonly(!buffer
->isReadonly());
809 // --- Menus -----------------------------------------------
810 case LFUN_BUFFER_CLOSE
:
811 lyx_view_
->closeBuffer();
813 updateFlags
= Update::None
;
816 case LFUN_BUFFER_RELOAD
: {
817 LASSERT(lyx_view_
&& buffer
, /**/);
818 docstring
const file
= makeDisplayPath(buffer
->absFileName(), 20);
819 docstring text
= bformat(_("Any changes will be lost. Are you sure "
820 "you want to revert to the saved version of the document %1$s?"), file
);
821 int const ret
= Alert::prompt(_("Revert to saved document?"),
822 text
, 1, 1, _("&Revert"), _("&Cancel"));
829 case LFUN_BUFFER_UPDATE
:
830 LASSERT(lyx_view_
&& buffer
, /**/);
831 buffer
->doExport(argument
, true);
834 case LFUN_BUFFER_VIEW
:
835 LASSERT(lyx_view_
&& buffer
, /**/);
836 buffer
->preview(argument
);
839 case LFUN_MASTER_BUFFER_UPDATE
:
840 LASSERT(lyx_view_
&& buffer
&& buffer
->masterBuffer(), /**/);
841 buffer
->masterBuffer()->doExport(argument
, true);
844 case LFUN_MASTER_BUFFER_VIEW
:
845 LASSERT(lyx_view_
&& buffer
&& buffer
->masterBuffer(), /**/);
846 buffer
->masterBuffer()->preview(argument
);
849 case LFUN_BUILD_PROGRAM
:
850 LASSERT(lyx_view_
&& buffer
, /**/);
851 buffer
->doExport("program", true);
854 case LFUN_BUFFER_CHKTEX
:
855 LASSERT(lyx_view_
&& buffer
, /**/);
859 case LFUN_BUFFER_EXPORT
:
860 LASSERT(lyx_view_
&& buffer
, /**/);
861 if (argument
== "custom")
862 dispatch(FuncRequest(LFUN_DIALOG_SHOW
, "sendto"));
864 buffer
->doExport(argument
, false);
867 case LFUN_BUFFER_EXPORT_CUSTOM
: {
868 LASSERT(lyx_view_
&& buffer
, /**/);
870 string command
= split(argument
, format_name
, ' ');
871 Format
const * format
= formats
.getFormat(format_name
);
873 lyxerr
<< "Format \"" << format_name
874 << "\" not recognized!"
879 // The name of the file created by the conversion process
882 // Output to filename
883 if (format
->name() == "lyx") {
884 string
const latexname
= buffer
->latexName(false);
885 filename
= changeExtension(latexname
,
886 format
->extension());
887 filename
= addName(buffer
->temppath(), filename
);
889 if (!buffer
->writeFile(FileName(filename
)))
893 buffer
->doExport(format_name
, true, filename
);
896 // Substitute $$FName for filename
897 if (!contains(command
, "$$FName"))
898 command
= "( " + command
+ " ) < $$FName";
899 command
= subst(command
, "$$FName", filename
);
901 // Execute the command in the background
903 call
.startscript(Systemcall::DontWait
, command
);
907 case LFUN_BUFFER_PRINT
: {
908 LASSERT(lyx_view_
&& buffer
, /**/);
909 // FIXME: cmd.getArg() might fail if one of the arguments
910 // contains double quotes
911 string target
= cmd
.getArg(0);
912 string target_name
= cmd
.getArg(1);
913 string command
= cmd
.getArg(2);
916 || target_name
.empty()
917 || command
.empty()) {
918 lyxerr
<< "Unable to parse \""
919 << argument
<< '"' << endl
;
922 if (target
!= "printer" && target
!= "file") {
923 lyxerr
<< "Unrecognized target \""
924 << target
<< '"' << endl
;
928 if (!buffer
->doExport("dvi", true)) {
929 showPrintError(buffer
->absFileName());
933 // Push directory path.
934 string
const path
= buffer
->temppath();
935 // Prevent the compiler from optimizing away p
939 // there are three cases here:
940 // 1. we print to a file
941 // 2. we print directly to a printer
942 // 3. we print using a spool command (print to file first)
945 string
const dviname
=
946 changeExtension(buffer
->latexName(true), "dvi");
948 if (target
== "printer") {
949 if (!lyxrc
.print_spool_command
.empty()) {
950 // case 3: print using a spool
951 string
const psname
=
952 changeExtension(dviname
,".ps");
953 command
+= ' ' + lyxrc
.print_to_file
956 + quoteName(dviname
);
959 lyxrc
.print_spool_command
+ ' ';
960 if (target_name
!= "default") {
961 command2
+= lyxrc
.print_spool_printerprefix
965 command2
+= quoteName(psname
);
967 // If successful, then spool command
968 res
= one
.startscript(
973 res
= one
.startscript(
974 Systemcall::DontWait
,
977 // case 2: print directly to a printer
978 if (target_name
!= "default")
979 command
+= ' ' + lyxrc
.print_to_printer
+ target_name
+ ' ';
980 res
= one
.startscript(
981 Systemcall::DontWait
,
982 command
+ quoteName(dviname
));
986 // case 1: print to a file
987 FileName
const filename(makeAbsPath(target_name
,
988 buffer
->filePath()));
989 FileName
const dvifile(makeAbsPath(dviname
, path
));
990 if (filename
.exists()) {
991 docstring text
= bformat(
992 _("The file %1$s already exists.\n\n"
993 "Do you want to overwrite that file?"),
994 makeDisplayPath(filename
.absFilename()));
995 if (Alert::prompt(_("Overwrite file?"),
996 text
, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
999 command
+= ' ' + lyxrc
.print_to_file
1000 + quoteName(filename
.toFilesystemEncoding())
1002 + quoteName(dvifile
.toFilesystemEncoding());
1003 res
= one
.startscript(Systemcall::DontWait
,
1008 showPrintError(buffer
->absFileName());
1012 // FIXME: There is need for a command-line import.
1014 case LFUN_BUFFER_IMPORT:
1019 case LFUN_BUFFER_AUTO_SAVE
:
1023 case LFUN_RECONFIGURE
:
1024 // argument is any additional parameter to the configure.py command
1025 reconfigure(lyx_view_
, argument
);
1028 case LFUN_HELP_OPEN
: {
1030 theApp()->dispatch(FuncRequest(LFUN_WINDOW_NEW
));
1031 string
const arg
= argument
;
1033 setErrorMessage(from_ascii(N_("Missing argument")));
1036 FileName
const fname
= i18nLibFileSearch("doc", arg
, "lyx");
1037 if (fname
.empty()) {
1038 lyxerr
<< "LyX: unable to find documentation file `"
1039 << arg
<< "'. Bad installation?" << endl
;
1042 lyx_view_
->message(bformat(_("Opening help file %1$s..."),
1043 makeDisplayPath(fname
.absFilename())));
1044 Buffer
* buf
= lyx_view_
->loadDocument(fname
, false);
1047 lyx_view_
->setBuffer(buf
);
1048 buf
->errors("Parse");
1050 updateFlags
= Update::None
;
1054 // --- version control -------------------------------
1055 case LFUN_VC_REGISTER
:
1056 LASSERT(lyx_view_
&& buffer
, /**/);
1057 if (!ensureBufferClean(view()) || buffer
->isUnnamed())
1059 if (!buffer
->lyxvc().inUse()) {
1060 buffer
->lyxvc().registrer();
1063 updateFlags
= Update::Force
;
1066 case LFUN_VC_CHECK_IN
:
1067 LASSERT(lyx_view_
&& buffer
, /**/);
1068 if (!ensureBufferClean(view()))
1070 if (buffer
->lyxvc().inUse()
1071 && !buffer
->isReadonly()) {
1072 setMessage(from_utf8(buffer
->lyxvc().checkIn()));
1077 case LFUN_VC_CHECK_OUT
:
1078 LASSERT(lyx_view_
&& buffer
, /**/);
1079 if (!ensureBufferClean(view()))
1081 if (buffer
->lyxvc().inUse()) {
1082 setMessage(from_utf8(buffer
->lyxvc().checkOut()));
1087 case LFUN_VC_REVERT
:
1088 LASSERT(lyx_view_
&& buffer
, /**/);
1089 buffer
->lyxvc().revert();
1093 case LFUN_VC_UNDO_LAST
:
1094 LASSERT(lyx_view_
&& buffer
, /**/);
1095 buffer
->lyxvc().undoLast();
1099 // --- lyxserver commands ----------------------------
1100 case LFUN_SERVER_GET_FILENAME
:
1101 LASSERT(lyx_view_
&& buffer
, /**/);
1102 setMessage(from_utf8(buffer
->absFileName()));
1103 LYXERR(Debug::INFO
, "FNAME["
1104 << buffer
->absFileName() << ']');
1107 case LFUN_SERVER_NOTIFY
:
1108 dispatch_buffer
= keyseq
.print(KeySequence::Portable
);
1109 theServer().notifyClient(to_utf8(dispatch_buffer
));
1112 case LFUN_SERVER_GOTO_FILE_ROW
: {
1113 LASSERT(lyx_view_
, /**/);
1116 istringstream
is(argument
);
1117 is
>> file_name
>> row
;
1119 bool loaded
= false;
1120 if (prefixIs(file_name
, package().temp_dir().absFilename()))
1121 // Needed by inverse dvi search. If it is a file
1122 // in tmpdir, call the apropriated function
1123 buf
= theBufferList().getBufferFromTmp(file_name
);
1125 // Must replace extension of the file to be .lyx
1126 // and get full path
1127 FileName
const s
= fileSearch(string(), changeExtension(file_name
, ".lyx"), "lyx");
1128 // Either change buffer or load the file
1129 if (theBufferList().exists(s
))
1130 buf
= theBufferList().getBuffer(s
);
1132 buf
= lyx_view_
->loadDocument(s
);
1138 updateFlags
= Update::None
;
1143 lyx_view_
->setBuffer(buf
);
1144 view()->setCursorFromRow(row
);
1146 buf
->errors("Parse");
1147 updateFlags
= Update::FitCursor
;
1152 case LFUN_DIALOG_SHOW_NEW_INSET
: {
1153 LASSERT(lyx_view_
, /**/);
1154 string
const name
= cmd
.getArg(0);
1155 InsetCode code
= insetCode(name
);
1156 string data
= trim(to_utf8(cmd
.argument()).substr(name
.size()));
1157 bool insetCodeOK
= true;
1166 case HYPERLINK_CODE
: {
1167 InsetCommandParams
p(code
);
1168 data
= InsetCommand::params2string(name
, p
);
1171 case INCLUDE_CODE
: {
1172 // data is the include type: one of "include",
1173 // "input", "verbatiminput" or "verbatiminput*"
1175 // default type is requested
1177 InsetCommandParams
p(INCLUDE_CODE
, data
);
1178 data
= InsetCommand::params2string("include", p
);
1182 // \c data == "Boxed" || "Frameless" etc
1183 InsetBoxParams
p(data
);
1184 data
= InsetBox::params2string(p
);
1188 InsetBranchParams p
;
1189 data
= InsetBranch::params2string(p
);
1193 InsetCommandParams
p(CITE_CODE
);
1194 data
= InsetCommand::params2string(name
, p
);
1198 data
= InsetERT::params2string(InsetCollapsable::Open
);
1201 case EXTERNAL_CODE
: {
1202 InsetExternalParams p
;
1203 data
= InsetExternal::params2string(p
, *buffer
);
1208 data
= InsetFloat::params2string(p
);
1211 case LISTINGS_CODE
: {
1212 InsetListingsParams p
;
1213 data
= InsetListings::params2string(p
);
1216 case GRAPHICS_CODE
: {
1217 InsetGraphicsParams p
;
1218 data
= InsetGraphics::params2string(p
, *buffer
);
1223 data
= InsetNote::params2string(p
);
1228 data
= InsetSpace::params2string(p
);
1233 data
= InsetVSpace::params2string(space
);
1238 data
= InsetWrap::params2string(p
);
1242 lyxerr
<< "Inset type '" << name
<<
1243 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << endl
;
1244 insetCodeOK
= false;
1246 } // end switch(code)
1248 dispatch(FuncRequest(LFUN_DIALOG_SHOW
, name
+ " " + data
));
1252 case LFUN_CITATION_INSERT
: {
1253 LASSERT(lyx_view_
, /**/);
1254 if (!argument
.empty()) {
1255 // we can have one optional argument, delimited by '|'
1256 // citation-insert <key>|<text_before>
1257 // this should be enhanced to also support text_after
1258 // and citation style
1259 string arg
= argument
;
1261 if (contains(argument
, "|")) {
1262 arg
= token(argument
, '|', 0);
1263 opt1
= token(argument
, '|', 1);
1265 InsetCommandParams
icp(CITE_CODE
);
1266 icp
["key"] = from_utf8(arg
);
1268 icp
["before"] = from_utf8(opt1
);
1269 string icstr
= InsetCommand::params2string("citation", icp
);
1270 FuncRequest
fr(LFUN_INSET_INSERT
, icstr
);
1273 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET
, "citation"));
1277 case LFUN_BUFFER_CHILD_OPEN
: {
1278 LASSERT(lyx_view_
&& buffer
, /**/);
1279 FileName filename
= makeAbsPath(argument
, buffer
->filePath());
1280 view()->saveBookmark(false);
1282 bool parsed
= false;
1283 if (theBufferList().exists(filename
)) {
1284 child
= theBufferList().getBuffer(filename
);
1286 setMessage(bformat(_("Opening child document %1$s..."),
1287 makeDisplayPath(filename
.absFilename())));
1288 child
= lyx_view_
->loadDocument(filename
, false);
1292 // Set the parent name of the child document.
1293 // This makes insertion of citations and references in the child work,
1294 // when the target is in the parent or another child document.
1295 child
->setParent(buffer
);
1296 updateLabels(*child
->masterBuffer());
1297 lyx_view_
->setBuffer(child
);
1299 child
->errors("Parse");
1302 // If a screen update is required (in case where auto_open is false),
1303 // setBuffer() would have taken care of it already. Otherwise we shall
1304 // reset the update flag because it can cause a circular problem.
1306 updateFlags
= Update::None
;
1310 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE
:
1311 LASSERT(lyx_view_
, /**/);
1312 lyxrc
.cursor_follows_scrollbar
= !lyxrc
.cursor_follows_scrollbar
;
1315 case LFUN_KEYMAP_OFF
:
1316 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1317 lyx_view_
->view()->getIntl().keyMapOn(false);
1320 case LFUN_KEYMAP_PRIMARY
:
1321 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1322 lyx_view_
->view()->getIntl().keyMapPrim();
1325 case LFUN_KEYMAP_SECONDARY
:
1326 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1327 lyx_view_
->view()->getIntl().keyMapSec();
1330 case LFUN_KEYMAP_TOGGLE
:
1331 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1332 lyx_view_
->view()->getIntl().toggleKeyMap();
1338 string rest
= split(argument
, countstr
, ' ');
1339 istringstream
is(countstr
);
1342 //lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1343 for (int i
= 0; i
< count
; ++i
)
1344 dispatch(lyxaction
.lookupFunc(rest
));
1348 case LFUN_COMMAND_SEQUENCE
: {
1349 // argument contains ';'-terminated commands
1350 string arg
= argument
;
1351 while (!arg
.empty()) {
1353 arg
= split(arg
, first
, ';');
1354 FuncRequest
func(lyxaction
.lookupFunc(first
));
1355 func
.origin
= cmd
.origin
;
1361 case LFUN_COMMAND_ALTERNATIVES
: {
1362 // argument contains ';'-terminated commands
1363 string arg
= argument
;
1364 while (!arg
.empty()) {
1366 arg
= split(arg
, first
, ';');
1367 FuncRequest
func(lyxaction
.lookupFunc(first
));
1368 func
.origin
= cmd
.origin
;
1369 FuncStatus stat
= getStatus(func
);
1370 if (stat
.enabled()) {
1380 if (theTopLevelCmdDef().lock(argument
, func
)) {
1381 func
.origin
= cmd
.origin
;
1383 theTopLevelCmdDef().release(argument
);
1385 if (func
.action
== LFUN_UNKNOWN_ACTION
) {
1386 // unknown command definition
1387 lyxerr
<< "Warning: unknown command definition `"
1391 // recursion detected
1392 lyxerr
<< "Warning: Recursion in the command definition `"
1393 << argument
<< "' detected"
1400 case LFUN_PREFERENCES_SAVE
: {
1401 lyxrc
.write(makeAbsPath("preferences",
1402 package().user_support().absFilename()),
1408 LASSERT(lyx_view_
, /**/);
1409 lyx_view_
->message(from_utf8(argument
));
1412 case LFUN_BUFFER_LANGUAGE
: {
1413 LASSERT(lyx_view_
, /**/);
1414 Language
const * oldL
= buffer
->params().language
;
1415 Language
const * newL
= languages
.getLanguage(argument
);
1416 if (!newL
|| oldL
== newL
)
1419 if (oldL
->rightToLeft() == newL
->rightToLeft()
1420 && !buffer
->isMultiLingual())
1421 buffer
->changeLanguage(oldL
, newL
);
1425 case LFUN_BUFFER_SAVE_AS_DEFAULT
: {
1426 string
const fname
=
1427 addName(addPath(package().user_support().absFilename(), "templates/"),
1429 Buffer
defaults(fname
);
1431 istringstream
ss(argument
);
1434 int const unknown_tokens
= defaults
.readHeader(lex
);
1436 if (unknown_tokens
!= 0) {
1437 lyxerr
<< "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1438 << unknown_tokens
<< " unknown token"
1439 << (unknown_tokens
== 1 ? "" : "s")
1443 if (defaults
.writeFile(FileName(defaults
.absFileName())))
1444 setMessage(bformat(_("Document defaults saved in %1$s"),
1445 makeDisplayPath(fname
)));
1447 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1451 case LFUN_BUFFER_PARAMS_APPLY
: {
1452 LASSERT(lyx_view_
, /**/);
1454 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1455 Cursor
& cur
= view()->cursor();
1456 cur
.recordUndoFullDocument();
1458 istringstream
ss(argument
);
1461 int const unknown_tokens
= buffer
->readHeader(lex
);
1463 if (unknown_tokens
!= 0) {
1464 lyxerr
<< "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1465 << unknown_tokens
<< " unknown token"
1466 << (unknown_tokens
== 1 ? "" : "s")
1470 updateLayout(oldClass
, buffer
);
1472 updateFlags
= Update::Force
| Update::FitCursor
;
1473 // We are most certainly here because of a change in the document
1474 // It is then better to make sure that all dialogs are in sync with
1475 // current document settings. LyXView::restartCursor() achieve this.
1476 lyx_view_
->restartCursor();
1480 case LFUN_LAYOUT_MODULES_CLEAR
: {
1481 LASSERT(lyx_view_
, /**/);
1482 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1483 view()->cursor().recordUndoFullDocument();
1484 buffer
->params().clearLayoutModules();
1485 buffer
->params().makeDocumentClass();
1486 updateLayout(oldClass
, buffer
);
1487 updateFlags
= Update::Force
| Update::FitCursor
;
1491 case LFUN_LAYOUT_MODULE_ADD
: {
1492 LASSERT(lyx_view_
, /**/);
1493 BufferParams
const & params
= buffer
->params();
1494 if (!params
.moduleCanBeAdded(argument
)) {
1495 LYXERR0("Module `" << argument
<<
1496 "' cannot be added due to failed requirements or "
1497 "conflicts with installed modules.");
1500 DocumentClass
const * const oldClass
= params
.documentClassPtr();
1501 view()->cursor().recordUndoFullDocument();
1502 buffer
->params().addLayoutModule(argument
);
1503 buffer
->params().makeDocumentClass();
1504 updateLayout(oldClass
, buffer
);
1505 updateFlags
= Update::Force
| Update::FitCursor
;
1509 case LFUN_TEXTCLASS_APPLY
: {
1510 LASSERT(lyx_view_
, /**/);
1512 if (!loadLayoutFile(argument
, buffer
->temppath()) &&
1513 !loadLayoutFile(argument
, buffer
->filePath()))
1516 LayoutFile
const * old_layout
= buffer
->params().baseClass();
1517 LayoutFile
const * new_layout
= &(LayoutFileList::get()[argument
]);
1519 if (old_layout
== new_layout
)
1523 //Save the old, possibly modular, layout for use in conversion.
1524 DocumentClass
const * const oldDocClass
= buffer
->params().documentClassPtr();
1525 view()->cursor().recordUndoFullDocument();
1526 buffer
->params().setBaseClass(argument
);
1527 buffer
->params().makeDocumentClass();
1528 updateLayout(oldDocClass
, buffer
);
1529 updateFlags
= Update::Force
| Update::FitCursor
;
1533 case LFUN_LAYOUT_RELOAD
: {
1534 LASSERT(lyx_view_
, /**/);
1535 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1536 LayoutFileIndex bc
= buffer
->params().baseClassID();
1537 LayoutFileList::get().reset(bc
);
1538 buffer
->params().setBaseClass(bc
);
1539 buffer
->params().makeDocumentClass();
1540 updateLayout(oldClass
, buffer
);
1541 updateFlags
= Update::Force
| Update::FitCursor
;
1545 case LFUN_TEXTCLASS_LOAD
:
1546 loadLayoutFile(argument
, buffer
->temppath()) ||
1547 loadLayoutFile(argument
, buffer
->filePath());
1550 case LFUN_LYXRC_APPLY
: {
1551 LyXRC
const lyxrc_orig
= lyxrc
;
1553 istringstream
ss(argument
);
1554 bool const success
= lyxrc
.read(ss
) == 0;
1557 lyxerr
<< "Warning in LFUN_LYXRC_APPLY!\n"
1558 << "Unable to read lyxrc data"
1563 actOnUpdatedPrefs(lyxrc_orig
, lyxrc
);
1565 theApp()->resetGui();
1567 /// We force the redraw in any case because there might be
1568 /// some screen font changes.
1569 /// FIXME: only the current view will be updated. the Gui
1570 /// class is able to furnish the list of views.
1571 updateFlags
= Update::Force
;
1575 case LFUN_BOOKMARK_GOTO
:
1576 // go to bookmark, open unopened file and switch to buffer if necessary
1577 gotoBookmark(convert
<unsigned int>(to_utf8(cmd
.argument())), true, true);
1578 updateFlags
= Update::FitCursor
;
1581 case LFUN_BOOKMARK_CLEAR
:
1582 theSession().bookmarks().clear();
1586 LASSERT(theApp(), /**/);
1587 // Let the frontend dispatch its own actions.
1588 if (theApp()->dispatch(cmd
))
1589 // Nothing more to do.
1592 // Everything below is only for active lyx_view_
1596 // Start an undo group. This may be needed for
1597 // some stuff like inset-apply on labels.
1598 if (theBufferList().isLoaded(buffer
))
1599 buffer
->undo().beginUndoGroup();
1601 // Let the current LyXView dispatch its own actions.
1602 if (lyx_view_
->dispatch(cmd
)) {
1603 if (lyx_view_
->view()) {
1604 updateFlags
= lyx_view_
->view()->cursor().result().update();
1605 if (theBufferList().isLoaded(buffer
))
1606 buffer
->undo().endUndoGroup();
1611 LASSERT(lyx_view_
->view(), /**/);
1613 // Let the current BufferView dispatch its own actions.
1614 if (view()->dispatch(cmd
)) {
1615 // The BufferView took care of its own updates if needed.
1616 updateFlags
= Update::None
;
1617 if (theBufferList().isLoaded(buffer
))
1618 buffer
->undo().endUndoGroup();
1622 // Let the current Cursor dispatch its own actions.
1623 Cursor old
= view()->cursor();
1624 view()->cursor().getPos(cursorPosBeforeDispatchX_
,
1625 cursorPosBeforeDispatchY_
);
1626 view()->cursor().dispatch(cmd
);
1628 // notify insets we just left
1629 if (view()->cursor() != old
) {
1631 bool badcursor
= notifyCursorLeaves(old
, view()->cursor());
1633 view()->cursor().fixIfBroken();
1636 if (theBufferList().isLoaded(buffer
))
1637 buffer
->undo().endUndoGroup();
1639 // update completion. We do it here and not in
1640 // processKeySym to avoid another redraw just for a
1641 // changed inline completion
1642 if (cmd
.origin
== FuncRequest::KEYBOARD
) {
1643 if (cmd
.action
== LFUN_SELF_INSERT
)
1644 lyx_view_
->updateCompletion(view()->cursor(), true, true);
1645 else if (cmd
.action
== LFUN_CHAR_DELETE_BACKWARD
)
1646 lyx_view_
->updateCompletion(view()->cursor(), false, true);
1648 lyx_view_
->updateCompletion(view()->cursor(), false, false);
1651 updateFlags
= view()->cursor().result().update();
1654 // if we executed a mutating lfun, mark the buffer as dirty
1655 if (theBufferList().isLoaded(buffer
) && flag
.enabled()
1656 && !lyxaction
.funcHasFlag(action
, LyXAction::NoBuffer
)
1657 && !lyxaction
.funcHasFlag(action
, LyXAction::ReadOnly
))
1658 buffer
->markDirty();
1660 if (lyx_view_
&& lyx_view_
->buffer()) {
1661 // BufferView::update() updates the ViewMetricsInfo and
1662 // also initializes the position cache for all insets in
1663 // (at least partially) visible top-level paragraphs.
1664 // We will redraw the screen only if needed.
1665 view()->processUpdateFlags(updateFlags
);
1667 // Do we have a selection?
1668 theSelection().haveSelection(view()->cursor().selection());
1671 lyx_view_
->restartCursor();
1675 // Some messages may already be translated, so we cannot use _()
1676 sendDispatchMessage(translateIfPossible(getMessage()), cmd
);
1681 void LyXFunc::sendDispatchMessage(docstring
const & msg
, FuncRequest
const & cmd
)
1683 const bool verbose
= (cmd
.origin
== FuncRequest::MENU
1684 || cmd
.origin
== FuncRequest::TOOLBAR
1685 || cmd
.origin
== FuncRequest::COMMANDBUFFER
);
1687 if (cmd
.action
== LFUN_SELF_INSERT
|| !verbose
) {
1688 LYXERR(Debug::ACTION
, "dispatch msg is " << to_utf8(msg
));
1690 lyx_view_
->message(msg
);
1694 docstring dispatch_msg
= msg
;
1695 if (!dispatch_msg
.empty())
1696 dispatch_msg
+= ' ';
1698 docstring comname
= from_utf8(lyxaction
.getActionName(cmd
.action
));
1700 bool argsadded
= false;
1702 if (!cmd
.argument().empty()) {
1703 if (cmd
.action
!= LFUN_UNKNOWN_ACTION
) {
1704 comname
+= ' ' + cmd
.argument();
1709 docstring
const shortcuts
= theTopLevelKeymap().printBindings(cmd
);
1711 if (!shortcuts
.empty())
1712 comname
+= ": " + shortcuts
;
1713 else if (!argsadded
&& !cmd
.argument().empty())
1714 comname
+= ' ' + cmd
.argument();
1716 if (!comname
.empty()) {
1717 comname
= rtrim(comname
);
1718 dispatch_msg
+= '(' + rtrim(comname
) + ')';
1721 LYXERR(Debug::ACTION
, "verbose dispatch msg " << to_utf8(dispatch_msg
));
1722 if (!dispatch_msg
.empty())
1723 lyx_view_
->message(dispatch_msg
);
1727 void LyXFunc::reloadBuffer()
1729 FileName filename
= lyx_view_
->buffer()->fileName();
1730 // The user has already confirmed that the changes, if any, should
1731 // be discarded. So we just release the Buffer and don't call closeBuffer();
1732 theBufferList().release(lyx_view_
->buffer());
1733 Buffer
* buf
= lyx_view_
->loadDocument(filename
);
1734 docstring
const disp_fn
= makeDisplayPath(filename
.absFilename());
1738 lyx_view_
->setBuffer(buf
);
1739 buf
->errors("Parse");
1740 str
= bformat(_("Document %1$s reloaded."), disp_fn
);
1742 str
= bformat(_("Could not reload document %1$s"), disp_fn
);
1744 lyx_view_
->message(str
);
1747 // Each "lyx_view_" should have it's own message method. lyxview and
1748 // the minibuffer would use the minibuffer, but lyxserver would
1749 // send an ERROR signal to its client. Alejandro 970603
1750 // This function is bit problematic when it comes to NLS, to make the
1751 // lyx servers client be language indepenent we must not translate
1752 // strings sent to this func.
1753 void LyXFunc::setErrorMessage(docstring
const & m
) const
1755 dispatch_buffer
= m
;
1760 void LyXFunc::setMessage(docstring
const & m
) const
1762 dispatch_buffer
= m
;
1766 docstring
LyXFunc::viewStatusMessage()
1768 // When meta-fake key is pressed, show the key sequence so far + "M-".
1770 return keyseq
.print(KeySequence::ForGui
) + "M-";
1772 // Else, when a non-complete key sequence is pressed,
1773 // show the available options.
1774 if (keyseq
.length() > 0 && !keyseq
.deleted())
1775 return keyseq
.printOptions(true);
1777 LASSERT(lyx_view_
, /**/);
1778 if (!lyx_view_
->buffer())
1779 return _("Welcome to LyX!");
1781 return view()->cursor().currentState();
1785 BufferView
* LyXFunc::view() const
1787 LASSERT(lyx_view_
, /**/);
1788 return lyx_view_
->view();
1792 bool LyXFunc::wasMetaKey() const
1794 return (meta_fake_bit
!= NoModifier
);
1798 void LyXFunc::updateLayout(DocumentClass
const * const oldlayout
, Buffer
* buffer
)
1800 lyx_view_
->message(_("Converting document to new document class..."));
1802 StableDocIterator
backcur(view()->cursor());
1803 ErrorList
& el
= buffer
->errorList("Class Switch");
1804 cap::switchBetweenClasses(
1805 oldlayout
, buffer
->params().documentClassPtr(),
1806 static_cast<InsetText
&>(buffer
->inset()), el
);
1808 view()->setCursor(backcur
.asDocIterator(&(buffer
->inset())));
1810 buffer
->errors("Class Switch");
1811 updateLabels(*buffer
);
1817 void actOnUpdatedPrefs(LyXRC
const & lyxrc_orig
, LyXRC
const & lyxrc_new
)
1819 // Why the switch you might ask. It is a trick to ensure that all
1820 // the elements in the LyXRCTags enum is handled. As you can see
1821 // there are no breaks at all. So it is just a huge fall-through.
1822 // The nice thing is that we will get a warning from the compiler
1823 // if we forget an element.
1824 LyXRC::LyXRCTags tag
= LyXRC::RC_LAST
;
1826 case LyXRC::RC_ACCEPT_COMPOUND
:
1827 case LyXRC::RC_ALT_LANG
:
1828 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND
:
1829 case LyXRC::RC_PLAINTEXT_LINELEN
:
1830 case LyXRC::RC_AUTOREGIONDELETE
:
1831 case LyXRC::RC_AUTORESET_OPTIONS
:
1832 case LyXRC::RC_AUTOSAVE
:
1833 case LyXRC::RC_AUTO_NUMBER
:
1834 case LyXRC::RC_BACKUPDIR_PATH
:
1835 case LyXRC::RC_BIBTEX_COMMAND
:
1836 case LyXRC::RC_BINDFILE
:
1837 case LyXRC::RC_CHECKLASTFILES
:
1838 case LyXRC::RC_COMPLETION_CURSOR_TEXT
:
1839 case LyXRC::RC_COMPLETION_INLINE_DELAY
:
1840 case LyXRC::RC_COMPLETION_INLINE_DOTS
:
1841 case LyXRC::RC_COMPLETION_INLINE_MATH
:
1842 case LyXRC::RC_COMPLETION_INLINE_TEXT
:
1843 case LyXRC::RC_COMPLETION_POPUP_AFTER_COMPLETE
:
1844 case LyXRC::RC_COMPLETION_POPUP_DELAY
:
1845 case LyXRC::RC_COMPLETION_POPUP_MATH
:
1846 case LyXRC::RC_COMPLETION_POPUP_TEXT
:
1847 case LyXRC::RC_USELASTFILEPOS
:
1848 case LyXRC::RC_LOADSESSION
:
1849 case LyXRC::RC_CHKTEX_COMMAND
:
1850 case LyXRC::RC_CONVERTER
:
1851 case LyXRC::RC_CONVERTER_CACHE_MAXAGE
:
1852 case LyXRC::RC_COPIER
:
1853 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR
:
1854 case LyXRC::RC_CUSTOM_EXPORT_COMMAND
:
1855 case LyXRC::RC_CUSTOM_EXPORT_FORMAT
:
1856 case LyXRC::RC_DATE_INSERT_FORMAT
:
1857 case LyXRC::RC_DEFAULT_LANGUAGE
:
1858 case LyXRC::RC_GUI_LANGUAGE
:
1859 case LyXRC::RC_DEFAULT_PAPERSIZE
:
1860 case LyXRC::RC_DEFFILE
:
1861 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN
:
1862 case LyXRC::RC_DISPLAY_GRAPHICS
:
1863 case LyXRC::RC_DOCUMENTPATH
:
1864 if (lyxrc_orig
.document_path
!= lyxrc_new
.document_path
) {
1865 FileName
path(lyxrc_new
.document_path
);
1866 if (path
.exists() && path
.isDirectory())
1867 package().document_dir() = FileName(lyxrc
.document_path
);
1869 case LyXRC::RC_ESC_CHARS
:
1870 case LyXRC::RC_EXAMPLEPATH
:
1871 case LyXRC::RC_FONT_ENCODING
:
1872 case LyXRC::RC_FORMAT
:
1873 case LyXRC::RC_GROUP_LAYOUTS
:
1874 case LyXRC::RC_INDEX_COMMAND
:
1875 case LyXRC::RC_NOMENCL_COMMAND
:
1876 case LyXRC::RC_INPUT
:
1877 case LyXRC::RC_KBMAP
:
1878 case LyXRC::RC_KBMAP_PRIMARY
:
1879 case LyXRC::RC_KBMAP_SECONDARY
:
1880 case LyXRC::RC_LABEL_INIT_LENGTH
:
1881 case LyXRC::RC_LANGUAGE_AUTO_BEGIN
:
1882 case LyXRC::RC_LANGUAGE_AUTO_END
:
1883 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN
:
1884 case LyXRC::RC_LANGUAGE_COMMAND_END
:
1885 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL
:
1886 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS
:
1887 case LyXRC::RC_LANGUAGE_PACKAGE
:
1888 case LyXRC::RC_LANGUAGE_USE_BABEL
:
1889 case LyXRC::RC_MAC_LIKE_WORD_MOVEMENT
:
1890 case LyXRC::RC_MACRO_EDIT_STYLE
:
1891 case LyXRC::RC_MAKE_BACKUP
:
1892 case LyXRC::RC_MARK_FOREIGN_LANGUAGE
:
1893 case LyXRC::RC_MOUSE_WHEEL_SPEED
:
1894 case LyXRC::RC_NUMLASTFILES
:
1895 case LyXRC::RC_PATH_PREFIX
:
1896 if (lyxrc_orig
.path_prefix
!= lyxrc_new
.path_prefix
) {
1897 prependEnvPath("PATH", lyxrc
.path_prefix
);
1899 case LyXRC::RC_PERS_DICT
:
1900 case LyXRC::RC_PREVIEW
:
1901 case LyXRC::RC_PREVIEW_HASHED_LABELS
:
1902 case LyXRC::RC_PREVIEW_SCALE_FACTOR
:
1903 case LyXRC::RC_PRINTCOLLCOPIESFLAG
:
1904 case LyXRC::RC_PRINTCOPIESFLAG
:
1905 case LyXRC::RC_PRINTER
:
1906 case LyXRC::RC_PRINTEVENPAGEFLAG
:
1907 case LyXRC::RC_PRINTEXSTRAOPTIONS
:
1908 case LyXRC::RC_PRINTFILEEXTENSION
:
1909 case LyXRC::RC_PRINTLANDSCAPEFLAG
:
1910 case LyXRC::RC_PRINTODDPAGEFLAG
:
1911 case LyXRC::RC_PRINTPAGERANGEFLAG
:
1912 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG
:
1913 case LyXRC::RC_PRINTPAPERFLAG
:
1914 case LyXRC::RC_PRINTREVERSEFLAG
:
1915 case LyXRC::RC_PRINTSPOOL_COMMAND
:
1916 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX
:
1917 case LyXRC::RC_PRINTTOFILE
:
1918 case LyXRC::RC_PRINTTOPRINTER
:
1919 case LyXRC::RC_PRINT_ADAPTOUTPUT
:
1920 case LyXRC::RC_PRINT_COMMAND
:
1921 case LyXRC::RC_RTL_SUPPORT
:
1922 case LyXRC::RC_SCREEN_DPI
:
1923 case LyXRC::RC_SCREEN_FONT_ROMAN
:
1924 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY
:
1925 case LyXRC::RC_SCREEN_FONT_SANS
:
1926 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY
:
1927 case LyXRC::RC_SCREEN_FONT_SCALABLE
:
1928 case LyXRC::RC_SCREEN_FONT_SIZES
:
1929 case LyXRC::RC_SCREEN_FONT_TYPEWRITER
:
1930 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY
:
1931 case LyXRC::RC_GEOMETRY_SESSION
:
1932 case LyXRC::RC_SCREEN_ZOOM
:
1933 case LyXRC::RC_SERVERPIPE
:
1934 case LyXRC::RC_SET_COLOR
:
1935 case LyXRC::RC_SHOW_BANNER
:
1936 case LyXRC::RC_OPEN_BUFFERS_IN_TABS
:
1937 case LyXRC::RC_SPELL_COMMAND
:
1938 case LyXRC::RC_TEMPDIRPATH
:
1939 case LyXRC::RC_TEMPLATEPATH
:
1940 case LyXRC::RC_TEX_ALLOWS_SPACES
:
1941 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS
:
1942 if (lyxrc_orig
.windows_style_tex_paths
!= lyxrc_new
.windows_style_tex_paths
) {
1943 os::windows_style_tex_paths(lyxrc_new
.windows_style_tex_paths
);
1945 case LyXRC::RC_UIFILE
:
1946 case LyXRC::RC_USER_EMAIL
:
1947 case LyXRC::RC_USER_NAME
:
1948 case LyXRC::RC_USETEMPDIR
:
1949 case LyXRC::RC_USE_ALT_LANG
:
1950 case LyXRC::RC_USE_CONVERTER_CACHE
:
1951 case LyXRC::RC_USE_ESC_CHARS
:
1952 case LyXRC::RC_USE_INP_ENC
:
1953 case LyXRC::RC_USE_PERS_DICT
:
1954 case LyXRC::RC_USE_TOOLTIP
:
1955 case LyXRC::RC_USE_PIXMAP_CACHE
:
1956 case LyXRC::RC_USE_SPELL_LIB
:
1957 case LyXRC::RC_VIEWDVI_PAPEROPTION
:
1958 case LyXRC::RC_SORT_LAYOUTS
:
1959 case LyXRC::RC_FULL_SCREEN_LIMIT
:
1960 case LyXRC::RC_FULL_SCREEN_SCROLLBAR
:
1961 case LyXRC::RC_FULL_SCREEN_TABBAR
:
1962 case LyXRC::RC_FULL_SCREEN_TOOLBARS
:
1963 case LyXRC::RC_FULL_SCREEN_WIDTH
:
1964 case LyXRC::RC_VISUAL_CURSOR
:
1965 case LyXRC::RC_VIEWER
:
1966 case LyXRC::RC_LAST
: