#include "frontends/alert.h"
#include "frontends/FileDialog.h"
#include "frontends/FontMetrics.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 {
}
-void BufferView::setBuffer(Buffer * b)
+Buffer * BufferView::setBuffer(Buffer * b)
{
LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION
<< "[ b = " << b << "]" << endl;
if (buffer_) {
+ // Save the current selection if any
+ cap::saveSelection(cursor_);
// 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.
// If we're quitting lyx, don't bother updating stuff
if (quitting) {
buffer_ = 0;
- return;
+ return 0;
}
+ //FIXME Fix for bug 3440 is here.
// 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
+ //FIXME 3440
+ // if (last_buffer_) buffer_ = last_buffer_;
+ // also check that this is in theBufferList()?
buffer_ = theBufferList().first();
} else {
+ //FIXME 3440
+ // last_buffer = buffer_;
// Set current buffer
buffer_ = b;
}
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_);
-}
-
+ if (!buffer_)
+ return 0;
-bool BufferView::loadLyXFile(FileName const & filename, bool tolastfiles)
-{
- // 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;
- }
+ LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION
+ << "Buffer addr: " << buffer_ << endl;
+ cursor_.push(buffer_->inset());
+ cursor_.resetAnchor();
+ buffer_->text().setCurrentFont(cursor_);
- Buffer * b = 0;
+ // Update the metrics now that we have a proper Cursor.
+ updateMetrics(false);
- 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;
- }
+ // FIXME: This code won't be needed once we switch to
+ // "one Buffer" / "one BufferView".
+ 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.
- setBuffer(b);
- // Send the "errors" signal in case of parsing errors
- b->errors("Parse");
+ // Make sure that the restored cursor is not broken. This can happen for
+ // example if this Buffer has been modified by another view.
+ cursor_.fixIfBroken();
- // 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 (fitCursor())
+ // Update the metrics if the cursor new position was off screen.
+ updateMetrics(false);
}
- if (tolastfiles)
- LyX::ref().session().lastFiles().add(FileName(b->fileName()));
-
- return true;
+ if (graphics::Previews::status() != LyXRC::PREVIEW_OFF)
+ graphics::Previews::get().generateBufferPreviews(*buffer_);
+ return buffer_;
}
LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION << endl;
updateMetrics(false);
- switchKeyMap();
}
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.
{
// 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()),
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.
+ // 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();
for (size_t i = 0; i < n; ++i)
if (dit[i].inset().editable() != Inset::HIGHLY_EDITABLE) {
}
}
// 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());
- }
+ DocIterator it = doc_iterator_begin(buffer_->inset());
+ it.pit() = bottom_pit;
+ it.pos() = min(bottom_pos, it.paragraph().size());
+ setCursor(it);
+ return boost::make_tuple(it.pit(), it.pos(),
+ it.paragraph().id());
}
// both methods fail
return boost::make_tuple(pit_type(0), pos_type(0), 0);
}
-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_.innerText()->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);
}
{
FuncStatus flag;
+ Cursor & cur = cursor_;
+
switch (cmd.action) {
case LFUN_UNDO:
case LFUN_FILE_INSERT_PLAINTEXT:
case LFUN_BOOKMARK_SAVE:
// FIXME: Actually, these LFUNS should be moved to Text
- flag.enabled(cursor_.inTexted());
+ 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;
}
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:
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_CHANGES_OUTPUT:
buffer_->params().outputChanges = !buffer_->params().outputChanges;
if (buffer_->params().outputChanges) {
- if (!LaTeXFeatures::isAvailable("dvipost")) {
+ 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 dvipost is not installed.\n"
- "If you are familiar with TeX, consider redefining "
- "\\lyxinserted and \\lyxdeleted in the LaTeX preamble."));
- } else {
+ _("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.\n"
- "If you are familiar with TeX, consider redefining "
- "\\lyxinserted and \\lyxdeleted in the LaTeX preamble."));
+ _("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;
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 * 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;
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;
// 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 =
+ Inset const * covering_inset =
getCoveringInset(buffer_->text(), cmd.x, cmd.y);
if (covering_inset == last_inset_)
// Same inset, no need to do anything...
// 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;
// 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);
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());
buffer_->texrow().getIdFromRow(row, tmpid, tmppos);
+ cursor_.reset(buffer_->inset());
if (tmpid == -1)
buffer_->text().setCursor(cursor_, 0, 0);
else
if (tmc_it == text_metrics_.end()) {
tmc_it = text_metrics_.insert(
make_pair(t, TextMetrics(this, const_cast<Text *>(t)))).first;
- }
+ }
return tmc_it->second;
}
if (need_anchor_change)
cur.resetAnchor();
-
+
if (!changed)
return false;
{
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_);
}
}
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
+ tm.clear();
+ }
+
// 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();
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)) {
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),