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(file
)) {
251 dispatch(FuncRequest(LFUN_FILE_OPEN
, file
));
255 // open may fail, so we need to test it again
256 if (!theBufferList().exists(file
))
259 // if the current buffer is not that one, switch to it.
260 if (lyx_view_
->buffer()->absFileName() != file
) {
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();
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(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
);
538 string name
= to_utf8(cmd
.argument());
539 if (theTopLevelCmdDef().lock(name
, func
)) {
540 func
.origin
= cmd
.origin
;
541 flag
= getStatus(func
);
542 theTopLevelCmdDef().release(name
);
544 // catch recursion or unknown command definiton
545 // all operations until the recursion or unknown command
546 // definiton occures are performed, so set the state to enabled
552 case LFUN_WORD_FIND_FORWARD
:
553 case LFUN_WORD_FIND_BACKWARD
:
554 case LFUN_COMMAND_PREFIX
:
555 case LFUN_COMMAND_EXECUTE
:
557 case LFUN_META_PREFIX
:
558 case LFUN_BUFFER_CLOSE
:
559 case LFUN_BUFFER_UPDATE
:
560 case LFUN_BUFFER_VIEW
:
561 case LFUN_MASTER_BUFFER_UPDATE
:
562 case LFUN_MASTER_BUFFER_VIEW
:
563 case LFUN_BUFFER_IMPORT
:
564 case LFUN_BUFFER_AUTO_SAVE
:
565 case LFUN_RECONFIGURE
:
567 case LFUN_DROP_LAYOUTS_CHOICE
:
569 case LFUN_SERVER_GET_FILENAME
:
570 case LFUN_SERVER_NOTIFY
:
571 case LFUN_SERVER_GOTO_FILE_ROW
:
572 case LFUN_DIALOG_HIDE
:
573 case LFUN_DIALOG_DISCONNECT_INSET
:
574 case LFUN_BUFFER_CHILD_OPEN
:
575 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE
:
576 case LFUN_KEYMAP_OFF
:
577 case LFUN_KEYMAP_PRIMARY
:
578 case LFUN_KEYMAP_SECONDARY
:
579 case LFUN_KEYMAP_TOGGLE
:
581 case LFUN_BUFFER_EXPORT_CUSTOM
:
582 case LFUN_BUFFER_PRINT
:
583 case LFUN_PREFERENCES_SAVE
:
585 case LFUN_INSET_EDIT
:
586 case LFUN_BUFFER_LANGUAGE
:
587 case LFUN_TEXTCLASS_APPLY
:
588 case LFUN_TEXTCLASS_LOAD
:
589 case LFUN_BUFFER_SAVE_AS_DEFAULT
:
590 case LFUN_BUFFER_PARAMS_APPLY
:
591 case LFUN_LAYOUT_MODULES_CLEAR
:
592 case LFUN_LAYOUT_MODULE_ADD
:
593 case LFUN_LAYOUT_RELOAD
:
594 case LFUN_LYXRC_APPLY
:
595 case LFUN_BUFFER_NEXT
:
596 case LFUN_BUFFER_PREVIOUS
:
597 // these are handled in our dispatch()
605 if (theApp()->getStatus(cmd
, flag
))
608 // Does the view know something?
613 if (lyx_view_
->getStatus(cmd
, flag
))
616 // If we have a BufferView, try cursor position and
617 // then the BufferView.
622 if (!getLocalStatus(view()->cursor(), cmd
, flag
))
623 flag
= view()->getStatus(cmd
);
627 flag
.setEnabled(false);
629 // Can we use a readonly buffer?
630 if (buf
&& buf
->isReadonly()
631 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::ReadOnly
)
632 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::NoBuffer
)) {
633 flag
.message(from_utf8(N_("Document is read-only")));
634 flag
.setEnabled(false);
637 // Are we in a DELETED change-tracking region?
639 && lookupChangeType(view()->cursor(), true) == Change::DELETED
640 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::ReadOnly
)
641 && !lyxaction
.funcHasFlag(cmd
.action
, LyXAction::NoBuffer
)) {
642 flag
.message(from_utf8(N_("This portion of the document is deleted.")));
643 flag
.setEnabled(false);
646 // the default error message if we disable the command
647 if (!flag
.enabled() && flag
.message().empty())
648 flag
.message(from_utf8(N_("Command disabled")));
654 bool LyXFunc::ensureBufferClean(BufferView
* bv
)
656 Buffer
& buf
= bv
->buffer();
660 docstring
const file
= buf
.fileName().displayName(30);
661 docstring text
= bformat(_("The document %1$s has unsaved "
662 "changes.\n\nDo you want to save "
663 "the document?"), file
);
664 int const ret
= Alert::prompt(_("Save changed document?"),
665 text
, 0, 1, _("&Save"),
669 dispatch(FuncRequest(LFUN_BUFFER_WRITE
));
671 return buf
.isClean();
677 void showPrintError(string
const & name
)
679 docstring str
= bformat(_("Could not print the document %1$s.\n"
680 "Check that your printer is set up correctly."),
681 makeDisplayPath(name
, 50));
682 Alert::error(_("Print document failed"), str
);
686 bool loadLayoutFile(string
const & name
, string
const & buf_path
)
688 if (!LayoutFileList::get().haveClass(name
)) {
689 lyxerr
<< "Document class \"" << name
690 << "\" does not exist."
695 LayoutFile
& tc
= LayoutFileList::get()[name
];
696 if (!tc
.load(buf_path
)) {
697 docstring s
= bformat(_("The document class %1$s "
698 "could not be loaded."), from_utf8(name
));
699 Alert::error(_("Could not load class"), s
);
706 void actOnUpdatedPrefs(LyXRC
const & lyxrc_orig
, LyXRC
const & lyxrc_new
);
711 void LyXFunc::dispatch(FuncRequest
const & cmd
)
713 string
const argument
= to_utf8(cmd
.argument());
714 FuncCode
const action
= cmd
.action
;
716 LYXERR(Debug::ACTION
, "\nLyXFunc::dispatch: cmd: " << cmd
);
717 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
719 // we have not done anything wrong yet.
721 dispatch_buffer
.erase();
723 // redraw the screen at the end (first of the two drawing steps).
724 //This is done unless explicitely requested otherwise
725 Update::flags updateFlags
= Update::FitCursor
;
727 FuncStatus
const flag
= getStatus(cmd
);
728 if (!flag
.enabled()) {
729 // We cannot use this function here
730 LYXERR(Debug::ACTION
, "LyXFunc::dispatch: "
731 << lyxaction
.getActionName(action
)
732 << " [" << action
<< "] is disabled at this location");
733 setErrorMessage(flag
.message());
737 case LFUN_WORD_FIND_FORWARD
:
738 case LFUN_WORD_FIND_BACKWARD
: {
739 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
740 static docstring last_search
;
741 docstring searched_string
;
743 if (!cmd
.argument().empty()) {
744 last_search
= cmd
.argument();
745 searched_string
= cmd
.argument();
747 searched_string
= last_search
;
750 if (searched_string
.empty())
753 bool const fw
= action
== LFUN_WORD_FIND_FORWARD
;
754 docstring
const data
=
755 find2string(searched_string
, true, false, fw
);
756 find(view(), FuncRequest(LFUN_WORD_FIND
, data
));
760 case LFUN_COMMAND_PREFIX
:
761 LASSERT(lyx_view_
, /**/);
762 lyx_view_
->message(keyseq
.printOptions(true));
766 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
768 meta_fake_bit
= NoModifier
;
769 if (lyx_view_
->buffer())
770 // cancel any selection
771 dispatch(FuncRequest(LFUN_MARK_OFF
));
772 setMessage(from_ascii(N_("Cancel")));
775 case LFUN_META_PREFIX
:
776 meta_fake_bit
= AltModifier
;
777 setMessage(keyseq
.print(KeySequence::ForGui
));
780 case LFUN_BUFFER_TOGGLE_READ_ONLY
: {
781 LASSERT(lyx_view_
&& lyx_view_
->view() && lyx_view_
->buffer(), /**/);
782 Buffer
* buf
= lyx_view_
->buffer();
783 if (buf
->lyxvc().inUse())
784 buf
->lyxvc().toggleReadOnly();
786 buf
->setReadonly(!lyx_view_
->buffer()->isReadonly());
790 // --- Menus -----------------------------------------------
791 case LFUN_BUFFER_CLOSE
:
792 lyx_view_
->closeBuffer();
793 updateFlags
= Update::None
;
796 case LFUN_BUFFER_RELOAD
: {
797 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
798 docstring
const file
= makeDisplayPath(lyx_view_
->buffer()->absFileName(), 20);
799 docstring text
= bformat(_("Any changes will be lost. Are you sure "
800 "you want to revert to the saved version of the document %1$s?"), file
);
801 int const ret
= Alert::prompt(_("Revert to saved document?"),
802 text
, 1, 1, _("&Revert"), _("&Cancel"));
809 case LFUN_BUFFER_UPDATE
:
810 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
811 lyx_view_
->buffer()->doExport(argument
, true);
814 case LFUN_BUFFER_VIEW
:
815 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
816 lyx_view_
->buffer()->preview(argument
);
819 case LFUN_MASTER_BUFFER_UPDATE
:
820 LASSERT(lyx_view_
&& lyx_view_
->buffer() && lyx_view_
->buffer()->masterBuffer(), /**/);
821 lyx_view_
->buffer()->masterBuffer()->doExport(argument
, true);
824 case LFUN_MASTER_BUFFER_VIEW
:
825 LASSERT(lyx_view_
&& lyx_view_
->buffer() && lyx_view_
->buffer()->masterBuffer(), /**/);
826 lyx_view_
->buffer()->masterBuffer()->preview(argument
);
829 case LFUN_BUILD_PROGRAM
:
830 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
831 lyx_view_
->buffer()->doExport("program", true);
834 case LFUN_BUFFER_CHKTEX
:
835 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
836 lyx_view_
->buffer()->runChktex();
839 case LFUN_BUFFER_EXPORT
:
840 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
841 if (argument
== "custom")
842 dispatch(FuncRequest(LFUN_DIALOG_SHOW
, "sendto"));
844 lyx_view_
->buffer()->doExport(argument
, false);
847 case LFUN_BUFFER_EXPORT_CUSTOM
: {
848 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
850 string command
= split(argument
, format_name
, ' ');
851 Format
const * format
= formats
.getFormat(format_name
);
853 lyxerr
<< "Format \"" << format_name
854 << "\" not recognized!"
859 Buffer
* buffer
= lyx_view_
->buffer();
861 // The name of the file created by the conversion process
864 // Output to filename
865 if (format
->name() == "lyx") {
866 string
const latexname
= buffer
->latexName(false);
867 filename
= changeExtension(latexname
,
868 format
->extension());
869 filename
= addName(buffer
->temppath(), filename
);
871 if (!buffer
->writeFile(FileName(filename
)))
875 buffer
->doExport(format_name
, true, filename
);
878 // Substitute $$FName for filename
879 if (!contains(command
, "$$FName"))
880 command
= "( " + command
+ " ) < $$FName";
881 command
= subst(command
, "$$FName", filename
);
883 // Execute the command in the background
885 call
.startscript(Systemcall::DontWait
, command
);
889 case LFUN_BUFFER_PRINT
: {
890 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
891 // FIXME: cmd.getArg() might fail if one of the arguments
892 // contains double quotes
893 string target
= cmd
.getArg(0);
894 string target_name
= cmd
.getArg(1);
895 string command
= cmd
.getArg(2);
898 || target_name
.empty()
899 || command
.empty()) {
900 lyxerr
<< "Unable to parse \""
901 << argument
<< '"' << endl
;
904 if (target
!= "printer" && target
!= "file") {
905 lyxerr
<< "Unrecognized target \""
906 << target
<< '"' << endl
;
910 Buffer
* buffer
= lyx_view_
->buffer();
912 if (!buffer
->doExport("dvi", true)) {
913 showPrintError(buffer
->absFileName());
917 // Push directory path.
918 string
const path
= buffer
->temppath();
919 // Prevent the compiler from optimizing away p
923 // there are three cases here:
924 // 1. we print to a file
925 // 2. we print directly to a printer
926 // 3. we print using a spool command (print to file first)
929 string
const dviname
=
930 changeExtension(buffer
->latexName(true), "dvi");
932 if (target
== "printer") {
933 if (!lyxrc
.print_spool_command
.empty()) {
934 // case 3: print using a spool
935 string
const psname
=
936 changeExtension(dviname
,".ps");
937 command
+= ' ' + lyxrc
.print_to_file
940 + quoteName(dviname
);
943 lyxrc
.print_spool_command
+ ' ';
944 if (target_name
!= "default") {
945 command2
+= lyxrc
.print_spool_printerprefix
949 command2
+= quoteName(psname
);
951 // If successful, then spool command
952 res
= one
.startscript(
957 res
= one
.startscript(
958 Systemcall::DontWait
,
961 // case 2: print directly to a printer
962 if (target_name
!= "default")
963 command
+= ' ' + lyxrc
.print_to_printer
+ target_name
+ ' ';
964 res
= one
.startscript(
965 Systemcall::DontWait
,
966 command
+ quoteName(dviname
));
970 // case 1: print to a file
971 FileName
const filename(makeAbsPath(target_name
,
972 lyx_view_
->buffer()->filePath()));
973 FileName
const dvifile(makeAbsPath(dviname
, path
));
974 if (filename
.exists()) {
975 docstring text
= bformat(
976 _("The file %1$s already exists.\n\n"
977 "Do you want to overwrite that file?"),
978 makeDisplayPath(filename
.absFilename()));
979 if (Alert::prompt(_("Overwrite file?"),
980 text
, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
983 command
+= ' ' + lyxrc
.print_to_file
984 + quoteName(filename
.toFilesystemEncoding())
986 + quoteName(dvifile
.toFilesystemEncoding());
987 res
= one
.startscript(Systemcall::DontWait
,
992 showPrintError(buffer
->absFileName());
996 // FIXME: There is need for a command-line import.
998 case LFUN_BUFFER_IMPORT:
1003 case LFUN_BUFFER_AUTO_SAVE
:
1004 lyx_view_
->buffer()->autoSave();
1007 case LFUN_RECONFIGURE
:
1008 // argument is any additional parameter to the configure.py command
1009 reconfigure(lyx_view_
, argument
);
1012 case LFUN_HELP_OPEN
: {
1013 LASSERT(lyx_view_
, /**/);
1014 string
const arg
= argument
;
1016 setErrorMessage(from_ascii(N_("Missing argument")));
1019 FileName
const fname
= i18nLibFileSearch("doc", arg
, "lyx");
1020 if (fname
.empty()) {
1021 lyxerr
<< "LyX: unable to find documentation file `"
1022 << arg
<< "'. Bad installation?" << endl
;
1025 lyx_view_
->message(bformat(_("Opening help file %1$s..."),
1026 makeDisplayPath(fname
.absFilename())));
1027 Buffer
* buf
= lyx_view_
->loadDocument(fname
, false);
1030 lyx_view_
->setBuffer(buf
);
1031 buf
->errors("Parse");
1033 updateFlags
= Update::None
;
1037 // --- version control -------------------------------
1038 case LFUN_VC_REGISTER
:
1039 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
1040 if (!ensureBufferClean(view()))
1042 if (!lyx_view_
->buffer()->lyxvc().inUse()) {
1043 lyx_view_
->buffer()->lyxvc().registrer();
1046 updateFlags
= Update::Force
;
1049 case LFUN_VC_CHECK_IN
:
1050 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
1051 if (!ensureBufferClean(view()))
1053 if (lyx_view_
->buffer()->lyxvc().inUse()
1054 && !lyx_view_
->buffer()->isReadonly()) {
1055 lyx_view_
->buffer()->lyxvc().checkIn();
1060 case LFUN_VC_CHECK_OUT
:
1061 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
1062 if (!ensureBufferClean(view()))
1064 if (lyx_view_
->buffer()->lyxvc().inUse()) {
1065 lyx_view_
->buffer()->lyxvc().checkOut();
1070 case LFUN_VC_REVERT
:
1071 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
1072 lyx_view_
->buffer()->lyxvc().revert();
1076 case LFUN_VC_UNDO_LAST
:
1077 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
1078 lyx_view_
->buffer()->lyxvc().undoLast();
1082 // --- lyxserver commands ----------------------------
1083 case LFUN_SERVER_GET_FILENAME
:
1084 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
1085 setMessage(from_utf8(lyx_view_
->buffer()->absFileName()));
1086 LYXERR(Debug::INFO
, "FNAME["
1087 << lyx_view_
->buffer()->absFileName() << ']');
1090 case LFUN_SERVER_NOTIFY
:
1091 dispatch_buffer
= keyseq
.print(KeySequence::Portable
);
1092 theServer().notifyClient(to_utf8(dispatch_buffer
));
1095 case LFUN_SERVER_GOTO_FILE_ROW
: {
1096 LASSERT(lyx_view_
, /**/);
1099 istringstream
is(argument
);
1100 is
>> file_name
>> row
;
1102 bool loaded
= false;
1103 if (prefixIs(file_name
, package().temp_dir().absFilename()))
1104 // Needed by inverse dvi search. If it is a file
1105 // in tmpdir, call the apropriated function
1106 buf
= theBufferList().getBufferFromTmp(file_name
);
1108 // Must replace extension of the file to be .lyx
1109 // and get full path
1110 FileName
const s
= fileSearch(string(), changeExtension(file_name
, ".lyx"), "lyx");
1111 // Either change buffer or load the file
1112 if (theBufferList().exists(s
.absFilename()))
1113 buf
= theBufferList().getBuffer(s
.absFilename());
1115 buf
= lyx_view_
->loadDocument(s
);
1121 updateFlags
= Update::None
;
1126 lyx_view_
->setBuffer(buf
);
1127 view()->setCursorFromRow(row
);
1129 buf
->errors("Parse");
1130 updateFlags
= Update::FitCursor
;
1135 case LFUN_DIALOG_SHOW_NEW_INSET
: {
1136 LASSERT(lyx_view_
, /**/);
1137 string
const name
= cmd
.getArg(0);
1138 InsetCode code
= insetCode(name
);
1139 string data
= trim(to_utf8(cmd
.argument()).substr(name
.size()));
1140 bool insetCodeOK
= true;
1149 case HYPERLINK_CODE
: {
1150 InsetCommandParams
p(code
);
1151 data
= InsetCommand::params2string(name
, p
);
1154 case INCLUDE_CODE
: {
1155 // data is the include type: one of "include",
1156 // "input", "verbatiminput" or "verbatiminput*"
1158 // default type is requested
1160 InsetCommandParams
p(INCLUDE_CODE
, data
);
1161 data
= InsetCommand::params2string("include", p
);
1165 // \c data == "Boxed" || "Frameless" etc
1166 InsetBoxParams
p(data
);
1167 data
= InsetBox::params2string(p
);
1171 InsetBranchParams p
;
1172 data
= InsetBranch::params2string(p
);
1176 InsetCommandParams
p(CITE_CODE
);
1177 data
= InsetCommand::params2string(name
, p
);
1181 data
= InsetERT::params2string(InsetCollapsable::Open
);
1184 case EXTERNAL_CODE
: {
1185 InsetExternalParams p
;
1186 Buffer
const & buffer
= *lyx_view_
->buffer();
1187 data
= InsetExternal::params2string(p
, buffer
);
1192 data
= InsetFloat::params2string(p
);
1195 case LISTINGS_CODE
: {
1196 InsetListingsParams p
;
1197 data
= InsetListings::params2string(p
);
1200 case GRAPHICS_CODE
: {
1201 InsetGraphicsParams p
;
1202 Buffer
const & buffer
= *lyx_view_
->buffer();
1203 data
= InsetGraphics::params2string(p
, buffer
);
1208 data
= InsetNote::params2string(p
);
1213 data
= InsetSpace::params2string(p
);
1218 data
= InsetVSpace::params2string(space
);
1223 data
= InsetWrap::params2string(p
);
1227 lyxerr
<< "Inset type '" << name
<<
1228 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << endl
;
1229 insetCodeOK
= false;
1231 } // end switch(code)
1233 dispatch(FuncRequest(LFUN_DIALOG_SHOW
, name
+ " " + data
));
1237 case LFUN_CITATION_INSERT
: {
1238 LASSERT(lyx_view_
, /**/);
1239 if (!argument
.empty()) {
1240 // we can have one optional argument, delimited by '|'
1241 // citation-insert <key>|<text_before>
1242 // this should be enhanced to also support text_after
1243 // and citation style
1244 string arg
= argument
;
1246 if (contains(argument
, "|")) {
1247 arg
= token(argument
, '|', 0);
1248 opt1
= token(argument
, '|', 1);
1250 InsetCommandParams
icp(CITE_CODE
);
1251 icp
["key"] = from_utf8(arg
);
1253 icp
["before"] = from_utf8(opt1
);
1254 string icstr
= InsetCommand::params2string("citation", icp
);
1255 FuncRequest
fr(LFUN_INSET_INSERT
, icstr
);
1258 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET
, "citation"));
1262 case LFUN_BUFFER_CHILD_OPEN
: {
1263 LASSERT(lyx_view_
&& lyx_view_
->buffer(), /**/);
1264 Buffer
* parent
= lyx_view_
->buffer();
1265 FileName filename
= makeAbsPath(argument
, parent
->filePath());
1266 view()->saveBookmark(false);
1268 bool parsed
= false;
1269 if (theBufferList().exists(filename
.absFilename())) {
1270 child
= theBufferList().getBuffer(filename
.absFilename());
1272 setMessage(bformat(_("Opening child document %1$s..."),
1273 makeDisplayPath(filename
.absFilename())));
1274 child
= lyx_view_
->loadDocument(filename
, false);
1278 // Set the parent name of the child document.
1279 // This makes insertion of citations and references in the child work,
1280 // when the target is in the parent or another child document.
1281 child
->setParent(parent
);
1282 updateLabels(*child
->masterBuffer());
1283 lyx_view_
->setBuffer(child
);
1285 child
->errors("Parse");
1288 // If a screen update is required (in case where auto_open is false),
1289 // setBuffer() would have taken care of it already. Otherwise we shall
1290 // reset the update flag because it can cause a circular problem.
1292 updateFlags
= Update::None
;
1296 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE
:
1297 LASSERT(lyx_view_
, /**/);
1298 lyxrc
.cursor_follows_scrollbar
= !lyxrc
.cursor_follows_scrollbar
;
1301 case LFUN_KEYMAP_OFF
:
1302 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1303 lyx_view_
->view()->getIntl().keyMapOn(false);
1306 case LFUN_KEYMAP_PRIMARY
:
1307 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1308 lyx_view_
->view()->getIntl().keyMapPrim();
1311 case LFUN_KEYMAP_SECONDARY
:
1312 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1313 lyx_view_
->view()->getIntl().keyMapSec();
1316 case LFUN_KEYMAP_TOGGLE
:
1317 LASSERT(lyx_view_
&& lyx_view_
->view(), /**/);
1318 lyx_view_
->view()->getIntl().toggleKeyMap();
1324 string rest
= split(argument
, countstr
, ' ');
1325 istringstream
is(countstr
);
1328 lyxerr
<< "repeat: count: " << count
<< " cmd: " << rest
<< endl
;
1329 for (int i
= 0; i
< count
; ++i
)
1330 dispatch(lyxaction
.lookupFunc(rest
));
1334 case LFUN_COMMAND_SEQUENCE
: {
1335 // argument contains ';'-terminated commands
1336 string arg
= argument
;
1337 while (!arg
.empty()) {
1339 arg
= split(arg
, first
, ';');
1340 FuncRequest
func(lyxaction
.lookupFunc(first
));
1341 func
.origin
= cmd
.origin
;
1349 if (theTopLevelCmdDef().lock(argument
, func
)) {
1350 func
.origin
= cmd
.origin
;
1352 theTopLevelCmdDef().release(argument
);
1354 if (func
.action
== LFUN_UNKNOWN_ACTION
) {
1355 // unknown command definition
1356 lyxerr
<< "Warning: unknown command definition `"
1360 // recursion detected
1361 lyxerr
<< "Warning: Recursion in the command definition `"
1362 << argument
<< "' detected"
1369 case LFUN_PREFERENCES_SAVE
: {
1370 lyxrc
.write(makeAbsPath("preferences",
1371 package().user_support().absFilename()),
1377 LASSERT(lyx_view_
, /**/);
1378 lyx_view_
->message(from_utf8(argument
));
1381 case LFUN_BUFFER_LANGUAGE
: {
1382 LASSERT(lyx_view_
, /**/);
1383 Buffer
& buffer
= *lyx_view_
->buffer();
1384 Language
const * oldL
= buffer
.params().language
;
1385 Language
const * newL
= languages
.getLanguage(argument
);
1386 if (!newL
|| oldL
== newL
)
1389 if (oldL
->rightToLeft() == newL
->rightToLeft()
1390 && !buffer
.isMultiLingual())
1391 buffer
.changeLanguage(oldL
, newL
);
1395 case LFUN_BUFFER_SAVE_AS_DEFAULT
: {
1396 string
const fname
=
1397 addName(addPath(package().user_support().absFilename(), "templates/"),
1399 Buffer
defaults(fname
);
1401 istringstream
ss(argument
);
1404 int const unknown_tokens
= defaults
.readHeader(lex
);
1406 if (unknown_tokens
!= 0) {
1407 lyxerr
<< "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1408 << unknown_tokens
<< " unknown token"
1409 << (unknown_tokens
== 1 ? "" : "s")
1413 if (defaults
.writeFile(FileName(defaults
.absFileName())))
1414 setMessage(bformat(_("Document defaults saved in %1$s"),
1415 makeDisplayPath(fname
)));
1417 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1421 case LFUN_BUFFER_PARAMS_APPLY
: {
1422 LASSERT(lyx_view_
, /**/);
1424 Buffer
* buffer
= lyx_view_
->buffer();
1425 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1426 Cursor
& cur
= view()->cursor();
1427 cur
.recordUndoFullDocument();
1429 istringstream
ss(argument
);
1432 int const unknown_tokens
= buffer
->readHeader(lex
);
1434 if (unknown_tokens
!= 0) {
1435 lyxerr
<< "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1436 << unknown_tokens
<< " unknown token"
1437 << (unknown_tokens
== 1 ? "" : "s")
1441 updateLayout(oldClass
, buffer
);
1443 updateFlags
= Update::Force
| Update::FitCursor
;
1444 // We are most certainly here because of a change in the document
1445 // It is then better to make sure that all dialogs are in sync with
1446 // current document settings. LyXView::restartCursor() achieve this.
1447 lyx_view_
->restartCursor();
1451 case LFUN_LAYOUT_MODULES_CLEAR
: {
1452 LASSERT(lyx_view_
, /**/);
1453 Buffer
* buffer
= lyx_view_
->buffer();
1454 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1455 view()->cursor().recordUndoFullDocument();
1456 buffer
->params().clearLayoutModules();
1457 buffer
->params().makeDocumentClass();
1458 updateLayout(oldClass
, buffer
);
1459 updateFlags
= Update::Force
| Update::FitCursor
;
1463 case LFUN_LAYOUT_MODULE_ADD
: {
1464 LASSERT(lyx_view_
, /**/);
1465 Buffer
* buffer
= lyx_view_
->buffer();
1466 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1467 view()->cursor().recordUndoFullDocument();
1468 buffer
->params().addLayoutModule(argument
);
1469 buffer
->params().makeDocumentClass();
1470 updateLayout(oldClass
, buffer
);
1471 updateFlags
= Update::Force
| Update::FitCursor
;
1475 case LFUN_TEXTCLASS_APPLY
: {
1476 LASSERT(lyx_view_
, /**/);
1477 Buffer
* buffer
= lyx_view_
->buffer();
1479 if (!loadLayoutFile(argument
, buffer
->temppath()) &&
1480 !loadLayoutFile(argument
, buffer
->filePath()))
1483 LayoutFile
const * old_layout
= buffer
->params().baseClass();
1484 LayoutFile
const * new_layout
= &(LayoutFileList::get()[argument
]);
1486 if (old_layout
== new_layout
)
1490 //Save the old, possibly modular, layout for use in conversion.
1491 DocumentClass
const * const oldDocClass
= buffer
->params().documentClassPtr();
1492 view()->cursor().recordUndoFullDocument();
1493 buffer
->params().setBaseClass(argument
);
1494 buffer
->params().makeDocumentClass();
1495 updateLayout(oldDocClass
, buffer
);
1496 updateFlags
= Update::Force
| Update::FitCursor
;
1500 case LFUN_LAYOUT_RELOAD
: {
1501 LASSERT(lyx_view_
, /**/);
1502 Buffer
* buffer
= lyx_view_
->buffer();
1503 DocumentClass
const * const oldClass
= buffer
->params().documentClassPtr();
1504 LayoutFileIndex bc
= buffer
->params().baseClassID();
1505 LayoutFileList::get().reset(bc
);
1506 buffer
->params().setBaseClass(bc
);
1507 buffer
->params().makeDocumentClass();
1508 updateLayout(oldClass
, buffer
);
1509 updateFlags
= Update::Force
| Update::FitCursor
;
1513 case LFUN_TEXTCLASS_LOAD
:
1514 loadLayoutFile(argument
, lyx_view_
->buffer()->temppath()) ||
1515 loadLayoutFile(argument
, lyx_view_
->buffer()->filePath());
1518 case LFUN_LYXRC_APPLY
: {
1519 LyXRC
const lyxrc_orig
= lyxrc
;
1521 istringstream
ss(argument
);
1522 bool const success
= lyxrc
.read(ss
) == 0;
1525 lyxerr
<< "Warning in LFUN_LYXRC_APPLY!\n"
1526 << "Unable to read lyxrc data"
1531 actOnUpdatedPrefs(lyxrc_orig
, lyxrc
);
1533 theApp()->resetGui();
1535 /// We force the redraw in any case because there might be
1536 /// some screen font changes.
1537 /// FIXME: only the current view will be updated. the Gui
1538 /// class is able to furnish the list of views.
1539 updateFlags
= Update::Force
;
1543 case LFUN_BOOKMARK_GOTO
:
1544 // go to bookmark, open unopened file and switch to buffer if necessary
1545 gotoBookmark(convert
<unsigned int>(to_utf8(cmd
.argument())), true, true);
1546 updateFlags
= Update::FitCursor
;
1549 case LFUN_BOOKMARK_CLEAR
:
1550 theSession().bookmarks().clear();
1554 LASSERT(theApp(), /**/);
1555 // Let the frontend dispatch its own actions.
1556 if (theApp()->dispatch(cmd
))
1557 // Nothing more to do.
1560 // Everything below is only for active lyx_view_
1564 // Let the current LyXView dispatch its own actions.
1565 if (lyx_view_
->dispatch(cmd
)) {
1566 if (lyx_view_
->view())
1567 updateFlags
= lyx_view_
->view()->cursor().result().update();
1571 LASSERT(lyx_view_
->view(), /**/);
1572 // Let the current BufferView dispatch its own actions.
1573 if (view()->dispatch(cmd
)) {
1574 // The BufferView took care of its own updates if needed.
1575 updateFlags
= Update::None
;
1579 // Let the current Cursor dispatch its own actions.
1580 Cursor old
= view()->cursor();
1581 view()->cursor().getPos(cursorPosBeforeDispatchX_
,
1582 cursorPosBeforeDispatchY_
);
1583 view()->cursor().dispatch(cmd
);
1585 // notify insets we just left
1586 if (view()->cursor() != old
) {
1588 bool badcursor
= notifyCursorLeaves(old
, view()->cursor());
1590 view()->cursor().fixIfBroken();
1593 // update completion. We do it here and not in
1594 // processKeySym to avoid another redraw just for a
1595 // changed inline completion
1596 if (cmd
.origin
== FuncRequest::KEYBOARD
) {
1597 if (cmd
.action
== LFUN_SELF_INSERT
)
1598 lyx_view_
->updateCompletion(view()->cursor(), true, true);
1599 else if (cmd
.action
== LFUN_CHAR_DELETE_BACKWARD
)
1600 lyx_view_
->updateCompletion(view()->cursor(), false, true);
1602 lyx_view_
->updateCompletion(view()->cursor(), false, false);
1605 updateFlags
= view()->cursor().result().update();
1608 if (lyx_view_
&& lyx_view_
->buffer()) {
1609 // BufferView::update() updates the ViewMetricsInfo and
1610 // also initializes the position cache for all insets in
1611 // (at least partially) visible top-level paragraphs.
1612 // We will redraw the screen only if needed.
1613 view()->processUpdateFlags(updateFlags
);
1615 // if we executed a mutating lfun, mark the buffer as dirty
1617 && !lyxaction
.funcHasFlag(action
, LyXAction::NoBuffer
)
1618 && !lyxaction
.funcHasFlag(action
, LyXAction::ReadOnly
))
1619 lyx_view_
->buffer()->markDirty();
1621 // Do we have a selection?
1622 theSelection().haveSelection(view()->cursor().selection());
1625 lyx_view_
->restartCursor();
1629 // Some messages may already be translated, so we cannot use _()
1630 sendDispatchMessage(translateIfPossible(getMessage()), cmd
);
1635 void LyXFunc::sendDispatchMessage(docstring
const & msg
, FuncRequest
const & cmd
)
1637 const bool verbose
= (cmd
.origin
== FuncRequest::MENU
1638 || cmd
.origin
== FuncRequest::TOOLBAR
1639 || cmd
.origin
== FuncRequest::COMMANDBUFFER
);
1641 if (cmd
.action
== LFUN_SELF_INSERT
|| !verbose
) {
1642 LYXERR(Debug::ACTION
, "dispatch msg is " << to_utf8(msg
));
1644 lyx_view_
->message(msg
);
1648 docstring dispatch_msg
= msg
;
1649 if (!dispatch_msg
.empty())
1650 dispatch_msg
+= ' ';
1652 docstring comname
= from_utf8(lyxaction
.getActionName(cmd
.action
));
1654 bool argsadded
= false;
1656 if (!cmd
.argument().empty()) {
1657 if (cmd
.action
!= LFUN_UNKNOWN_ACTION
) {
1658 comname
+= ' ' + cmd
.argument();
1663 docstring
const shortcuts
= theTopLevelKeymap().printBindings(cmd
);
1665 if (!shortcuts
.empty())
1666 comname
+= ": " + shortcuts
;
1667 else if (!argsadded
&& !cmd
.argument().empty())
1668 comname
+= ' ' + cmd
.argument();
1670 if (!comname
.empty()) {
1671 comname
= rtrim(comname
);
1672 dispatch_msg
+= '(' + rtrim(comname
) + ')';
1675 LYXERR(Debug::ACTION
, "verbose dispatch msg " << to_utf8(dispatch_msg
));
1676 if (!dispatch_msg
.empty())
1677 lyx_view_
->message(dispatch_msg
);
1681 void LyXFunc::reloadBuffer()
1683 FileName filename
= lyx_view_
->buffer()->fileName();
1684 // The user has already confirmed that the changes, if any, should
1685 // be discarded. So we just release the Buffer and don't call closeBuffer();
1686 theBufferList().release(lyx_view_
->buffer());
1687 Buffer
* buf
= lyx_view_
->loadDocument(filename
);
1688 docstring
const disp_fn
= makeDisplayPath(filename
.absFilename());
1692 lyx_view_
->setBuffer(buf
);
1693 buf
->errors("Parse");
1694 str
= bformat(_("Document %1$s reloaded."), disp_fn
);
1696 str
= bformat(_("Could not reload document %1$s"), disp_fn
);
1698 lyx_view_
->message(str
);
1701 // Each "lyx_view_" should have it's own message method. lyxview and
1702 // the minibuffer would use the minibuffer, but lyxserver would
1703 // send an ERROR signal to its client. Alejandro 970603
1704 // This function is bit problematic when it comes to NLS, to make the
1705 // lyx servers client be language indepenent we must not translate
1706 // strings sent to this func.
1707 void LyXFunc::setErrorMessage(docstring
const & m
) const
1709 dispatch_buffer
= m
;
1714 void LyXFunc::setMessage(docstring
const & m
) const
1716 dispatch_buffer
= m
;
1720 docstring
LyXFunc::viewStatusMessage()
1722 // When meta-fake key is pressed, show the key sequence so far + "M-".
1724 return keyseq
.print(KeySequence::ForGui
) + "M-";
1726 // Else, when a non-complete key sequence is pressed,
1727 // show the available options.
1728 if (keyseq
.length() > 0 && !keyseq
.deleted())
1729 return keyseq
.printOptions(true);
1731 LASSERT(lyx_view_
, /**/);
1732 if (!lyx_view_
->buffer())
1733 return _("Welcome to LyX!");
1735 return view()->cursor().currentState();
1739 BufferView
* LyXFunc::view() const
1741 LASSERT(lyx_view_
, /**/);
1742 return lyx_view_
->view();
1746 bool LyXFunc::wasMetaKey() const
1748 return (meta_fake_bit
!= NoModifier
);
1752 void LyXFunc::updateLayout(DocumentClass
const * const oldlayout
, Buffer
* buffer
)
1754 lyx_view_
->message(_("Converting document to new document class..."));
1756 StableDocIterator
backcur(view()->cursor());
1757 ErrorList
& el
= buffer
->errorList("Class Switch");
1758 cap::switchBetweenClasses(
1759 oldlayout
, buffer
->params().documentClassPtr(),
1760 static_cast<InsetText
&>(buffer
->inset()), el
);
1762 view()->setCursor(backcur
.asDocIterator(&(buffer
->inset())));
1764 buffer
->errors("Class Switch");
1765 updateLabels(*buffer
);
1771 void actOnUpdatedPrefs(LyXRC
const & lyxrc_orig
, LyXRC
const & lyxrc_new
)
1773 // Why the switch you might ask. It is a trick to ensure that all
1774 // the elements in the LyXRCTags enum is handled. As you can see
1775 // there are no breaks at all. So it is just a huge fall-through.
1776 // The nice thing is that we will get a warning from the compiler
1777 // if we forget an element.
1778 LyXRC::LyXRCTags tag
= LyXRC::RC_LAST
;
1780 case LyXRC::RC_ACCEPT_COMPOUND
:
1781 case LyXRC::RC_ALT_LANG
:
1782 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND
:
1783 case LyXRC::RC_PLAINTEXT_LINELEN
:
1784 case LyXRC::RC_AUTOREGIONDELETE
:
1785 case LyXRC::RC_AUTORESET_OPTIONS
:
1786 case LyXRC::RC_AUTOSAVE
:
1787 case LyXRC::RC_AUTO_NUMBER
:
1788 case LyXRC::RC_BACKUPDIR_PATH
:
1789 case LyXRC::RC_BIBTEX_COMMAND
:
1790 case LyXRC::RC_BINDFILE
:
1791 case LyXRC::RC_CHECKLASTFILES
:
1792 case LyXRC::RC_COMPLETION_CURSOR_TEXT
:
1793 case LyXRC::RC_COMPLETION_INLINE_DELAY
:
1794 case LyXRC::RC_COMPLETION_INLINE_DOTS
:
1795 case LyXRC::RC_COMPLETION_INLINE_MATH
:
1796 case LyXRC::RC_COMPLETION_INLINE_TEXT
:
1797 case LyXRC::RC_COMPLETION_POPUP_AFTER_COMPLETE
:
1798 case LyXRC::RC_COMPLETION_POPUP_DELAY
:
1799 case LyXRC::RC_COMPLETION_POPUP_MATH
:
1800 case LyXRC::RC_COMPLETION_POPUP_TEXT
:
1801 case LyXRC::RC_USELASTFILEPOS
:
1802 case LyXRC::RC_LOADSESSION
:
1803 case LyXRC::RC_CHKTEX_COMMAND
:
1804 case LyXRC::RC_CONVERTER
:
1805 case LyXRC::RC_CONVERTER_CACHE_MAXAGE
:
1806 case LyXRC::RC_COPIER
:
1807 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR
:
1808 case LyXRC::RC_CUSTOM_EXPORT_COMMAND
:
1809 case LyXRC::RC_CUSTOM_EXPORT_FORMAT
:
1810 case LyXRC::RC_DATE_INSERT_FORMAT
:
1811 case LyXRC::RC_DEFAULT_LANGUAGE
:
1812 case LyXRC::RC_GUI_LANGUAGE
:
1813 case LyXRC::RC_DEFAULT_PAPERSIZE
:
1814 case LyXRC::RC_DEFFILE
:
1815 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN
:
1816 case LyXRC::RC_DISPLAY_GRAPHICS
:
1817 case LyXRC::RC_DOCUMENTPATH
:
1818 if (lyxrc_orig
.document_path
!= lyxrc_new
.document_path
) {
1819 FileName
path(lyxrc_new
.document_path
);
1820 if (path
.exists() && path
.isDirectory())
1821 package().document_dir() = FileName(lyxrc
.document_path
);
1823 case LyXRC::RC_ESC_CHARS
:
1824 case LyXRC::RC_EXAMPLEPATH
:
1825 case LyXRC::RC_FONT_ENCODING
:
1826 case LyXRC::RC_FORMAT
:
1827 case LyXRC::RC_GROUP_LAYOUTS
:
1828 case LyXRC::RC_INDEX_COMMAND
:
1829 case LyXRC::RC_INPUT
:
1830 case LyXRC::RC_KBMAP
:
1831 case LyXRC::RC_KBMAP_PRIMARY
:
1832 case LyXRC::RC_KBMAP_SECONDARY
:
1833 case LyXRC::RC_LABEL_INIT_LENGTH
:
1834 case LyXRC::RC_LANGUAGE_AUTO_BEGIN
:
1835 case LyXRC::RC_LANGUAGE_AUTO_END
:
1836 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN
:
1837 case LyXRC::RC_LANGUAGE_COMMAND_END
:
1838 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL
:
1839 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS
:
1840 case LyXRC::RC_LANGUAGE_PACKAGE
:
1841 case LyXRC::RC_LANGUAGE_USE_BABEL
:
1842 case LyXRC::RC_MAC_LIKE_WORD_MOVEMENT
:
1843 case LyXRC::RC_MACRO_EDIT_STYLE
:
1844 case LyXRC::RC_MAKE_BACKUP
:
1845 case LyXRC::RC_MARK_FOREIGN_LANGUAGE
:
1846 case LyXRC::RC_MOUSE_WHEEL_SPEED
:
1847 case LyXRC::RC_NUMLASTFILES
:
1848 case LyXRC::RC_PATH_PREFIX
:
1849 if (lyxrc_orig
.path_prefix
!= lyxrc_new
.path_prefix
) {
1850 prependEnvPath("PATH", lyxrc
.path_prefix
);
1852 case LyXRC::RC_PERS_DICT
:
1853 case LyXRC::RC_PREVIEW
:
1854 case LyXRC::RC_PREVIEW_HASHED_LABELS
:
1855 case LyXRC::RC_PREVIEW_SCALE_FACTOR
:
1856 case LyXRC::RC_PRINTCOLLCOPIESFLAG
:
1857 case LyXRC::RC_PRINTCOPIESFLAG
:
1858 case LyXRC::RC_PRINTER
:
1859 case LyXRC::RC_PRINTEVENPAGEFLAG
:
1860 case LyXRC::RC_PRINTEXSTRAOPTIONS
:
1861 case LyXRC::RC_PRINTFILEEXTENSION
:
1862 case LyXRC::RC_PRINTLANDSCAPEFLAG
:
1863 case LyXRC::RC_PRINTODDPAGEFLAG
:
1864 case LyXRC::RC_PRINTPAGERANGEFLAG
:
1865 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG
:
1866 case LyXRC::RC_PRINTPAPERFLAG
:
1867 case LyXRC::RC_PRINTREVERSEFLAG
:
1868 case LyXRC::RC_PRINTSPOOL_COMMAND
:
1869 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX
:
1870 case LyXRC::RC_PRINTTOFILE
:
1871 case LyXRC::RC_PRINTTOPRINTER
:
1872 case LyXRC::RC_PRINT_ADAPTOUTPUT
:
1873 case LyXRC::RC_PRINT_COMMAND
:
1874 case LyXRC::RC_RTL_SUPPORT
:
1875 case LyXRC::RC_SCREEN_DPI
:
1876 case LyXRC::RC_SCREEN_FONT_ROMAN
:
1877 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY
:
1878 case LyXRC::RC_SCREEN_FONT_SANS
:
1879 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY
:
1880 case LyXRC::RC_SCREEN_FONT_SCALABLE
:
1881 case LyXRC::RC_SCREEN_FONT_SIZES
:
1882 case LyXRC::RC_SCREEN_FONT_TYPEWRITER
:
1883 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY
:
1884 case LyXRC::RC_GEOMETRY_SESSION
:
1885 case LyXRC::RC_SCREEN_ZOOM
:
1886 case LyXRC::RC_SERVERPIPE
:
1887 case LyXRC::RC_SET_COLOR
:
1888 case LyXRC::RC_SHOW_BANNER
:
1889 case LyXRC::RC_OPEN_BUFFERS_IN_TABS
:
1890 case LyXRC::RC_SPELL_COMMAND
:
1891 case LyXRC::RC_TEMPDIRPATH
:
1892 case LyXRC::RC_TEMPLATEPATH
:
1893 case LyXRC::RC_TEX_ALLOWS_SPACES
:
1894 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS
:
1895 if (lyxrc_orig
.windows_style_tex_paths
!= lyxrc_new
.windows_style_tex_paths
) {
1896 os::windows_style_tex_paths(lyxrc_new
.windows_style_tex_paths
);
1898 case LyXRC::RC_UIFILE
:
1899 case LyXRC::RC_USER_EMAIL
:
1900 case LyXRC::RC_USER_NAME
:
1901 case LyXRC::RC_USETEMPDIR
:
1902 case LyXRC::RC_USE_ALT_LANG
:
1903 case LyXRC::RC_USE_CONVERTER_CACHE
:
1904 case LyXRC::RC_USE_ESC_CHARS
:
1905 case LyXRC::RC_USE_INP_ENC
:
1906 case LyXRC::RC_USE_PERS_DICT
:
1907 case LyXRC::RC_USE_TOOLTIP
:
1908 case LyXRC::RC_USE_PIXMAP_CACHE
:
1909 case LyXRC::RC_USE_SPELL_LIB
:
1910 case LyXRC::RC_VIEWDVI_PAPEROPTION
:
1911 case LyXRC::RC_SORT_LAYOUTS
:
1912 case LyXRC::RC_FULL_SCREEN_LIMIT
:
1913 case LyXRC::RC_FULL_SCREEN_SCROLLBAR
:
1914 case LyXRC::RC_FULL_SCREEN_TABBAR
:
1915 case LyXRC::RC_FULL_SCREEN_TOOLBARS
:
1916 case LyXRC::RC_FULL_SCREEN_WIDTH
:
1917 case LyXRC::RC_VISUAL_CURSOR
:
1918 case LyXRC::RC_VIEWER
:
1919 case LyXRC::RC_LAST
: