X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView_pimpl.C;h=62c17dbb500b0778d062713acdf99a9b2b192880;hb=10ba1b8918e7da14334bb5573ce2a707671c8b51;hp=98ec94d012ebed5f4b037cbf6189cba851e2f4ba;hpb=1b3f5ee46ff2924c4b374f52ad6317b5fd7ac9a5;p=lyx.git diff --git a/src/BufferView_pimpl.C b/src/BufferView_pimpl.C index 98ec94d012..62c17dbb50 100644 --- a/src/BufferView_pimpl.C +++ b/src/BufferView_pimpl.C @@ -23,15 +23,17 @@ #include "buffer_funcs.h" #include "bufferlist.h" #include "bufferparams.h" +#include "coordcache.h" #include "cursor.h" #include "debug.h" #include "dispatchresult.h" #include "factory.h" #include "FloatList.h" #include "funcrequest.h" +#include "FuncStatus.h" #include "gettext.h" #include "intl.h" -#include "iterators.h" +#include "insetiterator.h" #include "lyx_cb.h" // added for Dispatch functions #include "lyx_main.h" #include "lyxfind.h" @@ -42,6 +44,8 @@ #include "paragraph.h" #include "paragraph_funcs.h" #include "ParagraphParameters.h" +#include "pariterator.h" +#include "rowpainter.h" #include "undo.h" #include "vspace.h" @@ -60,20 +64,26 @@ #include "graphics/Previews.h" #include "support/filetools.h" +#include "support/forkedcontr.h" #include "support/globbing.h" #include "support/path_defines.h" #include "support/tostr.h" +#include "support/types.h" #include +#include + using lyx::pos_type; using lyx::support::AddPath; using lyx::support::bformat; using lyx::support::FileFilterList; using lyx::support::FileSearch; +using lyx::support::ForkedcallsController; using lyx::support::IsDirWriteable; using lyx::support::MakeDisplayPath; +using lyx::support::MakeAbsPath; using lyx::support::strToUnsignedInt; using lyx::support::system_lyxdir; @@ -82,6 +92,7 @@ using std::istringstream; using std::make_pair; using std::min; using std::string; +using std::mem_fun_ref; extern BufferList bufferlist; @@ -105,17 +116,31 @@ boost::signals::connection selectioncon; boost::signals::connection lostcon; +/// Get next inset of this class from current cursor position +template +T * getInsetByCode(LCursor & cur, InsetBase::Code code) +{ + T * inset = 0; + DocIterator it = cur; + if (it.nextInset() && + it.nextInset()->lyxCode() == code) { + inset = static_cast(it.nextInset()); + } + return inset; +} + + } // anon namespace BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner, - int xpos, int ypos, int width, int height) + int width, int height) : bv_(&bv), owner_(owner), buffer_(0), cursor_timeout(400), using_xterm_cursor(false), cursor_(bv) { xsel_cache_.set = false; - workarea_.reset(WorkAreaFactory::create(xpos, ypos, width, height)); + workarea_.reset(WorkAreaFactory::create(*owner_, width, height)); screen_.reset(LyXScreenFactory::create(workarea())); // Setup the signals @@ -305,8 +330,17 @@ void BufferView::Pimpl::setBuffer(Buffer * b) if (buffer_) disconnectBuffer(); - // set current buffer - buffer_ = b; + // if we are closing current buffer, switch to the first in + // buffer list. + if (!b) { + lyxerr[Debug::INFO] << " No Buffer!" << endl; + // we are closing the buffer, use the first buffer as current + buffer_ = bufferlist.first(); + owner_->getDialogs().hideBufferDependent(); + } else { + // set current buffer + buffer_ = b; + } // reset old cursor top_y_ = 0; @@ -323,6 +357,7 @@ void BufferView::Pimpl::setBuffer(Buffer * b) cursor_.push(buffer_->inset()); cursor_.resetAnchor(); buffer_->text().init(bv_); + buffer_->text().setCurrentFont(cursor_); // If we don't have a text object for this, we make one //if (bv_->text() == 0) @@ -332,28 +367,32 @@ void BufferView::Pimpl::setBuffer(Buffer * b) // hidden. This should go here because some dialogs (eg ToC) // require bv_->text. owner_->getDialogs().updateBufferDependent(true); - owner_->setLayout(bv_->text()->getPar(0)->layout()->name()); - } else { - lyxerr[Debug::INFO] << " No Buffer!" << endl; - // we are closing the buffer, use the first buffer as current - buffer_ = bufferlist.first(); - owner_->getDialogs().hideBufferDependent(); } update(); updateScrollbar(); owner_->updateMenubar(); - owner_->updateToolbar(); + owner_->updateToolbars(); owner_->updateLayoutChoice(); owner_->updateWindowTitle(); - if (lyx::graphics::Previews::activated() && buffer_) + // This is done after the layout combox has been populated + if (buffer_) + owner_->setLayout(cursor_.paragraph().layout()->name()); + + if (buffer_ && lyx::graphics::Previews::status() != LyXRC::PREVIEW_OFF) lyx::graphics::Previews::get().generateBufferPreviews(*buffer_); } bool BufferView::Pimpl::fitCursor() { + // to get the correct y cursor info + lyxerr[Debug::DEBUG] << "BufferView::fitCursor" << std::endl; + lyx::pit_type const pit = bv_->cursor().bottom().pit(); + bv_->text()->redoParagraph(pit); + refreshPar(*bv_, *bv_->text(), pit); + if (!screen().fitCursor(bv_)) return false; updateScrollbar(); @@ -363,7 +402,7 @@ bool BufferView::Pimpl::fitCursor() void BufferView::Pimpl::redoCurrentBuffer() { - lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl; + lyxerr[Debug::DEBUG] << "BufferView::redoCurrentBuffer" << endl; if (buffer_ && bv_->text()) { resizeCurrentBuffer(); updateScrollbar(); @@ -374,57 +413,16 @@ void BufferView::Pimpl::redoCurrentBuffer() void BufferView::Pimpl::resizeCurrentBuffer() { - lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl; - - int par = -1; - int selstartpar = -1; - int selendpar = -1; - - pos_type pos = 0; - pos_type selstartpos = 0; - pos_type selendpos = 0; - bool sel = false; - bool mark_set = false; - + lyxerr[Debug::DEBUG] << "resizeCurrentBuffer" << endl; owner_->busy(true); - owner_->message(_("Formatting document...")); LyXText * text = bv_->text(); - lyxerr << "### resizeCurrentBuffer: text " << text << endl; if (!text) return; - LCursor & cur = bv_->cursor(); - par = cur.par(); - pos = cur.pos(); - selstartpar = cur.selBegin().par(); - selstartpos = cur.selBegin().pos(); - selendpar = cur.selEnd().par(); - selendpos = cur.selEnd().pos(); - sel = cur.selection(); - mark_set = cur.mark(); text->init(bv_); update(); - - if (par != -1) { - cur.selection() = true; - // At this point just to avoid the Delete-Empty-Paragraph- - // Mechanism when setting the cursor. - cur.mark() = mark_set; - if (sel) { - text->setCursor(cur, selstartpar, selstartpos); - cur.resetAnchor(); - text->setCursor(cur, selendpar, selendpos); - cur.setSelection(); - text->setCursor(cur, par, pos); - } else { - text->setCursor(cur, par, pos); - cur.resetAnchor(); - cur.selection() = false; - } - } - fitCursor(); switchKeyMap(); @@ -440,8 +438,7 @@ void BufferView::Pimpl::resizeCurrentBuffer() void BufferView::Pimpl::updateScrollbar() { if (!bv_->text()) { - lyxerr[Debug::GUI] << "no text in updateScrollbar" << endl; - lyxerr << "no text in updateScrollbar" << endl; + lyxerr[Debug::DEBUG] << "no text in updateScrollbar" << endl; workarea().setScrollbarParams(0, 0, 0); return; } @@ -476,14 +473,14 @@ void BufferView::Pimpl::scrollDocView(int value) int const first = top_y() + height; int const last = top_y() + workarea().workHeight() - height; - bv_->cursor().reset(); + bv_->cursor().reset(bv_->buffer()->inset()); LyXText * text = bv_->text(); - CursorSlice & cur = bv_->cursor().front(); - int y = text->cursorY(cur); + int y = text->cursorY(bv_->cursor().front()); if (y < first) - text->setCursorFromCoordinates(bv_->cursor(), 0, first); - else if (y > last) - text->setCursorFromCoordinates(bv_->cursor(), 0, last); + y = first; + if (y > last) + y = last; + text->setCursorFromCoordinates(bv_->cursor(), 0, y); owner_->updateLayoutChoice(); } @@ -554,7 +551,7 @@ void BufferView::Pimpl::selectionRequested() sel = cur.selectionAsString(false); if (!sel.empty()) workarea().putClipboard(sel); - } + } } @@ -601,16 +598,26 @@ void BufferView::Pimpl::update() // check needed to survive LyX startup if (buffer_) { + // update macro store + buffer_->buildMacros(); + // update all 'visible' paragraphs - ParagraphList::iterator beg; - ParagraphList::iterator end; + lyx::pit_type beg, end; getParsInRange(buffer_->paragraphs(), top_y(), top_y() + workarea().workHeight(), beg, end); bv_->text()->redoParagraphs(beg, end); + + // and the scrollbar updateScrollbar(); } + + // remove old position cache + theCoords.clear(); + + // The real, big redraw. screen().redraw(*bv_); + bv_->owner()->view_state_changed(); } @@ -618,8 +625,17 @@ void BufferView::Pimpl::update() // Callback for cursor timer void BufferView::Pimpl::cursorToggle() { - if (buffer_) + if (buffer_) { screen().toggleCursor(*bv_); + + // Use this opportunity to deal with any child processes that + // have finished but are waiting to communicate this fact + // to the rest of LyX. + ForkedcallsController & fcc = ForkedcallsController::get(); + if (fcc.processesCompleted()) + fcc.handleCompletedProcesses(); + } + cursor_timeout.restart(); } @@ -641,8 +657,8 @@ Change const BufferView::Pimpl::getCurrentChange() if (!cur.selection()) return Change(Change::UNCHANGED); - return text->getPar(cur.selBegin()) - ->lookupChangeFull(cur.selBegin().pos()); + return text->getPar(cur.selBegin().pit()). + lookupChangeFull(cur.selBegin().pos()); } @@ -650,9 +666,10 @@ void BufferView::Pimpl::savePosition(unsigned int i) { if (i >= saved_positions_num) return; + BOOST_ASSERT(bv_->cursor().inTexted()); saved_positions[i] = Position(buffer_->fileName(), - bv_->text()->cursorPar()->id(), - bv_->text()->cursor().pos()); + bv_->cursor().paragraph().id(), + bv_->cursor().pos()); if (i > 0) owner_->message(bformat(_("Saved bookmark %1$s"), tostr(i))); } @@ -683,9 +700,7 @@ void BufferView::Pimpl::restorePosition(unsigned int i) if (par == buffer_->par_iterator_end()) return; - bv_->text()->setCursor( - bv_->cursor(), - bv_->text()->parOffset(par.pit()), + bv_->text()->setCursor(bv_->cursor(), par.pit(), min(par->size(), saved_positions[i].par_pos)); if (i > 0) @@ -744,42 +759,6 @@ void BufferView::Pimpl::stuffClipboard(string const & stuff) const } -InsetBase * BufferView::Pimpl::getInsetByCode(InsetBase::Code code) -{ -#warning Does not work for mathed - // Ok, this is a little bit too brute force but it - // should work for now. Better infrastructure is coming. (Lgb) - - Buffer * buf = bv_->buffer(); - Buffer::inset_iterator beg = buf->inset_iterator_begin(); - Buffer::inset_iterator end = buf->inset_iterator_end(); - - bool cursor_par_seen = false; - - LCursor & cur = bv_->cursor(); - ParagraphList::iterator pit = bv_->getLyXText()->getPar(cur.par()); - - for (; beg != end; ++beg) { - if (beg.getPar() == pit) - cursor_par_seen = true; - if (cursor_par_seen) { - if (beg.getPar() == pit && beg.getPos() >= cur.pos()) - break; - if (beg.getPar() != pit) - break; - } - } - if (beg != end) { - // Now find the first inset that matches code. - for (; beg != end; ++beg) { - if (beg->lyxCode() == code) - return &(*beg); - } - } - return 0; -} - - void BufferView::Pimpl::MenuInsertLyXFile(string const & filenm) { string filename = filenm; @@ -825,12 +804,19 @@ void BufferView::Pimpl::MenuInsertLyXFile(string const & filenm) string const disp_fn = MakeDisplayPath(filename); owner_->message(bformat(_("Inserting document %1$s..."), disp_fn)); - if (bv_->insertLyXFile(filename)) - owner_->message(bformat(_("Document %1$s inserted."), - disp_fn)); - else - owner_->message(bformat(_("Could not insert document %1$s"), - disp_fn)); + + bv_->cursor().clearSelection(); + bv_->text()->breakParagraph(bv_->cursor()); + + BOOST_ASSERT(bv_->cursor().inTexted()); + + string const fname = MakeAbsPath(filename); + bool const res = bv_->buffer()->readFile(fname, bv_->cursor().pit()); + bv_->resize(); + + string s = res ? _("Document %1$s inserted.") + : _("Could not insert document %1$s"); + owner_->message(bformat(s, disp_fn)); } @@ -840,9 +826,9 @@ void BufferView::Pimpl::trackChanges() bool const tracking = buf->params().tracking_changes; if (!tracking) { - ParIterator const end = buf->par_iterator_end(); - for (ParIterator it = buf->par_iterator_begin(); it != end; ++it) - it->trackChanges(); + for_each(buf->par_iterator_begin(), + buf->par_iterator_end(), + bind(&Paragraph::trackChanges, _1, Change::UNCHANGED)); buf->params().tracking_changes = true; // we cannot allow undos beyond the freeze point @@ -850,16 +836,19 @@ void BufferView::Pimpl::trackChanges() } else { update(); bv_->text()->setCursor(bv_->cursor(), 0, 0); +#ifdef WITH_WARNINGS #warning changes FIXME +#endif bool found = lyx::find::findNextChange(bv_); if (found) { owner_->getDialogs().show("changes"); return; } - ParIterator const end = buf->par_iterator_end(); - for (ParIterator it = buf->par_iterator_begin(); it != end; ++it) - it->untrackChanges(); + for_each(buf->par_iterator_begin(), + buf->par_iterator_end(), + mem_fun_ref(&Paragraph::untrackChanges)); + buf->params().tracking_changes = false; } @@ -869,104 +858,143 @@ void BufferView::Pimpl::trackChanges() bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0) { - // - // this is only called for mouse related events (including - // LFUN_FILE_OPEN generated by drag-and-drop) - // + lyxerr << "BufferView::Pimpl::workAreaDispatch: request: " + << cmd0 << std::endl; + // this is only called for mouse related events including + // LFUN_FILE_OPEN generated by drag-and-drop. FuncRequest cmd = cmd0; + + // handle drag&drop + if (cmd.action == LFUN_FILE_OPEN) { + owner_->dispatch(cmd); + return true; + } + cmd.y += bv_->top_y(); - //lyxerr << "*** workAreaDispatch: request: " << cmd << std::endl; + if (!bv_->buffer()) + return false; + LCursor cur(*bv_); cur.push(bv_->buffer()->inset()); - cur.resetAnchor(); cur.selection() = bv_->cursor().selection(); - switch (cmd.action) { -#if 0 - case LFUN_MOUSE_MOTION: { - if (!available()) - return false; - FuncRequest cmd1 = cmd; - DispatchResult res = cur.inset().dispatch(cur, cmd); - if (fitCursor() || res.update()) { - update(); - cur.updatePos(); - } - return true; - } -#else - case LFUN_MOUSE_MOTION: -#endif + // Doesn't go through lyxfunc, so we need to update + // the layout choice etc. ourselves - case LFUN_MOUSE_PRESS: - case LFUN_MOUSE_RELEASE: - case LFUN_MOUSE_DOUBLE: - case LFUN_MOUSE_TRIPLE: { - // We pass those directly to the Bufferview, since - // otherwise selection handling breaks down + // e.g. Qt mouse press when no buffer + if (!available()) + return false; - // Doesn't go through lyxfunc, so we need to update - // the layout choice etc. ourselves + screen().hideCursor(); - // e.g. Qt mouse press when no buffer - if (!available()) - return false; + // Either the inset under the cursor or the + // surrounding LyXText will handle this event. - screen().hideCursor(); + // Build temporary cursor. + InsetBase * inset = bv_->text()->editXY(cur, cmd.x, cmd.y); + lyxerr << " * created temp cursor: " << inset << endl; + lyxerr << " * hit inset at tip: " << inset << endl; + lyxerr << " * created temp cursor:" << cur << endl; - // either the inset under the cursor or the - // surrounding LyXText will handle this event. + // Put anchor at the same position. + cur.resetAnchor(); - // built temporary path to inset - InsetBase * inset = bv_->text()->editXY(cur, cmd.x, cmd.y); - lyxerr << "hit inset at tip: " << inset << endl; - lyxerr << "created temp cursor:\n" << cur << endl; + // Try to dispatch to an non-editable inset near this position + // via the temp cursor. If the inset wishes to change the real + // cursor it has to do so explicitly by using + // cur.bv().cursor() = cur; (or similar) + if (inset) + inset->dispatch(cur, cmd); + + // Now dispatch to the temporary cursor. If the real cursor should + // be modified, the inset's dispatch has to do so explicitly. + if (!cur.result().dispatched()) + cur.dispatch(cmd); + + if (cur.result().dispatched()) { + // Redraw if requested or necessary. + if (fitCursor() || cur.result().update()) + update(); + } - // Try to dispatch to an non-editable inset near this position - DispatchResult res; - if (inset) - inset->dispatch(cur, cmd); + // see workAreaKeyPress + cursor_timeout.restart(); + screen().showCursor(*bv_); - // Dispatch to the temp cursor. - // An inset (or LyXText) can assign this to bv->cursor() - // if it wishes to do so. - if (!res.dispatched()) - res = cur.dispatch(cmd); + // skip these when selecting + if (cmd.action != LFUN_MOUSE_MOTION) { + owner_->updateLayoutChoice(); + owner_->updateToolbars(); + } - if (fitCursor() || res.update()) - update(); + // slight hack: this is only called currently when we + // clicked somewhere, so we force through the display + // of the new status here. + owner_->clearMessage(); + return true; +} - // see workAreaKeyPress - cursor_timeout.restart(); - screen().showCursor(*bv_); - // skip these when selecting - if (cmd.action != LFUN_MOUSE_MOTION) { - owner_->updateLayoutChoice(); - owner_->updateToolbar(); - } +FuncStatus BufferView::Pimpl::getStatus(FuncRequest const & cmd) +{ + Buffer * buf = bv_->buffer(); - // slight hack: this is only called currently when we - // clicked somewhere, so we force through the display - // of the new status here. - owner_->clearMessage(); - return true; - } + FuncStatus flag; - case LFUN_FILE_OPEN: - owner_->dispatch(cmd); - return true; + switch (cmd.action) { + case LFUN_UNDO: + flag.enabled(!buf->undostack().empty()); + break; + case LFUN_REDO: + flag.enabled(!buf->redostack().empty()); + break; + case LFUN_FILE_INSERT: + case LFUN_FILE_INSERT_ASCII_PARA: + case LFUN_FILE_INSERT_ASCII: + case LFUN_FONT_STATE: + case LFUN_INSERT_LABEL: + case LFUN_BOOKMARK_SAVE: + case LFUN_REF_GOTO: + case LFUN_WORD_FIND: + case LFUN_WORD_REPLACE: + case LFUN_MARK_OFF: + case LFUN_MARK_ON: + case LFUN_SETMARK: + case LFUN_CENTER: + case LFUN_BEGINNINGBUF: + case LFUN_ENDBUF: + case LFUN_BEGINNINGBUFSEL: + case LFUN_ENDBUFSEL: + flag.enabled(true); + break; + case LFUN_BOOKMARK_GOTO: + flag.enabled(bv_->isSavedPosition(strToUnsignedInt(cmd.argument))); + break; + case LFUN_TRACK_CHANGES: + flag.enabled(true); + flag.setOnOff(buf->params().tracking_changes); + break; + + case LFUN_MERGE_CHANGES: + case LFUN_ACCEPT_CHANGE: // what about these two + case LFUN_REJECT_CHANGE: // what about these two + case LFUN_ACCEPT_ALL_CHANGES: + case LFUN_REJECT_ALL_CHANGES: + flag.enabled(buf && buf->params().tracking_changes); + break; default: - BOOST_ASSERT(false); + flag.enabled(false); } - return true; + + return flag; } + bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) { - //lyxerr << "*** BufferView::Pimpl: request: " << cmd << std::endl; + //lyxerr << "BufferView::Pimpl::dispatch cmd: " << cmd << std::endl; // Make sure that the cached BufferView is correct. lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch:" << " action[" << cmd.action << ']' @@ -1018,16 +1046,6 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) cur.message(cur.currentState()); break; - case LFUN_INSERT_LABEL: { - // Try and generate a valid label - string const contents = cmd.argument.empty() ? - cur.getPossibleLabel() : cmd.argument; - InsetCommandParams icp("label", contents); - string data = InsetCommandMailer::params2string("label", icp); - owner_->getDialogs().show("label", data, 0); - break; - } - case LFUN_BOOKMARK_SAVE: savePosition(strToUnsignedInt(cmd.argument)); break; @@ -1040,7 +1058,8 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) string label = cmd.argument; if (label.empty()) { InsetRef * inset = - static_cast(getInsetByCode(InsetBase::REF_CODE)); + getInsetByCode(bv_->cursor(), + InsetBase::REF_CODE); if (inset) { label = inset->getContents(); savePosition(0); @@ -1061,8 +1080,10 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) break; case LFUN_ACCEPT_ALL_CHANGES: { - bv_->cursor().reset(); + bv_->cursor().reset(bv_->buffer()->inset()); +#ifdef WITH_WARNINGS #warning FIXME changes +#endif while (lyx::find::findNextChange(bv_)) bv_->getLyXText()->acceptChange(bv_->cursor()); update(); @@ -1070,11 +1091,12 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) } case LFUN_REJECT_ALL_CHANGES: { - bv_->cursor().reset(); + bv_->cursor().reset(bv_->buffer()->inset()); +#ifdef WITH_WARNINGS #warning FIXME changes +#endif while (lyx::find::findNextChange(bv_)) bv_->getLyXText()->rejectChange(bv_->cursor()); - update(); break; } @@ -1088,7 +1110,6 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) case LFUN_MARK_OFF: cur.clearSelection(); - update(); cur.resetAnchor(); cur.message(N_("Mark off")); break; @@ -1096,7 +1117,6 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) case LFUN_MARK_ON: cur.clearSelection(); cur.mark() = true; - update(); cur.resetAnchor(); cur.message(N_("Mark on")); break; @@ -1111,11 +1131,6 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) cur.message(N_("Mark set")); } cur.resetAnchor(); - update(); - break; - - case LFUN_UNKNOWN_ACTION: - cur.errorMessage(N_("Unknown function!")); break; case LFUN_CENTER: @@ -1123,7 +1138,7 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) break; case LFUN_BEGINNINGBUFSEL: - bv_->cursor().reset(); + bv_->cursor().reset(bv_->buffer()->inset()); if (!cur.selection()) cur.resetAnchor(); bv_->text()->cursorTop(cur); @@ -1131,7 +1146,7 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) break; case LFUN_ENDBUFSEL: - bv_->cursor().reset(); + bv_->cursor().reset(bv_->buffer()->inset()); if (!cur.selection()) cur.resetAnchor(); bv_->text()->cursorBottom(cur);