2 * \file BufferView_pimpl.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Asger Alstrup
7 * \author Alfredo Braunstein
8 * \author Lars Gullik Bjønnes
9 * \author Jean-Marc Lasgouttes
10 * \author Angus Leeming
12 * \author André Pönitz
14 * \author Jürgen Vigna
16 * Full author contact details are available in file CREDITS.
21 #include "BufferView_pimpl.h"
23 #include "buffer_funcs.h"
24 #include "bufferlist.h"
25 #include "bufferparams.h"
28 #include "dispatchresult.h"
30 #include "FloatList.h"
31 #include "funcrequest.h"
34 #include "iterators.h"
35 #include "lyx_cb.h" // added for Dispatch functions
41 #include "lastfiles.h"
42 #include "paragraph.h"
43 #include "paragraph_funcs.h"
44 #include "ParagraphParameters.h"
48 #include "insets/insetref.h"
49 #include "insets/insettext.h"
51 #include "frontends/Alert.h"
52 #include "frontends/Dialogs.h"
53 #include "frontends/FileDialog.h"
54 #include "frontends/LyXView.h"
55 #include "frontends/LyXScreenFactory.h"
56 #include "frontends/screen.h"
57 #include "frontends/WorkArea.h"
58 #include "frontends/WorkAreaFactory.h"
60 #include "graphics/Previews.h"
62 #include "support/filetools.h"
63 #include "support/globbing.h"
64 #include "support/path_defines.h"
65 #include "support/tostr.h"
67 #include <boost/bind.hpp>
71 using lyx::support::AddPath;
72 using lyx::support::bformat;
73 using lyx::support::FileFilterList;
74 using lyx::support::FileSearch;
75 using lyx::support::IsDirWriteable;
76 using lyx::support::MakeDisplayPath;
77 using lyx::support::strToUnsignedInt;
78 using lyx::support::system_lyxdir;
81 using std::istringstream;
87 extern BufferList bufferlist;
92 unsigned int const saved_positions_num = 20;
94 // All the below connection objects are needed because of a bug in some
95 // versions of GCC (<=2.96 are on the suspects list.) By having and assigning
96 // to these connections we avoid a segfault upon startup, and also at exit.
99 boost::signals::connection dispatchcon;
100 boost::signals::connection timecon;
101 boost::signals::connection doccon;
102 boost::signals::connection resizecon;
103 boost::signals::connection kpresscon;
104 boost::signals::connection selectioncon;
105 boost::signals::connection lostcon;
111 BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner,
112 int xpos, int ypos, int width, int height)
113 : bv_(&bv), owner_(owner), buffer_(0), cursor_timeout(400),
114 using_xterm_cursor(false), cursor_(bv)
116 xsel_cache_.set = false;
118 workarea_.reset(WorkAreaFactory::create(xpos, ypos, width, height));
119 screen_.reset(LyXScreenFactory::create(workarea()));
122 doccon = workarea().scrollDocView
123 .connect(boost::bind(&BufferView::Pimpl::scrollDocView, this, _1));
124 resizecon = workarea().workAreaResize
125 .connect(boost::bind(&BufferView::Pimpl::workAreaResize, this));
126 dispatchcon = workarea().dispatch
127 .connect(boost::bind(&BufferView::Pimpl::workAreaDispatch, this, _1));
128 kpresscon = workarea().workAreaKeyPress
129 .connect(boost::bind(&BufferView::Pimpl::workAreaKeyPress, this, _1, _2));
130 selectioncon = workarea().selectionRequested
131 .connect(boost::bind(&BufferView::Pimpl::selectionRequested, this));
132 lostcon = workarea().selectionLost
133 .connect(boost::bind(&BufferView::Pimpl::selectionLost, this));
135 timecon = cursor_timeout.timeout
136 .connect(boost::bind(&BufferView::Pimpl::cursorToggle, this));
137 cursor_timeout.start();
138 saved_positions.resize(saved_positions_num);
142 void BufferView::Pimpl::addError(ErrorItem const & ei)
144 errorlist_.push_back(ei);
148 void BufferView::Pimpl::showReadonly(bool)
150 owner_->updateWindowTitle();
151 owner_->getDialogs().updateBufferDependent(false);
155 void BufferView::Pimpl::connectBuffer(Buffer & buf)
157 if (errorConnection_.connected())
162 boost::bind(&BufferView::Pimpl::addError, this, _1));
166 boost::bind(&LyXView::message, owner_, _1));
170 boost::bind(&LyXView::busy, owner_, _1));
173 buf.updateTitles.connect(
174 boost::bind(&LyXView::updateWindowTitle, owner_));
177 buf.resetAutosaveTimers.connect(
178 boost::bind(&LyXView::resetAutosaveTimer, owner_));
180 readonlyConnection_ =
181 buf.readonly.connect(
182 boost::bind(&BufferView::Pimpl::showReadonly, this, _1));
186 boost::bind(&BufferView::Pimpl::setBuffer, this, (Buffer *)0));
190 void BufferView::Pimpl::disconnectBuffer()
192 errorConnection_.disconnect();
193 messageConnection_.disconnect();
194 busyConnection_.disconnect();
195 titleConnection_.disconnect();
196 timerConnection_.disconnect();
197 readonlyConnection_.disconnect();
198 closingConnection_.disconnect();
202 void BufferView::Pimpl::newFile(string const & filename, string const & tname,
205 setBuffer(::newFile(filename, tname, isNamed));
209 bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles)
211 // get absolute path of file and add ".lyx" to the filename if
213 string s = FileSearch(string(), filename, "lyx");
215 bool const found = !s.empty();
220 // file already open?
221 if (bufferlist.exists(s)) {
222 string const file = MakeDisplayPath(s, 20);
223 string text = bformat(_("The document %1$s is already "
224 "loaded.\n\nDo you want to revert "
225 "to the saved version?"), file);
226 int const ret = Alert::prompt(_("Revert to saved document?"),
227 text, 0, 1, _("&Revert"), _("&Switch to document"));
230 setBuffer(bufferlist.getBuffer(s));
233 // FIXME: should be LFUN_REVERT
234 if (!bufferlist.close(bufferlist.getBuffer(s), false))
236 // Fall through to new load. (Asger)
242 b = bufferlist.newBuffer(s);
244 if (!::loadLyXFile(b, s)) {
245 bufferlist.release(b);
249 string text = bformat(_("The document %1$s does not yet "
250 "exist.\n\nDo you want to create "
251 "a new document?"), s);
252 int const ret = Alert::prompt(_("Create new document?"),
253 text, 0, 1, _("&Create"), _("Cancel"));
256 b = ::newFile(s, string(), true);
262 bv_->showErrorList(_("Parse"));
265 LyX::ref().lastfiles().newFile(b->fileName());
271 WorkArea & BufferView::Pimpl::workarea() const
273 return *workarea_.get();
277 LyXScreen & BufferView::Pimpl::screen() const
279 return *screen_.get();
283 Painter & BufferView::Pimpl::painter() const
285 return workarea().getPainter();
289 void BufferView::Pimpl::top_y(int y)
295 int BufferView::Pimpl::top_y() const
301 void BufferView::Pimpl::setBuffer(Buffer * b)
303 lyxerr[Debug::INFO] << "Setting buffer in BufferView ("
308 // set current buffer
313 cursor_ = LCursor(*bv_);
315 // if we're quitting lyx, don't bother updating stuff
320 lyxerr[Debug::INFO] << "Buffer addr: " << buffer_ << endl;
321 connectBuffer(*buffer_);
323 cursor_.push(buffer_->inset());
324 cursor_.resetAnchor();
325 buffer_->text().init(bv_);
327 // If we don't have a text object for this, we make one
328 //if (bv_->text() == 0)
329 // resizeCurrentBuffer();
331 // Buffer-dependent dialogs should be updated or
332 // hidden. This should go here because some dialogs (eg ToC)
333 // require bv_->text.
334 owner_->getDialogs().updateBufferDependent(true);
335 owner_->setLayout(bv_->text()->getPar(0)->layout()->name());
337 lyxerr[Debug::INFO] << " No Buffer!" << endl;
338 // we are closing the buffer, use the first buffer as current
339 buffer_ = bufferlist.first();
340 owner_->getDialogs().hideBufferDependent();
345 owner_->updateMenubar();
346 owner_->updateToolbar();
347 owner_->updateLayoutChoice();
348 owner_->updateWindowTitle();
350 if (lyx::graphics::Previews::activated() && buffer_)
351 lyx::graphics::Previews::get().generateBufferPreviews(*buffer_);
355 bool BufferView::Pimpl::fitCursor()
357 if (!screen().fitCursor(bv_))
364 void BufferView::Pimpl::redoCurrentBuffer()
366 lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
367 if (buffer_ && bv_->text()) {
368 resizeCurrentBuffer();
370 owner_->updateLayoutChoice();
375 void BufferView::Pimpl::resizeCurrentBuffer()
377 lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
380 int selstartpar = -1;
384 pos_type selstartpos = 0;
385 pos_type selendpos = 0;
387 bool mark_set = false;
391 owner_->message(_("Formatting document..."));
393 LyXText * text = bv_->text();
394 lyxerr << "### resizeCurrentBuffer: text " << text << endl;
398 LCursor & cur = bv_->cursor();
401 selstartpar = cur.selBegin().par();
402 selstartpos = cur.selBegin().pos();
403 selendpar = cur.selEnd().par();
404 selendpos = cur.selEnd().pos();
405 sel = cur.selection();
406 mark_set = cur.mark();
411 cur.selection() = true;
412 // At this point just to avoid the Delete-Empty-Paragraph-
413 // Mechanism when setting the cursor.
414 cur.mark() = mark_set;
416 text->setCursor(cur, selstartpar, selstartpos);
418 text->setCursor(cur, selendpar, selendpos);
420 text->setCursor(cur, par, pos);
422 text->setCursor(cur, par, pos);
424 cur.selection() = false;
433 // reset the "Formatting..." message
434 owner_->clearMessage();
440 void BufferView::Pimpl::updateScrollbar()
443 lyxerr[Debug::GUI] << "no text in updateScrollbar" << endl;
444 lyxerr << "no text in updateScrollbar" << endl;
445 workarea().setScrollbarParams(0, 0, 0);
449 LyXText const & t = *bv_->text();
452 << "Updating scrollbar: height: " << t.height()
453 << " top_y: " << top_y()
454 << " default height " << defaultRowHeight() << endl;
456 workarea().setScrollbarParams(t.height(), top_y(), defaultRowHeight());
460 void BufferView::Pimpl::scrollDocView(int value)
462 lyxerr[Debug::GUI] << "scrollDocView of " << value << endl;
467 screen().hideCursor();
470 screen().redraw(*bv_);
472 if (!lyxrc.cursor_follows_scrollbar)
475 int const height = defaultRowHeight();
476 int const first = top_y() + height;
477 int const last = top_y() + workarea().workHeight() - height;
479 bv_->cursor().reset();
480 LyXText * text = bv_->text();
481 CursorSlice & cur = bv_->cursor().front();
482 int y = text->cursorY(cur);
484 text->setCursorFromCoordinates(bv_->cursor(), 0, first);
486 text->setCursorFromCoordinates(bv_->cursor(), 0, last);
488 owner_->updateLayoutChoice();
492 void BufferView::Pimpl::scroll(int lines)
497 LyXText const * t = bv_->text();
498 int const line_height = defaultRowHeight();
500 // The new absolute coordinate
501 int new_top_y = top_y() + lines * line_height;
503 // Restrict to a valid value
504 new_top_y = std::min(t->height() - 4 * line_height, new_top_y);
505 new_top_y = std::max(0, new_top_y);
507 scrollDocView(new_top_y);
509 // Update the scrollbar.
510 workarea().setScrollbarParams(t->height(), top_y(), defaultRowHeight());
514 void BufferView::Pimpl::workAreaKeyPress(LyXKeySymPtr key,
515 key_modifier::state state)
517 bv_->owner()->getLyXFunc().processKeySym(key, state);
519 /* This is perhaps a bit of a hack. When we move
520 * around, or type, it's nice to be able to see
521 * the cursor immediately after the keypress. So
522 * we reset the toggle timeout and force the visibility
523 * of the cursor. Note we cannot do this inside
524 * dispatch() itself, because that's called recursively.
527 cursor_timeout.restart();
528 screen().showCursor(*bv_);
533 void BufferView::Pimpl::selectionRequested()
540 LCursor & cur = bv_->cursor();
542 if (!cur.selection()) {
543 xsel_cache_.set = false;
547 if (!xsel_cache_.set ||
548 cur.back() != xsel_cache_.cursor ||
549 cur.anchor_.back() != xsel_cache_.anchor)
551 xsel_cache_.cursor = cur.back();
552 xsel_cache_.anchor = cur.anchor_.back();
553 xsel_cache_.set = cur.selection();
554 sel = cur.selectionAsString(false);
556 workarea().putClipboard(sel);
561 void BufferView::Pimpl::selectionLost()
564 screen().hideCursor();
565 bv_->cursor().clearSelection();
566 xsel_cache_.set = false;
571 void BufferView::Pimpl::workAreaResize()
573 static int work_area_width;
574 static int work_area_height;
576 bool const widthChange = workarea().workWidth() != work_area_width;
577 bool const heightChange = workarea().workHeight() != work_area_height;
579 // update from work area
580 work_area_width = workarea().workWidth();
581 work_area_height = workarea().workHeight();
583 if (buffer_ && widthChange) {
584 // The visible LyXView need a resize
585 resizeCurrentBuffer();
588 if (widthChange || heightChange)
591 // always make sure that the scrollbar is sane.
593 owner_->updateLayoutChoice();
597 void BufferView::Pimpl::update()
599 //lyxerr << "BufferView::Pimpl::update(), buffer: " << buffer_ << endl;
600 // fix cursor coordinate cache in case something went wrong
602 // check needed to survive LyX startup
604 // update all 'visible' paragraphs
605 ParagraphList::iterator beg;
606 ParagraphList::iterator end;
607 getParsInRange(buffer_->paragraphs(),
608 top_y(), top_y() + workarea().workHeight(),
610 bv_->text()->redoParagraphs(beg, end);
613 screen().redraw(*bv_);
614 bv_->owner()->view_state_changed();
618 // Callback for cursor timer
619 void BufferView::Pimpl::cursorToggle()
622 screen().toggleCursor(*bv_);
623 cursor_timeout.restart();
627 bool BufferView::Pimpl::available() const
629 return buffer_ && bv_->text();
633 Change const BufferView::Pimpl::getCurrentChange()
635 if (!bv_->buffer()->params().tracking_changes)
636 return Change(Change::UNCHANGED);
638 LyXText * text = bv_->getLyXText();
639 LCursor & cur = bv_->cursor();
641 if (!cur.selection())
642 return Change(Change::UNCHANGED);
644 return text->getPar(cur.selBegin())
645 ->lookupChangeFull(cur.selBegin().pos());
649 void BufferView::Pimpl::savePosition(unsigned int i)
651 if (i >= saved_positions_num)
653 saved_positions[i] = Position(buffer_->fileName(),
654 bv_->text()->cursorPar()->id(),
655 bv_->text()->cursor().pos());
657 owner_->message(bformat(_("Saved bookmark %1$s"), tostr(i)));
661 void BufferView::Pimpl::restorePosition(unsigned int i)
663 if (i >= saved_positions_num)
666 string const fname = saved_positions[i].filename;
668 bv_->cursor().clearSelection();
670 if (fname != buffer_->fileName()) {
672 if (bufferlist.exists(fname))
673 b = bufferlist.getBuffer(fname);
675 b = bufferlist.newBuffer(fname);
676 ::loadLyXFile(b, fname); // don't ask, just load it
682 ParIterator par = buffer_->getParFromID(saved_positions[i].par_id);
683 if (par == buffer_->par_iterator_end())
686 bv_->text()->setCursor(
688 bv_->text()->parOffset(par.pit()),
689 min(par->size(), saved_positions[i].par_pos));
692 owner_->message(bformat(_("Moved to bookmark %1$s"), tostr(i)));
696 bool BufferView::Pimpl::isSavedPosition(unsigned int i)
698 return i < saved_positions_num && !saved_positions[i].filename.empty();
702 void BufferView::Pimpl::switchKeyMap()
704 if (!lyxrc.rtl_support)
707 Intl & intl = owner_->getIntl();
708 if (bv_->getLyXText()->real_current_font.isRightToLeft()) {
709 if (intl.keymap == Intl::PRIMARY)
712 if (intl.keymap == Intl::SECONDARY)
718 void BufferView::Pimpl::center()
720 LyXText * text = bv_->text();
722 bv_->cursor().clearSelection();
723 int const half_height = workarea().workHeight() / 2;
724 int new_y = text->cursorY(bv_->cursor().front()) - half_height;
728 // FIXME: look at this comment again ...
729 // This updates top_y() but means the fitCursor() call
730 // from the update(FITCUR) doesn't realise that we might
731 // have moved (e.g. from GOTOPARAGRAPH), so doesn't cause
732 // the scrollbar to be updated as it should, so we have
733 // to do it manually. Any operation that does a center()
734 // and also might have moved top_y() must make sure to call
735 // updateScrollbar() currently. Never mind that this is a
736 // pretty obfuscated way of updating text->top_y()
741 void BufferView::Pimpl::stuffClipboard(string const & stuff) const
743 workarea().putClipboard(stuff);
747 InsetBase * BufferView::Pimpl::getInsetByCode(InsetBase::Code code)
749 #warning Does not work for mathed
750 // Ok, this is a little bit too brute force but it
751 // should work for now. Better infrastructure is coming. (Lgb)
753 Buffer * buf = bv_->buffer();
754 Buffer::inset_iterator beg = buf->inset_iterator_begin();
755 Buffer::inset_iterator end = buf->inset_iterator_end();
757 bool cursor_par_seen = false;
759 LCursor & cur = bv_->cursor();
760 ParagraphList::iterator pit = bv_->getLyXText()->getPar(cur.par());
762 for (; beg != end; ++beg) {
763 if (beg.getPar() == pit)
764 cursor_par_seen = true;
765 if (cursor_par_seen) {
766 if (beg.getPar() == pit && beg.getPos() >= cur.pos())
768 if (beg.getPar() != pit)
773 // Now find the first inset that matches code.
774 for (; beg != end; ++beg) {
775 if (beg->lyxCode() == code)
783 void BufferView::Pimpl::MenuInsertLyXFile(string const & filenm)
785 string filename = filenm;
787 if (filename.empty()) {
788 // Launch a file browser
789 string initpath = lyxrc.document_path;
792 string const trypath = owner_->buffer()->filePath();
793 // If directory is writeable, use this as default.
794 if (IsDirWriteable(trypath))
798 FileDialog fileDlg(_("Select LyX document to insert"),
800 make_pair(string(_("Documents|#o#O")),
801 string(lyxrc.document_path)),
802 make_pair(string(_("Examples|#E#e")),
803 string(AddPath(system_lyxdir(), "examples"))));
805 FileDialog::Result result =
806 fileDlg.open(initpath,
807 FileFilterList(_("LyX Documents (*.lyx)")),
810 if (result.first == FileDialog::Later)
813 filename = result.second;
815 // check selected filename
816 if (filename.empty()) {
817 owner_->message(_("Canceled."));
822 // get absolute path of file and add ".lyx" to the filename if
824 filename = FileSearch(string(), filename, "lyx");
826 string const disp_fn = MakeDisplayPath(filename);
827 owner_->message(bformat(_("Inserting document %1$s..."), disp_fn));
828 if (bv_->insertLyXFile(filename))
829 owner_->message(bformat(_("Document %1$s inserted."),
832 owner_->message(bformat(_("Could not insert document %1$s"),
837 void BufferView::Pimpl::trackChanges()
839 Buffer * buf = bv_->buffer();
840 bool const tracking = buf->params().tracking_changes;
843 ParIterator const end = buf->par_iterator_end();
844 for (ParIterator it = buf->par_iterator_begin(); it != end; ++it)
846 buf->params().tracking_changes = true;
848 // we cannot allow undos beyond the freeze point
849 buf->undostack().clear();
852 bv_->text()->setCursor(bv_->cursor(), 0, 0);
853 #warning changes FIXME
854 bool found = lyx::find::findNextChange(bv_);
856 owner_->getDialogs().show("changes");
860 ParIterator const end = buf->par_iterator_end();
861 for (ParIterator it = buf->par_iterator_begin(); it != end; ++it)
862 it->untrackChanges();
863 buf->params().tracking_changes = false;
866 buf->redostack().clear();
870 bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0)
873 // this is only called for mouse related events (including
874 // LFUN_FILE_OPEN generated by drag-and-drop)
876 FuncRequest cmd = cmd0;
877 cmd.y += bv_->top_y();
878 //lyxerr << "*** workAreaDispatch: request: " << cmd << std::endl;
880 cur.push(bv_->buffer()->inset());
882 cur.selection() = bv_->cursor().selection();
883 switch (cmd.action) {
886 case LFUN_MOUSE_MOTION: {
889 FuncRequest cmd1 = cmd;
890 DispatchResult res = cur.inset().dispatch(cur, cmd);
891 if (fitCursor() || res.update()) {
898 case LFUN_MOUSE_MOTION:
901 case LFUN_MOUSE_PRESS:
902 case LFUN_MOUSE_RELEASE:
903 case LFUN_MOUSE_DOUBLE:
904 case LFUN_MOUSE_TRIPLE: {
905 // We pass those directly to the Bufferview, since
906 // otherwise selection handling breaks down
908 // Doesn't go through lyxfunc, so we need to update
909 // the layout choice etc. ourselves
911 // e.g. Qt mouse press when no buffer
915 screen().hideCursor();
917 // either the inset under the cursor or the
918 // surrounding LyXText will handle this event.
920 // built temporary path to inset
921 InsetBase * inset = bv_->text()->editXY(cur, cmd.x, cmd.y);
922 lyxerr << "hit inset at tip: " << inset << endl;
923 lyxerr << "created temp cursor:\n" << cur << endl;
925 // Try to dispatch to an non-editable inset near this position
928 inset->dispatch(cur, cmd);
930 // Dispatch to the temp cursor.
931 // An inset (or LyXText) can assign this to bv->cursor()
932 // if it wishes to do so.
933 if (!res.dispatched())
934 res = cur.dispatch(cmd);
936 if (fitCursor() || res.update())
939 // see workAreaKeyPress
940 cursor_timeout.restart();
941 screen().showCursor(*bv_);
943 // skip these when selecting
944 if (cmd.action != LFUN_MOUSE_MOTION) {
945 owner_->updateLayoutChoice();
946 owner_->updateToolbar();
949 // slight hack: this is only called currently when we
950 // clicked somewhere, so we force through the display
951 // of the new status here.
952 owner_->clearMessage();
957 owner_->dispatch(cmd);
967 bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
969 //lyxerr << "*** BufferView::Pimpl: request: " << cmd << std::endl;
970 // Make sure that the cached BufferView is correct.
971 lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch:"
972 << " action[" << cmd.action << ']'
973 << " arg[" << cmd.argument << ']'
974 << " x[" << cmd.x << ']'
975 << " y[" << cmd.y << ']'
976 << " button[" << cmd.button() << ']'
979 LCursor & cur = bv_->cursor();
981 switch (cmd.action) {
985 cur.message(_("Undo"));
986 cur.clearSelection();
988 cur.message(_("No further undo information"));
996 cur.message(_("Redo"));
997 cur.clearSelection();
999 cur.message(_("No further redo information"));
1005 case LFUN_FILE_INSERT:
1006 MenuInsertLyXFile(cmd.argument);
1009 case LFUN_FILE_INSERT_ASCII_PARA:
1010 InsertAsciiFile(bv_, cmd.argument, true);
1013 case LFUN_FILE_INSERT_ASCII:
1014 InsertAsciiFile(bv_, cmd.argument, false);
1017 case LFUN_FONT_STATE:
1018 cur.message(cur.currentState());
1021 case LFUN_INSERT_LABEL: {
1022 // Try and generate a valid label
1023 string const contents = cmd.argument.empty() ?
1024 cur.getPossibleLabel() : cmd.argument;
1025 InsetCommandParams icp("label", contents);
1026 string data = InsetCommandMailer::params2string("label", icp);
1027 owner_->getDialogs().show("label", data, 0);
1031 case LFUN_BOOKMARK_SAVE:
1032 savePosition(strToUnsignedInt(cmd.argument));
1035 case LFUN_BOOKMARK_GOTO:
1036 restorePosition(strToUnsignedInt(cmd.argument));
1039 case LFUN_REF_GOTO: {
1040 string label = cmd.argument;
1041 if (label.empty()) {
1043 static_cast<InsetRef*>(getInsetByCode(InsetBase::REF_CODE));
1045 label = inset->getContents();
1051 bv_->gotoLabel(label);
1055 case LFUN_TRACK_CHANGES:
1059 case LFUN_MERGE_CHANGES:
1060 owner_->getDialogs().show("changes");
1063 case LFUN_ACCEPT_ALL_CHANGES: {
1064 bv_->cursor().reset();
1065 #warning FIXME changes
1066 while (lyx::find::findNextChange(bv_))
1067 bv_->getLyXText()->acceptChange(bv_->cursor());
1072 case LFUN_REJECT_ALL_CHANGES: {
1073 bv_->cursor().reset();
1074 #warning FIXME changes
1075 while (lyx::find::findNextChange(bv_))
1076 bv_->getLyXText()->rejectChange(bv_->cursor());
1081 case LFUN_WORD_FIND:
1082 lyx::find::find(bv_, cmd);
1085 case LFUN_WORD_REPLACE:
1086 lyx::find::replace(bv_, cmd);
1090 cur.clearSelection();
1093 cur.message(N_("Mark off"));
1097 cur.clearSelection();
1101 cur.message(N_("Mark on"));
1105 cur.clearSelection();
1108 cur.message(N_("Mark removed"));
1111 cur.message(N_("Mark set"));
1117 case LFUN_UNKNOWN_ACTION:
1118 cur.errorMessage(N_("Unknown function!"));
1125 case LFUN_BEGINNINGBUFSEL:
1126 bv_->cursor().reset();
1127 if (!cur.selection())
1129 bv_->text()->cursorTop(cur);
1133 case LFUN_ENDBUFSEL:
1134 bv_->cursor().reset();
1135 if (!cur.selection())
1137 bv_->text()->cursorBottom(cur);