#include "BufferList.h"
#include "BufferParams.h"
#include "bufferview_funcs.h"
+#include "callback.h" // added for Dispatch functions
#include "CoordCache.h"
#include "CutAndPaste.h"
#include "debug.h"
#include "InsetIterator.h"
#include "Language.h"
#include "LaTeXFeatures.h"
-#include "callback.h" // added for Dispatch functions
#include "LyX.h"
#include "lyxfind.h"
#include "LyXFunc.h"
#include "Layout.h"
-#include "LyXText.h"
-#include "TextClass.h"
#include "LyXRC.h"
-#include "Session.h"
+#include "MetricsInfo.h"
#include "Paragraph.h"
#include "paragraph_funcs.h"
#include "ParagraphParameters.h"
#include "ParIterator.h"
+#include "Session.h"
#include "TexRow.h"
+#include "Text.h"
+#include "TextClass.h"
#include "toc.h"
#include "Undo.h"
#include "VSpace.h"
#include "WordLangTuple.h"
-#include "MetricsInfo.h"
#include "insets/InsetBibtex.h"
#include "insets/InsetCommand.h" // ChangeRefs
#include "frontends/alert.h"
#include "frontends/FileDialog.h"
#include "frontends/FontMetrics.h"
+#include "frontends/Painter.h"
+#include "frontends/Selection.h"
#include "graphics/Previews.h"
#include <functional>
#include <vector>
+using std::distance;
+using std::endl;
+using std::istringstream;
+using std::make_pair;
+using std::min;
+using std::max;
+using std::mem_fun_ref;
+using std::string;
+using std::vector;
+
namespace lyx {
using support::makeDisplayPath;
using support::package;
-using std::distance;
-using std::endl;
-using std::istringstream;
-using std::make_pair;
-using std::min;
-using std::max;
-using std::mem_fun_ref;
-using std::string;
-using std::vector;
-
namespace Alert = frontend::Alert;
namespace {
} // anon namespace
-BufferView::BufferView()
- : width_(0), height_(0), buffer_(0), wh_(0),
+BufferView::BufferView(Buffer & buf)
+ : width_(0), height_(0), buffer_(buf), wh_(0),
cursor_(*this),
multiparsel_cache_(false), anchor_ref_(0), offset_ref_(0),
- intl_(new Intl), last_inset_(0)
+ need_centering_(false), intl_(new Intl), last_inset_(0)
{
xsel_cache_.set = false;
intl_->initKeyMapper(lyxrc.use_kbmap);
-}
-
-BufferView::~BufferView()
-{
-}
+ cursor_.push(buffer_.inset());
+ cursor_.resetAnchor();
+ cursor_.setCurrentFont();
-
-Buffer * BufferView::buffer() const
-{
- return buffer_;
+ if (graphics::Previews::status() != LyXRC::PREVIEW_OFF)
+ graphics::Previews::get().generateBufferPreviews(buffer_);
}
-void BufferView::setBuffer(Buffer * b)
+BufferView::~BufferView()
{
- LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION
- << "[ b = " << b << "]" << endl;
-
- if (buffer_) {
- // Save the actual cursor position and anchor inside the
- // buffer so that it can be restored in case we rechange
- // to this buffer later on.
- buffer_->saveCursor(cursor_.selectionBegin(),
- cursor_.selectionEnd());
- // update bookmark pit of the current buffer before switch
- for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) {
- BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(i);
- if (buffer()->fileName() != bm.filename.absFilename())
- continue;
- // if top_id or bottom_pit, bottom_pos has been changed, update bookmark
- // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
- pit_type new_pit;
- pos_type new_pos;
- int new_id;
- boost::tie(new_pit, new_pos, new_id) = moveToPosition(bm.bottom_pit, bm.bottom_pos, bm.top_id, bm.top_pos);
- if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos || bm.top_id != new_id )
- const_cast<BookmarksSection::Bookmark &>(bm).updatePos(new_pit, new_pos, new_id);
- }
- // current buffer is going to be switched-off, save cursor pos
- // Ideally, the whole cursor stack should be saved, but session
- // currently can only handle bottom (whole document) level pit and pos.
- // That is to say, if a cursor is in a nested inset, it will be
- // restore to the left of the top level inset.
- LyX::ref().session().lastFilePos().save(FileName(buffer_->fileName()),
- boost::tie(cursor_.bottom().pit(), cursor_.bottom().pos()) );
- }
-
- // If we're quitting lyx, don't bother updating stuff
- if (quitting) {
- buffer_ = 0;
- return;
- }
-
- // If we are closing current buffer, switch to the first in
- // buffer list.
- if (!b) {
- LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION
- << " No Buffer!" << endl;
- // We are closing the buffer, use the first buffer as current
- buffer_ = theBufferList().first();
- } else {
- // Set current buffer
- buffer_ = b;
- }
-
- // Reset old cursor
- cursor_ = Cursor(*this);
- anchor_ref_ = 0;
- offset_ref_ = 0;
-
- if (buffer_) {
- LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION
- << "Buffer addr: " << buffer_ << endl;
- cursor_.push(buffer_->inset());
- cursor_.resetAnchor();
- buffer_->text().setCurrentFont(cursor_);
- if (buffer_->getCursor().size() > 0 &&
- buffer_->getAnchor().size() > 0)
- {
- cursor_.setCursor(buffer_->getAnchor().asDocIterator(&(buffer_->inset())));
- cursor_.resetAnchor();
- cursor_.setCursor(buffer_->getCursor().asDocIterator(&(buffer_->inset())));
- cursor_.setSelection();
- // do not set selection to the new buffer because we
- // only paste recent selection.
- }
- }
-
- if (buffer_)
- updateMetrics(false);
-
- if (buffer_ && graphics::Previews::status() != LyXRC::PREVIEW_OFF)
- graphics::Previews::get().generateBufferPreviews(*buffer_);
+ // current buffer is going to be switched-off, save cursor pos
+ // Ideally, the whole cursor stack should be saved, but session
+ // currently can only handle bottom (whole document) level pit and pos.
+ // That is to say, if a cursor is in a nested inset, it will be
+ // restore to the left of the top level inset.
+ LyX::ref().session().lastFilePos().save(
+ support::FileName(buffer_.fileName()),
+ boost::tie(cursor_.bottom().pit(), cursor_.bottom().pos()) );
}
-bool BufferView::loadLyXFile(FileName const & filename, bool tolastfiles)
+Buffer & BufferView::buffer()
{
- // File already open?
- if (theBufferList().exists(filename.absFilename())) {
- docstring const file = makeDisplayPath(filename.absFilename(), 20);
- docstring text = bformat(_("The document %1$s is already "
- "loaded.\n\nDo you want to revert "
- "to the saved version?"), file);
- int const ret = Alert::prompt(_("Revert to saved document?"),
- text, 0, 1, _("&Revert"), _("&Switch to document"));
-
- if (ret != 0) {
- setBuffer(theBufferList().getBuffer(filename.absFilename()));
- return true;
- }
- // FIXME: should be LFUN_REVERT
- if (!theBufferList().close(theBufferList().getBuffer(filename.absFilename()), false))
- return false;
- // Fall through to new load. (Asger)
- buffer_ = 0;
- }
-
- Buffer * b = 0;
-
- if (isFileReadable(filename)) {
- b = theBufferList().newBuffer(filename.absFilename());
- if (!lyx::loadLyXFile(b, filename)) {
- theBufferList().release(b);
- return false;
- }
- } else {
- docstring text = bformat(_("The document %1$s does not yet "
- "exist.\n\nDo you want to create "
- "a new document?"), from_utf8(filename.absFilename()));
- int const ret = Alert::prompt(_("Create new document?"),
- text, 0, 1, _("&Create"), _("Cancel"));
-
- if (ret == 0) {
- b = newFile(filename.absFilename(), string(), true);
- if (!b)
- return false;
- } else
- return false;
- }
-
- setBuffer(b);
- // Send the "errors" signal in case of parsing errors
- b->errors("Parse");
-
- // Update the labels and section numbering.
- updateLabels(*buffer_);
- // scroll to the position when the file was last closed
- if (lyxrc.use_lastfilepos) {
- pit_type pit;
- pos_type pos;
- boost::tie(pit, pos) = LyX::ref().session().lastFilePos().load(filename);
- // if successfully move to pit (returned par_id is not zero), update metrics and reset font
- if (moveToPosition(pit, pos, 0, 0).get<1>()) {
- if (fitCursor())
- updateMetrics(false);
- buffer_->text().setCurrentFont(cursor_);
- }
- }
-
- if (tolastfiles)
- LyX::ref().session().lastFiles().add(FileName(b->fileName()));
-
- return true;
+ return buffer_;
}
-void BufferView::resize()
+Buffer const & BufferView::buffer() const
{
- if (!buffer_)
- return;
-
- LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION << endl;
-
- updateMetrics(false);
- switchKeyMap();
+ return buffer_;
}
<< "[fitcursor = " << (flags & Update::FitCursor)
<< ", forceupdate = " << (flags & Update::Force)
<< ", singlepar = " << (flags & Update::SinglePar)
- << "] buffer: " << buffer_ << endl;
-
- // Check needed to survive LyX startup
- if (!buffer_)
- return false;
-
- LYXERR(Debug::WORKAREA) << "BufferView::update" << std::endl;
+ << "] buffer: " << &buffer_ << endl;
// Update macro store
if (!(cursor().inMathed() && cursor().inMacroMode()))
- buffer_->buildMacros();
+ buffer_.buildMacros();
// Now do the first drawing step if needed. This consists on updating
// the CoordCache in updateMetrics().
return true;
}
- if (flags == Update::FitCursor
+ if (flags == Update::FitCursor
|| flags == (Update::Decoration | Update::FitCursor)) {
bool const fit_cursor = fitCursor();
// tell the frontend to update the screen if needed.
void BufferView::updateScrollbar()
{
- if (!buffer_) {
- LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION
- << " no text in updateScrollbar" << endl;
- scrollbarParameters_.reset();
- return;
- }
-
- LyXText & t = buffer_->text();
+ Text & t = buffer_.text();
TextMetrics & tm = text_metrics_[&t];
int const parsize = int(t.paragraphs().size() - 1);
LYXERR(Debug::GUI) << BOOST_CURRENT_FUNCTION
<< "[ value = " << value << "]" << endl;
- if (!buffer_)
- return;
-
- LyXText & t = buffer_->text();
+ Text & t = buffer_.text();
TextMetrics & tm = text_metrics_[&t];
float const bar = value / float(wh_ * t.paragraphs().size());
void BufferView::setCursorFromScrollbar()
{
- if (!buffer_)
- return;
-
- LyXText & t = buffer_->text();
+ TextMetrics & tm = text_metrics_[&buffer_.text()];
int const height = 2 * defaultRowHeight();
int const first = height;
case bv_funcs::CUR_ABOVE:
// We reset the cursor because bv_funcs::status() does not
// work when the cursor is within mathed.
- cur.reset(buffer_->inset());
- t.setCursorFromCoordinates(cur, 0, first);
+ cur.reset(buffer_.inset());
+ tm.setCursorFromCoordinates(cur, 0, first);
cur.clearSelection();
break;
case bv_funcs::CUR_BELOW:
// We reset the cursor because bv_funcs::status() does not
// work when the cursor is within mathed.
- cur.reset(buffer_->inset());
- t.setCursorFromCoordinates(cur, 0, last);
+ cur.reset(buffer_.inset());
+ tm.setCursorFromCoordinates(cur, 0, last);
cur.clearSelection();
break;
case bv_funcs::CUR_INSIDE:
int const y = bv_funcs::getPos(*this, cur, cur.boundary()).y_;
int const newy = min(last, max(y, first));
if (y != newy) {
- cur.reset(buffer_->inset());
- t.setCursorFromCoordinates(cur, 0, newy);
+ cur.reset(buffer_.inset());
+ tm.setCursorFromCoordinates(cur, 0, newy);
}
}
}
{
// tenatively save bookmark, id and pos will be used to
// acturately locate a bookmark in a 'live' lyx session.
- // pit and pos will be updated with bottom level pit/pos
+ // pit and pos will be updated with bottom level pit/pos
// when lyx exits.
LyX::ref().session().bookmarks().save(
- FileName(buffer_->fileName()),
+ FileName(buffer_.fileName()),
cursor_.bottom().pit(),
cursor_.bottom().pos(),
cursor_.paragraph().id(),
}
-boost::tuple<pit_type, pos_type, int> BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
+bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
int top_id, pos_type top_pos)
{
+ bool success = false;
+ DocIterator doc_it;
+
cursor_.clearSelection();
// if a valid par_id is given, try it first
// This is the case for a 'live' bookmark when unique paragraph ID
// is used to track bookmarks.
if (top_id > 0) {
- ParIterator par = buffer_->getParFromID(top_id);
- if (par != buffer_->par_iterator_end()) {
- DocIterator dit = makeDocIterator(par, min(par->size(), top_pos));
- // Some slices of the iterator may not be reachable (e.g. closed collapsable inset)
- // so the dociterator may need to be shortened. Otherwise, setCursor may
- // crash lyx when the cursor can not be set to these insets.
- size_t const n = dit.depth();
+ ParIterator par = buffer_.getParFromID(top_id);
+ if (par != buffer_.par_iterator_end()) {
+ doc_it = makeDocIterator(par, min(par->size(), top_pos));
+ // Some slices of the iterator may not be
+ // reachable (e.g. closed collapsable inset)
+ // so the dociterator may need to be
+ // shortened. Otherwise, setCursor may crash
+ // lyx when the cursor can not be set to these
+ // insets.
+ size_t const n = doc_it.depth();
for (size_t i = 0; i < n; ++i)
- if (dit[i].inset().editable() != Inset::HIGHLY_EDITABLE) {
- dit.resize(i);
+ if (doc_it[i].inset().editable() != Inset::HIGHLY_EDITABLE) {
+ doc_it.resize(i);
break;
}
- setCursor(dit);
- // Note: return bottom (document) level pit.
- return boost::make_tuple(cursor_.bottom().pit(), cursor_.bottom().pos(), top_id);
+ success = true;
}
}
+
// if top_id == 0, or searching through top_id failed
- // This is the case for a 'restored' bookmark when only bottom
+ // This is the case for a 'restored' bookmark when only bottom
// (document level) pit was saved. Because of this, bookmark
// restoration is inaccurate. If a bookmark was within an inset,
// it will be restored to the left of the outmost inset that contains
// the bookmark.
- if (static_cast<size_t>(bottom_pit) < buffer_->paragraphs().size()) {
- ParIterator it = buffer_->par_iterator_begin();
- ParIterator const end = buffer_->par_iterator_end();
- for (; it != end; ++it)
- if (it.pit() == bottom_pit) {
- // restored pos may be bigger than it->size
- setCursor(makeDocIterator(it, min(bottom_pos, it->size())));
- return boost::make_tuple(bottom_pit, bottom_pos, it->id());
- }
+ if (static_cast<size_t>(bottom_pit) < buffer_.paragraphs().size()) {
+ doc_it = doc_iterator_begin(buffer_.inset());
+ doc_it.pit() = bottom_pit;
+ doc_it.pos() = min(bottom_pos, doc_it.paragraph().size());
+ success = true;
}
- // both methods fail
- return boost::make_tuple(pit_type(0), pos_type(0), 0);
+
+ if (success) {
+ // Note: only bottom (document) level pit is set.
+ setCursor(doc_it);
+ // set the current font.
+ cursor_.setCurrentFont();
+ // center the screen on this new position.
+ center();
+ }
+
+ return success;
}
-void BufferView::switchKeyMap()
+void BufferView::translateAndInsert(char_type c, Text * t, Cursor & cur)
{
- if (!lyxrc.rtl_support)
- return;
-
- if (cursor_.innerText()->real_current_font.isRightToLeft()) {
- if (intl_->keymap == Intl::PRIMARY)
- intl_->keyMapSec();
- } else {
- if (intl_->keymap == Intl::SECONDARY)
- intl_->keyMapPrim();
+ if (lyxrc.rtl_support) {
+ if (cursor_.real_current_font.isRightToLeft()) {
+ if (intl_->keymap == Intl::PRIMARY)
+ intl_->keyMapSec();
+ } else {
+ if (intl_->keymap == Intl::SECONDARY)
+ intl_->keyMapPrim();
+ }
}
+
+ intl_->getTransManager().translateAndInsert(c, t, cur);
}
}
-void BufferView::center()
+void BufferView::updateOffsetRef()
{
+ // No need to update offset_ref_ in this case.
+ if (!need_centering_)
+ return;
+
+ // We are not properly started yet, delay until resizing is
+ // done.
+ if (height_ == 0)
+ return;
+
CursorSlice & bot = cursor_.bottom();
TextMetrics & tm = text_metrics_[bot.text()];
- pit_type const pit = bot.pit();
- tm.redoParagraph(pit);
- ParagraphMetrics const & pm = tm.parMetrics(pit);
- anchor_ref_ = pit;
- offset_ref_ = bv_funcs::coordOffset(*this, cursor_, cursor_.boundary()).y_
- + pm.ascent() - height_ / 2;
+ ParagraphMetrics const & pm = tm.parMetrics(bot.pit());
+ Point p = bv_funcs::coordOffset(*this, cursor_, cursor_.boundary());
+ offset_ref_ = p.y_ + pm.ascent() - height_ / 2;
+
+ need_centering_ = false;
+}
+
+
+void BufferView::center()
+{
+ anchor_ref_ = cursor_.bottom().pit();
+ need_centering_ = true;
}
{
FuncStatus flag;
+ Cursor & cur = cursor_;
+
switch (cmd.action) {
case LFUN_UNDO:
- flag.enabled(!buffer_->undostack().empty());
+ flag.enabled(!buffer_.undostack().empty());
break;
case LFUN_REDO:
- flag.enabled(!buffer_->redostack().empty());
+ flag.enabled(!buffer_.redostack().empty());
break;
case LFUN_FILE_INSERT:
case LFUN_FILE_INSERT_PLAINTEXT_PARA:
case LFUN_FILE_INSERT_PLAINTEXT:
case LFUN_BOOKMARK_SAVE:
- // FIXME: Actually, these LFUNS should be moved to LyXText
- flag.enabled(cursor_.inTexted());
+ // FIXME: Actually, these LFUNS should be moved to Text
+ flag.enabled(cur.inTexted());
break;
case LFUN_FONT_STATE:
case LFUN_LABEL_INSERT:
case LFUN_LABEL_GOTO: {
flag.enabled(!cmd.argument().empty()
- || getInsetByCode<InsetRef>(cursor_, Inset::REF_CODE));
+ || getInsetByCode<InsetRef>(cur, Inset::REF_CODE));
break;
}
case LFUN_CHANGES_TRACK:
flag.enabled(true);
- flag.setOnOff(buffer_->params().trackChanges);
+ flag.setOnOff(buffer_.params().trackChanges);
break;
case LFUN_CHANGES_OUTPUT:
- flag.enabled(buffer_ && LaTeXFeatures::isAvailable("dvipost"));
- flag.setOnOff(buffer_->params().outputChanges);
+ flag.enabled(true);
+ flag.setOnOff(buffer_.params().outputChanges);
break;
case LFUN_CHANGES_MERGE:
// In principle, these command should only be enabled if there
// is a change in the document. However, without proper
// optimizations, this will inevitably result in poor performance.
- flag.enabled(buffer_);
+ flag.enabled(true);
break;
case LFUN_BUFFER_TOGGLE_COMPRESSION: {
- flag.setOnOff(buffer_->params().compressed);
+ flag.setOnOff(buffer_.params().compressed);
break;
}
<< " button[" << cmd.button() << ']'
<< endl;
- // FIXME: this should not be possible.
- if (!buffer_)
- return Update::None;
-
Cursor & cur = cursor_;
// Default Update flags.
Update::flags updateFlags = Update::Force | Update::FitCursor;
cur.message(_("No further undo information"));
updateFlags = Update::None;
}
- switchKeyMap();
break;
case LFUN_REDO:
cur.message(_("No further redo information"));
updateFlags = Update::None;
}
- switchKeyMap();
break;
case LFUN_FILE_INSERT:
case LFUN_PARAGRAPH_GOTO: {
int const id = convert<int>(to_utf8(cmd.argument()));
int i = 0;
- for (Buffer * b = buffer_; i == 0 || b != buffer_; b = theBufferList().next(b)) {
+ for (Buffer * b = &buffer_; i == 0 || b != &buffer_;
+ b = theBufferList().next(b)) {
+
ParIterator par = b->getParFromID(id);
if (par == b->par_iterator_end()) {
LYXERR(Debug::INFO)
<< " found in buffer `"
<< b->fileName() << "'." << endl;
- if (b == buffer_) {
+ if (b == &buffer_) {
// Set the cursor
setCursor(makeDocIterator(par, 0));
- switchKeyMap();
} else {
// Switch to other buffer view and resend cmd
theLyXFunc().dispatch(FuncRequest(
case LFUN_OUTLINE_UP:
toc::outline(toc::Up, cursor_);
cursor_.text()->setCursor(cursor_, cursor_.pit(), 0);
- updateLabels(*buffer_);
+ updateLabels(buffer_);
break;
case LFUN_OUTLINE_DOWN:
toc::outline(toc::Down, cursor_);
cursor_.text()->setCursor(cursor_, cursor_.pit(), 0);
- updateLabels(*buffer_);
+ updateLabels(buffer_);
break;
case LFUN_OUTLINE_IN:
toc::outline(toc::In, cursor_);
- updateLabels(*buffer_);
+ updateLabels(buffer_);
break;
case LFUN_OUTLINE_OUT:
toc::outline(toc::Out, cursor_);
- updateLabels(*buffer_);
+ updateLabels(buffer_);
break;
case LFUN_NOTE_NEXT:
}
case LFUN_CHANGES_TRACK:
- buffer_->params().trackChanges = !buffer_->params().trackChanges;
+ buffer_.params().trackChanges = !buffer_.params().trackChanges;
break;
case LFUN_CHANGES_OUTPUT:
- buffer_->params().outputChanges = !buffer_->params().outputChanges;
+ buffer_.params().outputChanges = !buffer_.params().outputChanges;
+ if (buffer_.params().outputChanges) {
+ bool dvipost = LaTeXFeatures::isAvailable("dvipost");
+ bool xcolorsoul = LaTeXFeatures::isAvailable("soul") &&
+ LaTeXFeatures::isAvailable("xcolor");
+
+ if (!dvipost && !xcolorsoul) {
+ Alert::warning(_("Changes not shown in LaTeX output"),
+ _("Changes will not be highlighted in LaTeX output, "
+ "because neither dvipost nor xcolor/soul are installed.\n"
+ "Please install these packages or redefine "
+ "\\lyxadded and \\lyxdeleted in the LaTeX preamble."));
+ } else if (!xcolorsoul) {
+ Alert::warning(_("Changes not shown in LaTeX output"),
+ _("Changes will not be highlighted in LaTeX output "
+ "when using pdflatex, because xcolor and soul are not installed.\n"
+ "Please install both packages or redefine "
+ "\\lyxadded and \\lyxdeleted in the LaTeX preamble."));
+ }
+ }
break;
case LFUN_CHANGE_NEXT:
case LFUN_ALL_CHANGES_ACCEPT:
// select complete document
- cursor_.reset(buffer_->inset());
+ cursor_.reset(buffer_.inset());
cursor_.selHandle(true);
- buffer_->text().cursorBottom(cursor_);
+ buffer_.text().cursorBottom(cursor_);
// accept everything in a single step to support atomic undo
- buffer_->text().acceptOrRejectChanges(cursor_, LyXText::ACCEPT);
+ buffer_.text().acceptOrRejectChanges(cursor_, Text::ACCEPT);
break;
case LFUN_ALL_CHANGES_REJECT:
// select complete document
- cursor_.reset(buffer_->inset());
+ cursor_.reset(buffer_.inset());
cursor_.selHandle(true);
- buffer_->text().cursorBottom(cursor_);
+ buffer_.text().cursorBottom(cursor_);
// reject everything in a single step to support atomic undo
// Note: reject does not work recursively; the user may have to repeat the operation
- buffer_->text().acceptOrRejectChanges(cursor_, LyXText::REJECT);
+ buffer_.text().acceptOrRejectChanges(cursor_, Text::REJECT);
break;
case LFUN_WORD_FIND:
find(this, cmd);
break;
- case LFUN_WORD_REPLACE:
- replace(this, cmd);
+ case LFUN_WORD_REPLACE: {
+ bool has_deleted = false;
+ if (cur.selection()) {
+ DocIterator beg = cur.selectionBegin();
+ DocIterator end = cur.selectionEnd();
+ if (beg.pit() == end.pit()) {
+ for (pos_type p = beg.pos() ; p < end.pos() ; ++p) {
+ if (cur.paragraph().isDeleted(p))
+ has_deleted = true;
+ }
+ }
+ }
+ replace(this, cmd, has_deleted);
break;
+ }
case LFUN_MARK_OFF:
cur.clearSelection();
Inset::BIBTEX_CODE);
if (inset) {
if (inset->addDatabase(to_utf8(cmd.argument())))
- buffer_->updateBibfilesCache();
+ buffer_.updateBibfilesCache();
}
break;
}
Inset::BIBTEX_CODE);
if (inset) {
if (inset->delDatabase(to_utf8(cmd.argument())))
- buffer_->updateBibfilesCache();
+ buffer_.updateBibfilesCache();
}
break;
}
from = cur.selectionBegin();
to = cur.selectionEnd();
} else {
- from = doc_iterator_begin(buffer_->inset());
- to = doc_iterator_end(buffer_->inset());
+ from = doc_iterator_begin(buffer_.inset());
+ to = doc_iterator_end(buffer_.inset());
}
int const count = countWords(from, to);
docstring message;
case LFUN_BUFFER_TOGGLE_COMPRESSION:
// turn compression on/off
- buffer_->params().compressed = !buffer_->params().compressed;
+ buffer_.params().compressed = !buffer_.params().compressed;
break;
case LFUN_NEXT_INSET_TOGGLE: {
docstring const BufferView::requestSelection()
{
- if (!buffer_)
- return docstring();
-
Cursor & cur = cursor_;
if (!cur.selection()) {
void BufferView::clearSelection()
{
- if (buffer_) {
- cursor_.clearSelection();
- // Clear the selection buffer. Otherwise a subsequent
- // middle-mouse-button paste would use the selection buffer,
- // not the more current external selection.
- cap::clearSelection();
- xsel_cache_.set = false;
- // The buffer did not really change, but this causes the
- // redraw we need because we cleared the selection above.
- buffer_->changed();
- }
+ cursor_.clearSelection();
+ // Clear the selection buffer. Otherwise a subsequent
+ // middle-mouse-button paste would use the selection buffer,
+ // not the more current external selection.
+ cap::clearSelection();
+ xsel_cache_.set = false;
+ // The buffer did not really change, but this causes the
+ // redraw we need because we cleared the selection above.
+ buffer_.changed();
}
-void BufferView::workAreaResize(int width, int height)
+void BufferView::resize(int width, int height)
{
// Update from work area
width_ = width;
height_ = height;
- // The complete text metrics will be redone.
- text_metrics_.clear();
-
- if (buffer_)
- resize();
+ updateMetrics(false);
}
-Inset const * BufferView::getCoveringInset(LyXText const & text, int x, int y)
+Inset const * BufferView::getCoveringInset(Text const & text, int x, int y)
{
- pit_type pit = text.getPitNearY(*this, y);
+ pit_type pit = text_metrics_[&text].getPitNearY(y);
BOOST_ASSERT(pit != -1);
Paragraph const & par = text.getPar(pit);
Inset * const inset = iit->inset;
if (inset->covers(*this, x, y)) {
if (!inset->descendable())
- // No need to go further down if the inset is not
+ // No need to go further down if the inset is not
// descendable.
return inset;
size_t cell_number = inset->nargs();
// Check all the inner cell.
for (size_t i = 0; i != cell_number; ++i) {
- LyXText const * inner_text = inset->getText(i);
+ Text const * inner_text = inset->getText(i);
if (inner_text) {
// Try deeper.
- Inset const * inset_deeper =
+ Inset const * inset_deeper =
getCoveringInset(*inner_text, x, y);
if (inset_deeper)
return inset_deeper;
// LFUN_FILE_OPEN generated by drag-and-drop.
FuncRequest cmd = cmd0;
- // E.g. Qt mouse press when no buffer
- if (!buffer_)
- return false;
-
Cursor cur(*this);
- cur.push(buffer_->inset());
+ cur.push(buffer_.inset());
cur.selection() = cursor_.selection();
// Either the inset under the cursor or the
- // surrounding LyXText will handle this event.
+ // surrounding Text will handle this event.
// make sure we stay within the screen...
cmd.y = min(max(cmd.y, -1), height_);
-
+
if (cmd.action == LFUN_MOUSE_MOTION && cmd.button() == mouse_button::none) {
-
+
// Get inset under mouse, if there is one.
- Inset const * covering_inset =
- getCoveringInset(buffer_->text(), cmd.x, cmd.y);
+ Inset const * covering_inset =
+ getCoveringInset(buffer_.text(), cmd.x, cmd.y);
if (covering_inset == last_inset_)
// Same inset, no need to do anything...
return false;
// not expose the button for redraw. We adjust here the metrics dimension
// to enable a full redraw.
// FIXME: It is possible to redraw only the area around the button!
- if (need_redraw
+ if (need_redraw
&& metrics_info_.update_strategy == SingleParUpdate) {
- // FIXME: It should be possible to redraw only the area around
+ // FIXME: It should be possible to redraw only the area around
// the button by doing this:
//
//metrics_info_.singlepar = false;
//metrics_info_.y1 = ymin of button;
//metrics_info_.y2 = ymax of button;
//
- // Unfortunately, rowpainter.cpp:paintText() does not distinguish
+ // Unfortunately, BufferView::draw() does not distinguish
// between background updates and text updates. So we use the hammer
// solution for now. We could also avoid the updateMetrics() below
// by using the first and last pit of the CoordCache. Have a look
- // at LyXText::getPitNearY() to see what I mean.
+ // at Text::getPitNearY() to see what I mean.
//
//metrics_info_.pit1 = first pit of CoordCache;
//metrics_info_.pit2 = last pit of CoordCache;
// This should be changed if it is further utilized.
return need_redraw;
}
-
+
// Build temporary cursor.
- Inset * inset = buffer_->text().editXY(cur, cmd.x, cmd.y);
+ Inset * inset = text_metrics_[&buffer_.text()].editXY(cur, cmd.x, cmd.y);
// Put anchor at the same position.
cur.resetAnchor();
if (!cur.result().dispatched())
cur.dispatch(cmd);
+ //Do we have a selection?
+ theSelection().haveSelection(cursor().selection());
+
// Redraw if requested and necessary.
if (cur.result().dispatched() && cur.result().update())
return update(cur.result().update());
void BufferView::scroll(int /*lines*/)
{
-// if (!buffer_)
-// return;
-//
-// LyXText const * t = &buffer_->text();
+// Text const * t = buffer_.text();
// int const line_height = defaultRowHeight();
//
// // The new absolute coordinate
int tmpid = -1;
int tmppos = -1;
- buffer_->texrow().getIdFromRow(row, tmpid, tmppos);
+ buffer_.texrow().getIdFromRow(row, tmpid, tmppos);
+ cursor_.reset(buffer_.inset());
if (tmpid == -1)
- buffer_->text().setCursor(cursor_, 0, 0);
+ buffer_.text().setCursor(cursor_, 0, 0);
else
- buffer_->text().setCursor(cursor_, buffer_->getParFromID(tmpid).pit(), tmppos);
+ buffer_.text().setCursor(cursor_, buffer_.getParFromID(tmpid).pit(), tmppos);
}
void BufferView::gotoLabel(docstring const & label)
{
- for (InsetIterator it = inset_iterator_begin(buffer_->inset()); it; ++it) {
+ for (InsetIterator it = inset_iterator_begin(buffer_.inset()); it; ++it) {
vector<docstring> labels;
- it->getLabelList(*buffer_, labels);
+ it->getLabelList(buffer_, labels);
if (std::find(labels.begin(), labels.end(), label) != labels.end()) {
setCursor(it);
update();
}
-TextMetrics const & BufferView::textMetrics(LyXText const * t) const
+TextMetrics const & BufferView::textMetrics(Text const * t) const
{
return const_cast<BufferView *>(this)->textMetrics(t);
}
-TextMetrics & BufferView::textMetrics(LyXText const * t)
+TextMetrics & BufferView::textMetrics(Text const * t)
{
TextMetricsCache::iterator tmc_it = text_metrics_.find(t);
if (tmc_it == text_metrics_.end()) {
tmc_it = text_metrics_.insert(
- make_pair(t, TextMetrics(this, const_cast<LyXText *>(t)))).first;
- }
+ make_pair(t, TextMetrics(this, const_cast<Text *>(t)))).first;
+ }
return tmc_it->second;
}
-ParagraphMetrics const & BufferView::parMetrics(LyXText const * t,
+ParagraphMetrics const & BufferView::parMetrics(Text const * t,
pit_type pit) const
{
return textMetrics(t).parMetrics(pit);
if (need_anchor_change)
cur.resetAnchor();
-
+
if (!changed)
return false;
- updateLabels(*buffer_);
+ updateLabels(buffer_);
updateMetrics(false);
- buffer_->changed();
+ buffer_.changed();
return true;
}
{
BOOST_ASSERT(&cur.bv() == this);
+ // this event will clear selection so we save selection for
+ // persistent selection
+ cap::saveSelection(cursor());
+
// Has the cursor just left the inset?
bool badcursor = false;
bool leftinset = (&cursor_.inset() != &cur.inset());
if (leftinset)
- badcursor = cursor_.inset().notifyCursorLeaves(cursor_);
+ badcursor = notifyCursorLeaves(cursor_, cur);
// do the dEPM magic if needed
// FIXME: (1) move this to InsetText::notifyCursorLeaves?
// position is in the nucleus of the inset, notifyCursorLeaves
// will kill the script inset itself. So we check all the
// elements of the cursor to make sure that they are correct.
- // For an example, see bug 2933:
- // http://bugzilla.lyx.org/show_bug.cgi?id=2933
+ // For an example, see bug 2933:
+ // http://bugzilla.lyx.org/show_bug.cgi?id=2933
// The code below could maybe be moved to a DocIterator method.
//lyxerr << "cur before " << cur <<std::endl;
DocIterator dit(cur.inset());
//lyxerr << "5 cur after" << dit <<std::endl;
cursor_.setCursor(dit);
+ cursor_.boundary(cur.boundary());
cursor_.clearSelection();
finishUndo();
return update;
cursor_.setSelection(cursor_, -length);
} else
cursor_.setSelection(cursor_, length);
- cap::saveSelection(cursor_);
}
}
// FIXME: We should split-up updateMetrics() for the singlepar case.
void BufferView::updateMetrics(bool singlepar)
{
- LyXText & buftext = buffer_->text();
- TextMetrics & tm = textMetrics(&buftext);
+ Text & buftext = buffer_.text();
pit_type size = int(buftext.paragraphs().size());
if (anchor_ref_ > int(buftext.paragraphs().size() - 1)) {
anchor_ref_ = int(buftext.paragraphs().size() - 1);
offset_ref_ = 0;
}
+
+ if (!singlepar) {
+ // Clear out the position cache in case of full screen redraw,
+ coord_cache_.clear();
+ // Clear out paragraph metrics to avoid having invalid metrics
+ // in the cache from paragraphs not relayouted below
+ // The complete text metrics will be redone.
+ text_metrics_.clear();
+ }
+
+ TextMetrics & tm = textMetrics(&buftext);
+
// If the paragraph metrics has changed, we can not
// use the singlepar optimisation.
if (singlepar
// Rebreak anchor paragraph.
if (!singlepar)
tm.redoParagraph(pit);
-
- // Clear out the position cache in case of full screen redraw.
- if (!singlepar)
- coord_cache_.clear();
+
+ updateOffsetRef();
int y0 = tm.parMetrics(pit).ascent() - offset_ref_;
<< "size: " << size
<< endl;
- metrics_info_ = ViewMetricsInfo(pit1, pit2, y1, y2,
+ metrics_info_ = ViewMetricsInfo(pit1, pit2, y1, y2,
singlepar? SingleParUpdate: FullScreenUpdate, size);
if (lyxerr.debugging(Debug::WORKAREA)) {
// Launch a file browser
// FIXME UNICODE
string initpath = lyxrc.document_path;
-
- if (buffer_) {
- string const trypath = buffer_->filePath();
- // If directory is writeable, use this as default.
- if (isDirWriteable(FileName(trypath)))
- initpath = trypath;
- }
+ string const trypath = buffer_.filePath();
+ // If directory is writeable, use this as default.
+ if (isDirWriteable(FileName(trypath)))
+ initpath = trypath;
// FIXME UNICODE
FileDialog fileDlg(_("Select LyX document to insert"),
LFUN_FILE_INSERT,
make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
- make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
+ make_pair(_("Examples|#E#e"),
+ from_utf8(addPath(package().system_support().absFilename(),
+ "examples"))));
FileDialog::Result result =
fileDlg.open(from_utf8(initpath),
docstring res;
Buffer buf("", false);
if (lyx::loadLyXFile(&buf, FileName(filename))) {
- ErrorList & el = buffer_->errorList("Parse");
+ ErrorList & el = buffer_.errorList("Parse");
// Copy the inserted document error list into the current buffer one.
el = buf.errorList("Parse");
recordUndo(cursor_);
cap::pasteParagraphList(cursor_, buf.paragraphs(),
- buf.params().textclass, el);
+ buf.params().getTextClass_ptr(), el);
res = _("Document %1$s inserted.");
} else
res = _("Could not insert document %1$s");
// emit message signal.
message(bformat(res, disp_fn));
- buffer_->errors("Parse");
- resize();
+ buffer_.errors("Parse");
+ updateMetrics(false);
+}
+
+
+void BufferView::draw(frontend::Painter & pain)
+{
+ Text & text = buffer_.text();
+ bool const select = cursor_.selection();
+
+ PainterInfo pi(this, pain);
+ // Should the whole screen, including insets, be refreshed?
+ // FIXME: We should also distinguish DecorationUpdate to avoid text
+ // drawing if possible. This is not possible to do easily right now
+ // because of the single backing pixmap.
+ pi.full_repaint = select
+ || metrics_info_.update_strategy != SingleParUpdate;
+
+ if (pi.full_repaint)
+ // Clear background (if not delegated to rows)
+ pain.fillRectangle(0, metrics_info_.y1, width_,
+ metrics_info_.y2 - metrics_info_.y1,
+ buffer_.inset().backgroundColor());
+
+ TextMetrics const & tm = text_metrics_[&text];
+
+ if (select)
+ tm.drawSelection(pi, 0, 0);
+
+ int yy = metrics_info_.y1;
+ // draw contents
+ LYXERR(Debug::PAINTING) << "\t\t*** START DRAWING ***" << endl;
+ for (pit_type pit = metrics_info_.p1; pit <= metrics_info_.p2; ++pit) {
+ ParagraphMetrics const & pm = tm.parMetrics(pit);
+ yy += pm.ascent();
+ tm.drawParagraph(pi, pit, 0, yy);
+ yy += pm.descent();
+ }
+ LYXERR(Debug::PAINTING) << "\n\t\t*** END DRAWING ***" << endl;
+
+ // and grey out above (should not happen later)
+// lyxerr << "par ascent: " << text.getPar(metrics_info_.p1).ascent() << endl;
+ if (metrics_info_.y1 > 0
+ && metrics_info_.update_strategy == FullScreenUpdate)
+ pain.fillRectangle(0, 0, width_, metrics_info_.y1, Color::bottomarea);
+
+ // and possibly grey out below
+// lyxerr << "par descent: " << text.getPar(metrics_info_.p1).ascent() << endl;
+ if (metrics_info_.y2 < height_
+ && metrics_info_.update_strategy == FullScreenUpdate)
+ pain.fillRectangle(0, metrics_info_.y2, width_,
+ height_ - metrics_info_.y2, Color::bottomarea);
}
} // namespace lyx