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"
26 #include "coordcache.h"
29 #include "dispatchresult.h"
31 #include "FloatList.h"
32 #include "funcrequest.h"
33 #include "FuncStatus.h"
36 #include "insetiterator.h"
37 #include "lyx_cb.h" // added for Dispatch functions
43 #include "lastfiles.h"
44 #include "paragraph.h"
45 #include "paragraph_funcs.h"
46 #include "ParagraphParameters.h"
47 #include "pariterator.h"
48 #include "rowpainter.h"
52 #include "insets/insetref.h"
53 #include "insets/insettext.h"
55 #include "frontends/Alert.h"
56 #include "frontends/Dialogs.h"
57 #include "frontends/FileDialog.h"
58 #include "frontends/LyXView.h"
59 #include "frontends/LyXScreenFactory.h"
60 #include "frontends/screen.h"
61 #include "frontends/WorkArea.h"
62 #include "frontends/WorkAreaFactory.h"
64 #include "graphics/Previews.h"
66 #include "support/filetools.h"
67 #include "support/forkedcontr.h"
68 #include "support/globbing.h"
69 #include "support/path_defines.h"
70 #include "support/tostr.h"
71 #include "support/types.h"
73 #include <boost/bind.hpp>
77 using lyx::support::AddPath;
78 using lyx::support::bformat;
79 using lyx::support::FileFilterList;
80 using lyx::support::FileSearch;
81 using lyx::support::ForkedcallsController;
82 using lyx::support::IsDirWriteable;
83 using lyx::support::MakeDisplayPath;
84 using lyx::support::strToUnsignedInt;
85 using lyx::support::system_lyxdir;
88 using std::istringstream;
94 extern BufferList bufferlist;
99 unsigned int const saved_positions_num = 20;
101 // All the below connection objects are needed because of a bug in some
102 // versions of GCC (<=2.96 are on the suspects list.) By having and assigning
103 // to these connections we avoid a segfault upon startup, and also at exit.
106 boost::signals::connection dispatchcon;
107 boost::signals::connection timecon;
108 boost::signals::connection doccon;
109 boost::signals::connection resizecon;
110 boost::signals::connection kpresscon;
111 boost::signals::connection selectioncon;
112 boost::signals::connection lostcon;
115 /// Get next inset of this class from current cursor position
117 T * getInsetByCode(LCursor & cur, InsetBase::Code code)
120 DocIterator it = cur;
121 if (it.nextInset() &&
122 it.nextInset()->lyxCode() == code) {
123 inset = static_cast<T*>(it.nextInset());
132 BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner,
133 int width, int height)
134 : bv_(&bv), owner_(owner), buffer_(0), cursor_timeout(400),
135 using_xterm_cursor(false), cursor_(bv)
137 xsel_cache_.set = false;
139 workarea_.reset(WorkAreaFactory::create(*owner_, width, height));
140 screen_.reset(LyXScreenFactory::create(workarea()));
143 doccon = workarea().scrollDocView
144 .connect(boost::bind(&BufferView::Pimpl::scrollDocView, this, _1));
145 resizecon = workarea().workAreaResize
146 .connect(boost::bind(&BufferView::Pimpl::workAreaResize, this));
147 dispatchcon = workarea().dispatch
148 .connect(boost::bind(&BufferView::Pimpl::workAreaDispatch, this, _1));
149 kpresscon = workarea().workAreaKeyPress
150 .connect(boost::bind(&BufferView::Pimpl::workAreaKeyPress, this, _1, _2));
151 selectioncon = workarea().selectionRequested
152 .connect(boost::bind(&BufferView::Pimpl::selectionRequested, this));
153 lostcon = workarea().selectionLost
154 .connect(boost::bind(&BufferView::Pimpl::selectionLost, this));
156 timecon = cursor_timeout.timeout
157 .connect(boost::bind(&BufferView::Pimpl::cursorToggle, this));
158 cursor_timeout.start();
159 saved_positions.resize(saved_positions_num);
163 void BufferView::Pimpl::addError(ErrorItem const & ei)
165 errorlist_.push_back(ei);
169 void BufferView::Pimpl::showReadonly(bool)
171 owner_->updateWindowTitle();
172 owner_->getDialogs().updateBufferDependent(false);
176 void BufferView::Pimpl::connectBuffer(Buffer & buf)
178 if (errorConnection_.connected())
183 boost::bind(&BufferView::Pimpl::addError, this, _1));
187 boost::bind(&LyXView::message, owner_, _1));
191 boost::bind(&LyXView::busy, owner_, _1));
194 buf.updateTitles.connect(
195 boost::bind(&LyXView::updateWindowTitle, owner_));
198 buf.resetAutosaveTimers.connect(
199 boost::bind(&LyXView::resetAutosaveTimer, owner_));
201 readonlyConnection_ =
202 buf.readonly.connect(
203 boost::bind(&BufferView::Pimpl::showReadonly, this, _1));
207 boost::bind(&BufferView::Pimpl::setBuffer, this, (Buffer *)0));
211 void BufferView::Pimpl::disconnectBuffer()
213 errorConnection_.disconnect();
214 messageConnection_.disconnect();
215 busyConnection_.disconnect();
216 titleConnection_.disconnect();
217 timerConnection_.disconnect();
218 readonlyConnection_.disconnect();
219 closingConnection_.disconnect();
223 void BufferView::Pimpl::newFile(string const & filename, string const & tname,
226 setBuffer(::newFile(filename, tname, isNamed));
230 bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles)
232 // get absolute path of file and add ".lyx" to the filename if
234 string s = FileSearch(string(), filename, "lyx");
236 bool const found = !s.empty();
241 // file already open?
242 if (bufferlist.exists(s)) {
243 string const file = MakeDisplayPath(s, 20);
244 string text = bformat(_("The document %1$s is already "
245 "loaded.\n\nDo you want to revert "
246 "to the saved version?"), file);
247 int const ret = Alert::prompt(_("Revert to saved document?"),
248 text, 0, 1, _("&Revert"), _("&Switch to document"));
251 setBuffer(bufferlist.getBuffer(s));
254 // FIXME: should be LFUN_REVERT
255 if (!bufferlist.close(bufferlist.getBuffer(s), false))
257 // Fall through to new load. (Asger)
263 b = bufferlist.newBuffer(s);
265 if (!::loadLyXFile(b, s)) {
266 bufferlist.release(b);
270 string text = bformat(_("The document %1$s does not yet "
271 "exist.\n\nDo you want to create "
272 "a new document?"), s);
273 int const ret = Alert::prompt(_("Create new document?"),
274 text, 0, 1, _("&Create"), _("Cancel"));
277 b = ::newFile(s, string(), true);
283 bv_->showErrorList(_("Parse"));
286 LyX::ref().lastfiles().newFile(b->fileName());
292 WorkArea & BufferView::Pimpl::workarea() const
294 return *workarea_.get();
298 LyXScreen & BufferView::Pimpl::screen() const
300 return *screen_.get();
304 Painter & BufferView::Pimpl::painter() const
306 return workarea().getPainter();
310 void BufferView::Pimpl::top_y(int y)
316 int BufferView::Pimpl::top_y() const
322 void BufferView::Pimpl::setBuffer(Buffer * b)
324 lyxerr[Debug::INFO] << "Setting buffer in BufferView ("
329 // set current buffer
334 cursor_ = LCursor(*bv_);
336 // if we're quitting lyx, don't bother updating stuff
341 lyxerr[Debug::INFO] << "Buffer addr: " << buffer_ << endl;
342 connectBuffer(*buffer_);
344 cursor_.push(buffer_->inset());
345 cursor_.resetAnchor();
346 buffer_->text().init(bv_);
347 buffer_->text().setCurrentFont(cursor_);
349 // If we don't have a text object for this, we make one
350 //if (bv_->text() == 0)
351 // resizeCurrentBuffer();
353 // Buffer-dependent dialogs should be updated or
354 // hidden. This should go here because some dialogs (eg ToC)
355 // require bv_->text.
356 owner_->getDialogs().updateBufferDependent(true);
358 lyxerr[Debug::INFO] << " No Buffer!" << endl;
359 // we are closing the buffer, use the first buffer as current
360 buffer_ = bufferlist.first();
361 owner_->getDialogs().hideBufferDependent();
366 owner_->updateMenubar();
367 owner_->updateToolbars();
368 owner_->updateLayoutChoice();
369 owner_->updateWindowTitle();
371 // This is done after the layout combox has been populated
373 owner_->setLayout(cursor_.paragraph().layout()->name());
375 if (buffer_ && lyx::graphics::Previews::status() != LyXRC::PREVIEW_OFF)
376 lyx::graphics::Previews::get().generateBufferPreviews(*buffer_);
380 bool BufferView::Pimpl::fitCursor()
382 // to get the correct y cursor info
383 lyxerr[Debug::DEBUG] << "BufferView::fitCursor" << std::endl;
384 lyx::par_type const pit = bv_->cursor().bottom().par();
385 bv_->text()->redoParagraph(pit);
386 refreshPar(*bv_, *bv_->text(), pit);
388 if (!screen().fitCursor(bv_))
395 void BufferView::Pimpl::redoCurrentBuffer()
397 lyxerr[Debug::DEBUG] << "BufferView::redoCurrentBuffer" << endl;
398 if (buffer_ && bv_->text()) {
399 resizeCurrentBuffer();
401 owner_->updateLayoutChoice();
406 void BufferView::Pimpl::resizeCurrentBuffer()
408 lyxerr[Debug::DEBUG] << "resizeCurrentBuffer" << endl;
410 owner_->message(_("Formatting document..."));
412 LyXText * text = bv_->text();
423 // reset the "Formatting..." message
424 owner_->clearMessage();
430 void BufferView::Pimpl::updateScrollbar()
433 lyxerr[Debug::DEBUG] << "no text in updateScrollbar" << endl;
434 workarea().setScrollbarParams(0, 0, 0);
438 LyXText const & t = *bv_->text();
441 << "Updating scrollbar: height: " << t.height()
442 << " top_y: " << top_y()
443 << " default height " << defaultRowHeight() << endl;
445 workarea().setScrollbarParams(t.height(), top_y(), defaultRowHeight());
449 void BufferView::Pimpl::scrollDocView(int value)
451 lyxerr[Debug::GUI] << "scrollDocView of " << value << endl;
456 screen().hideCursor();
459 screen().redraw(*bv_);
461 if (!lyxrc.cursor_follows_scrollbar)
464 int const height = defaultRowHeight();
465 int const first = top_y() + height;
466 int const last = top_y() + workarea().workHeight() - height;
468 bv_->cursor().reset(bv_->buffer()->inset());
469 LyXText * text = bv_->text();
470 int y = text->cursorY(bv_->cursor().front());
475 text->setCursorFromCoordinates(bv_->cursor(), 0, y);
477 owner_->updateLayoutChoice();
481 void BufferView::Pimpl::scroll(int lines)
486 LyXText const * t = bv_->text();
487 int const line_height = defaultRowHeight();
489 // The new absolute coordinate
490 int new_top_y = top_y() + lines * line_height;
492 // Restrict to a valid value
493 new_top_y = std::min(t->height() - 4 * line_height, new_top_y);
494 new_top_y = std::max(0, new_top_y);
496 scrollDocView(new_top_y);
498 // Update the scrollbar.
499 workarea().setScrollbarParams(t->height(), top_y(), defaultRowHeight());
503 void BufferView::Pimpl::workAreaKeyPress(LyXKeySymPtr key,
504 key_modifier::state state)
506 bv_->owner()->getLyXFunc().processKeySym(key, state);
508 /* This is perhaps a bit of a hack. When we move
509 * around, or type, it's nice to be able to see
510 * the cursor immediately after the keypress. So
511 * we reset the toggle timeout and force the visibility
512 * of the cursor. Note we cannot do this inside
513 * dispatch() itself, because that's called recursively.
516 cursor_timeout.restart();
517 screen().showCursor(*bv_);
522 void BufferView::Pimpl::selectionRequested()
529 LCursor & cur = bv_->cursor();
531 if (!cur.selection()) {
532 xsel_cache_.set = false;
536 if (!xsel_cache_.set ||
537 cur.back() != xsel_cache_.cursor ||
538 cur.anchor_.back() != xsel_cache_.anchor)
540 xsel_cache_.cursor = cur.back();
541 xsel_cache_.anchor = cur.anchor_.back();
542 xsel_cache_.set = cur.selection();
543 sel = cur.selectionAsString(false);
545 workarea().putClipboard(sel);
550 void BufferView::Pimpl::selectionLost()
553 screen().hideCursor();
554 bv_->cursor().clearSelection();
555 xsel_cache_.set = false;
560 void BufferView::Pimpl::workAreaResize()
562 static int work_area_width;
563 static int work_area_height;
565 bool const widthChange = workarea().workWidth() != work_area_width;
566 bool const heightChange = workarea().workHeight() != work_area_height;
568 // update from work area
569 work_area_width = workarea().workWidth();
570 work_area_height = workarea().workHeight();
572 if (buffer_ && widthChange) {
573 // The visible LyXView need a resize
574 resizeCurrentBuffer();
577 if (widthChange || heightChange)
580 // always make sure that the scrollbar is sane.
582 owner_->updateLayoutChoice();
586 void BufferView::Pimpl::update()
588 //lyxerr << "BufferView::Pimpl::update(), buffer: " << buffer_ << endl;
589 // fix cursor coordinate cache in case something went wrong
591 // check needed to survive LyX startup
593 // update macro store
594 buffer_->buildMacros();
596 // update all 'visible' paragraphs
597 lyx::par_type beg, end;
598 getParsInRange(buffer_->paragraphs(),
599 top_y(), top_y() + workarea().workHeight(),
601 bv_->text()->redoParagraphs(beg, end);
607 // remove old position cache
610 // The real, big redraw.
611 screen().redraw(*bv_);
613 bv_->owner()->view_state_changed();
617 // Callback for cursor timer
618 void BufferView::Pimpl::cursorToggle()
621 screen().toggleCursor(*bv_);
623 // Use this opportunity to deal with any child processes that
624 // have finished but are waiting to communicate this fact
625 // to the rest of LyX.
626 ForkedcallsController & fcc = ForkedcallsController::get();
627 if (fcc.processesCompleted())
628 fcc.handleCompletedProcesses();
631 cursor_timeout.restart();
635 bool BufferView::Pimpl::available() const
637 return buffer_ && bv_->text();
641 Change const BufferView::Pimpl::getCurrentChange()
643 if (!bv_->buffer()->params().tracking_changes)
644 return Change(Change::UNCHANGED);
646 LyXText * text = bv_->getLyXText();
647 LCursor & cur = bv_->cursor();
649 if (!cur.selection())
650 return Change(Change::UNCHANGED);
652 return text->getPar(cur.selBegin().par()).
653 lookupChangeFull(cur.selBegin().pos());
657 void BufferView::Pimpl::savePosition(unsigned int i)
659 if (i >= saved_positions_num)
661 BOOST_ASSERT(bv_->cursor().inTexted());
662 saved_positions[i] = Position(buffer_->fileName(),
663 bv_->cursor().paragraph().id(),
664 bv_->cursor().pos());
666 owner_->message(bformat(_("Saved bookmark %1$s"), tostr(i)));
670 void BufferView::Pimpl::restorePosition(unsigned int i)
672 if (i >= saved_positions_num)
675 string const fname = saved_positions[i].filename;
677 bv_->cursor().clearSelection();
679 if (fname != buffer_->fileName()) {
681 if (bufferlist.exists(fname))
682 b = bufferlist.getBuffer(fname);
684 b = bufferlist.newBuffer(fname);
685 ::loadLyXFile(b, fname); // don't ask, just load it
691 ParIterator par = buffer_->getParFromID(saved_positions[i].par_id);
692 if (par == buffer_->par_iterator_end())
695 bv_->text()->setCursor(bv_->cursor(), par.pit(),
696 min(par->size(), saved_positions[i].par_pos));
699 owner_->message(bformat(_("Moved to bookmark %1$s"), tostr(i)));
703 bool BufferView::Pimpl::isSavedPosition(unsigned int i)
705 return i < saved_positions_num && !saved_positions[i].filename.empty();
709 void BufferView::Pimpl::switchKeyMap()
711 if (!lyxrc.rtl_support)
714 Intl & intl = owner_->getIntl();
715 if (bv_->getLyXText()->real_current_font.isRightToLeft()) {
716 if (intl.keymap == Intl::PRIMARY)
719 if (intl.keymap == Intl::SECONDARY)
725 void BufferView::Pimpl::center()
727 LyXText * text = bv_->text();
729 bv_->cursor().clearSelection();
730 int const half_height = workarea().workHeight() / 2;
731 int new_y = text->cursorY(bv_->cursor().front()) - half_height;
735 // FIXME: look at this comment again ...
736 // This updates top_y() but means the fitCursor() call
737 // from the update(FITCUR) doesn't realise that we might
738 // have moved (e.g. from GOTOPARAGRAPH), so doesn't cause
739 // the scrollbar to be updated as it should, so we have
740 // to do it manually. Any operation that does a center()
741 // and also might have moved top_y() must make sure to call
742 // updateScrollbar() currently. Never mind that this is a
743 // pretty obfuscated way of updating text->top_y()
748 void BufferView::Pimpl::stuffClipboard(string const & stuff) const
750 workarea().putClipboard(stuff);
754 void BufferView::Pimpl::MenuInsertLyXFile(string const & filenm)
756 string filename = filenm;
758 if (filename.empty()) {
759 // Launch a file browser
760 string initpath = lyxrc.document_path;
763 string const trypath = owner_->buffer()->filePath();
764 // If directory is writeable, use this as default.
765 if (IsDirWriteable(trypath))
769 FileDialog fileDlg(_("Select LyX document to insert"),
771 make_pair(string(_("Documents|#o#O")),
772 string(lyxrc.document_path)),
773 make_pair(string(_("Examples|#E#e")),
774 string(AddPath(system_lyxdir(), "examples"))));
776 FileDialog::Result result =
777 fileDlg.open(initpath,
778 FileFilterList(_("LyX Documents (*.lyx)")),
781 if (result.first == FileDialog::Later)
784 filename = result.second;
786 // check selected filename
787 if (filename.empty()) {
788 owner_->message(_("Canceled."));
793 // get absolute path of file and add ".lyx" to the filename if
795 filename = FileSearch(string(), filename, "lyx");
797 string const disp_fn = MakeDisplayPath(filename);
798 owner_->message(bformat(_("Inserting document %1$s..."), disp_fn));
799 if (bv_->insertLyXFile(filename))
800 owner_->message(bformat(_("Document %1$s inserted."),
803 owner_->message(bformat(_("Could not insert document %1$s"),
808 void BufferView::Pimpl::trackChanges()
810 Buffer * buf = bv_->buffer();
811 bool const tracking = buf->params().tracking_changes;
814 ParIterator const end = buf->par_iterator_end();
815 for (ParIterator it = buf->par_iterator_begin(); it != end; ++it)
817 buf->params().tracking_changes = true;
819 // we cannot allow undos beyond the freeze point
820 buf->undostack().clear();
823 bv_->text()->setCursor(bv_->cursor(), 0, 0);
825 #warning changes FIXME
827 bool found = lyx::find::findNextChange(bv_);
829 owner_->getDialogs().show("changes");
833 ParIterator const end = buf->par_iterator_end();
834 for (ParIterator it = buf->par_iterator_begin(); it != end; ++it)
835 it->untrackChanges();
836 buf->params().tracking_changes = false;
839 buf->redostack().clear();
843 bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0)
845 lyxerr << "BufferView::Pimpl::workAreaDispatch: request: "
846 << cmd0 << std::endl;
847 // this is only called for mouse related events including
848 // LFUN_FILE_OPEN generated by drag-and-drop.
849 FuncRequest cmd = cmd0;
852 if (cmd.action == LFUN_FILE_OPEN) {
853 owner_->dispatch(cmd);
857 cmd.y += bv_->top_y();
862 cur.push(bv_->buffer()->inset());
863 cur.selection() = bv_->cursor().selection();
865 // Doesn't go through lyxfunc, so we need to update
866 // the layout choice etc. ourselves
868 // e.g. Qt mouse press when no buffer
872 screen().hideCursor();
874 // Either the inset under the cursor or the
875 // surrounding LyXText will handle this event.
877 // Build temporary cursor.
878 InsetBase * inset = bv_->text()->editXY(cur, cmd.x, cmd.y);
879 lyxerr << "hit inset at tip: " << inset << endl;
880 lyxerr << "created temp cursor:\n" << cur << endl;
882 // Put anchor at the same position.
885 // Try to dispatch to an non-editable inset near this position
886 // via the temp cursor. If the inset wishes to change the real
887 // cursor it has to do so explicitly by using
888 // cur.bv().cursor() = cur; (or similar)'
890 inset->dispatch(cur, cmd);
892 // Now dispatch to the temporary cursor. If the real cursor should
893 // be modified, the inset's dispatch has to do so explicitly.
894 if (!cur.result().dispatched())
897 if (cur.result().dispatched()) {
898 // Redraw if requested or necessary.
899 if (fitCursor() || cur.result().update())
903 // see workAreaKeyPress
904 cursor_timeout.restart();
905 screen().showCursor(*bv_);
907 // skip these when selecting
908 if (cmd.action != LFUN_MOUSE_MOTION) {
909 owner_->updateLayoutChoice();
910 owner_->updateToolbars();
913 // slight hack: this is only called currently when we
914 // clicked somewhere, so we force through the display
915 // of the new status here.
916 owner_->clearMessage();
921 FuncStatus BufferView::Pimpl::getStatus(FuncRequest const & cmd)
923 Buffer * buf = bv_->buffer();
927 switch (cmd.action) {
930 flag.enabled(!buf->undostack().empty());
933 flag.enabled(!buf->redostack().empty());
935 case LFUN_FILE_INSERT:
936 case LFUN_FILE_INSERT_ASCII_PARA:
937 case LFUN_FILE_INSERT_ASCII:
938 case LFUN_FONT_STATE:
939 case LFUN_INSERT_LABEL:
940 case LFUN_BOOKMARK_SAVE:
943 case LFUN_WORD_REPLACE:
948 case LFUN_BEGINNINGBUF:
950 case LFUN_BEGINNINGBUFSEL:
954 case LFUN_BOOKMARK_GOTO:
955 flag.enabled(bv_->isSavedPosition(strToUnsignedInt(cmd.argument)));
957 case LFUN_TRACK_CHANGES:
959 flag.setOnOff(buf->params().tracking_changes);
962 case LFUN_MERGE_CHANGES:
963 case LFUN_ACCEPT_CHANGE: // what about these two
964 case LFUN_REJECT_CHANGE: // what about these two
965 case LFUN_ACCEPT_ALL_CHANGES:
966 case LFUN_REJECT_ALL_CHANGES:
967 flag.enabled(buf && buf->params().tracking_changes);
978 bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
980 //lyxerr << "BufferView::Pimpl::dispatch cmd: " << cmd << std::endl;
981 // Make sure that the cached BufferView is correct.
982 lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch:"
983 << " action[" << cmd.action << ']'
984 << " arg[" << cmd.argument << ']'
985 << " x[" << cmd.x << ']'
986 << " y[" << cmd.y << ']'
987 << " button[" << cmd.button() << ']'
990 LCursor & cur = bv_->cursor();
992 switch (cmd.action) {
996 cur.message(_("Undo"));
997 cur.clearSelection();
999 cur.message(_("No further undo information"));
1007 cur.message(_("Redo"));
1008 cur.clearSelection();
1009 if (!textRedo(*bv_))
1010 cur.message(_("No further redo information"));
1016 case LFUN_FILE_INSERT:
1017 MenuInsertLyXFile(cmd.argument);
1020 case LFUN_FILE_INSERT_ASCII_PARA:
1021 InsertAsciiFile(bv_, cmd.argument, true);
1024 case LFUN_FILE_INSERT_ASCII:
1025 InsertAsciiFile(bv_, cmd.argument, false);
1028 case LFUN_FONT_STATE:
1029 cur.message(cur.currentState());
1032 case LFUN_BOOKMARK_SAVE:
1033 savePosition(strToUnsignedInt(cmd.argument));
1036 case LFUN_BOOKMARK_GOTO:
1037 restorePosition(strToUnsignedInt(cmd.argument));
1040 case LFUN_REF_GOTO: {
1041 string label = cmd.argument;
1042 if (label.empty()) {
1044 getInsetByCode<InsetRef>(bv_->cursor(),
1045 InsetBase::REF_CODE);
1047 label = inset->getContents();
1053 bv_->gotoLabel(label);
1057 case LFUN_TRACK_CHANGES:
1061 case LFUN_MERGE_CHANGES:
1062 owner_->getDialogs().show("changes");
1065 case LFUN_ACCEPT_ALL_CHANGES: {
1066 bv_->cursor().reset(bv_->buffer()->inset());
1067 #ifdef WITH_WARNINGS
1068 #warning FIXME changes
1070 while (lyx::find::findNextChange(bv_))
1071 bv_->getLyXText()->acceptChange(bv_->cursor());
1076 case LFUN_REJECT_ALL_CHANGES: {
1077 bv_->cursor().reset(bv_->buffer()->inset());
1078 #ifdef WITH_WARNINGS
1079 #warning FIXME changes
1081 while (lyx::find::findNextChange(bv_))
1082 bv_->getLyXText()->rejectChange(bv_->cursor());
1086 case LFUN_WORD_FIND:
1087 lyx::find::find(bv_, cmd);
1090 case LFUN_WORD_REPLACE:
1091 lyx::find::replace(bv_, cmd);
1095 cur.clearSelection();
1097 cur.message(N_("Mark off"));
1101 cur.clearSelection();
1104 cur.message(N_("Mark on"));
1108 cur.clearSelection();
1111 cur.message(N_("Mark removed"));
1114 cur.message(N_("Mark set"));
1123 case LFUN_BEGINNINGBUFSEL:
1124 bv_->cursor().reset(bv_->buffer()->inset());
1125 if (!cur.selection())
1127 bv_->text()->cursorTop(cur);
1131 case LFUN_ENDBUFSEL:
1132 bv_->cursor().reset(bv_->buffer()->inset());
1133 if (!cur.selection())
1135 bv_->text()->cursorBottom(cur);