-/* This file is part of
- * ======================================================
+/**
+ * \file text2.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
*
- * LyX, The Document Processor
+ * \author Asger Alstrup
+ * \author Lars Gullik Bjønnes
+ * \author Alfredo Braunstein
+ * \author Jean-Marc Lasgouttes
+ * \author Angus Leeming
+ * \author John Levon
+ * \author André Pönitz
+ * \author Allan Rae
+ * \author Dekel Tsur
+ * \author Jürgen Vigna
*
- * Copyright 1995 Matthias Ettrich
- * Copyright 1995-2001 The LyX Team.
- *
- * ====================================================== */
+ * Full author contact details are available in file CREDITS.
+ */
#include <config.h>
#include "frontends/font_metrics.h"
#include "debug.h"
#include "lyxrc.h"
+#include "Floating.h"
#include "FloatList.h"
#include "language.h"
#include "ParagraphParameters.h"
using lyx::pos_type;
-LyXText::LyXText(BufferView * bv)
+LyXText::LyXText(BufferView * bv, InsetText * inset, bool ininset,
+ ParagraphList & paragraphs)
: height(0), width(0), anchor_y_(0),
- inset_owner(0), the_locking_inset(0), bv_owner(bv)
-{}
-
-
-LyXText::LyXText(BufferView * bv, InsetText * inset)
- : height(0), width(0), anchor_y_(0),
- inset_owner(inset), the_locking_inset(0), bv_owner(bv)
-{}
+ inset_owner(inset), the_locking_inset(0), bv_owner(bv),
+ in_inset_(ininset), paragraphs_(paragraphs)
+{
+}
void LyXText::init(BufferView * bview)
else
inset->open(bv());
- bv()->updateInset();
+ bv()->updateInset(inset);
}
}
-// rebreaks all paragraphs between the specified pars
-// This function is needed after SetLayout and SetFont etc.
-void LyXText::redoParagraphs(ParagraphList::iterator start,
- ParagraphList::iterator end)
-{
- for ( ; start != end; ++start)
- redoParagraph(start);
-}
-
-
-void LyXText::redoParagraph(ParagraphList::iterator pit)
+int LyXText::redoParagraphInternal(ParagraphList::iterator pit)
{
RowList::iterator rit = pit->rows.begin();
RowList::iterator end = pit->rows.end();
- // remove rows of paragraph
+ // remove rows of paragraph, keep track of height changes
for (int i = 0; rit != end; ++rit, ++i)
height -= rit->height();
-
pit->rows.clear();
+ // redo insets
+ InsetList::iterator ii = pit->insetlist.begin();
+ InsetList::iterator iend = pit->insetlist.end();
+ for (; ii != iend; ++ii) {
+ Dimension dim;
+ MetricsInfo mi(bv(), getFont(pit, ii->pos), workWidth());
+ ii->inset->metrics(mi, dim);
+ }
+
// rebreak the paragraph
- // insert a new row, starting at position 0
+ for (pos_type z = 0; z < pit->size() + 1; ) {
+ Row row(z);
+ z = rowBreakPoint(pit, row) + 1;
+ row.end(z);
+ pit->rows.push_back(row);
+ }
- pos_type z = 0;
- pit->rows.push_back(Row(z));
- bool done = false;
- while (!done) {
- z = rowBreakPoint(pit, pit->rows.back());
+ int par_width = 0;
+ // set height and fill and width of rows
+ int const ww = workWidth();
+ for (rit = pit->rows.begin(); rit != end; ++rit) {
+ int const f = fill(pit, rit, ww);
+ int const w = ww - f;
+ par_width = std::max(par_width, w);
+ rit->fill(f);
+ rit->width(w);
+ prepareToPrint(pit, rit);
+ setHeightOfRow(pit, rit);
+ height += rit->height();
+ }
- RowList::iterator tmprow = boost::prior(pit->rows.end());
+ //lyxerr << "redoParagraph: " << pit->rows.size() << " rows\n";
+ return par_width;
+}
- if (z >= pit->size())
- done = true;
- else {
- ++z;
- pit->rows.push_back(Row(z));
- }
- tmprow->fill(fill(pit, tmprow, workWidth()));
- setHeightOfRow(pit, tmprow);
+int LyXText::redoParagraphs(ParagraphList::iterator start,
+ ParagraphList::iterator end)
+{
+ int pars_width = 0;
+ for ( ; start != end; ++start) {
+ int par_width = redoParagraphInternal(start);
+ pars_width = std::max(par_width, pars_width);
}
+ updateRowPositions();
+ return pars_width;
+}
- //lyxerr << "redoParagraph: " << pit->rows.size() << " rows\n";
+
+void LyXText::redoParagraph(ParagraphList::iterator pit)
+{
+ redoParagraphInternal(pit);
+ updateRowPositions();
}
void LyXText::metrics(MetricsInfo & mi, Dimension & dim)
{
- //lyxerr << "LyXText::metrics: width: " << mi.base.textwidth << endl;
+ //lyxerr << "LyXText::metrics: width: " << mi.base.textwidth
+ // << " workWidth: " << workWidth() << endl;
//Assert(mi.base.textwidth);
// rebuild row cache
- width = 0;
- height = 0;
+ width = 0;
+ ///height = 0;
//anchor_y_ = 0;
-
- ParagraphList::iterator pit = ownerParagraphs().begin();
- ParagraphList::iterator end = ownerParagraphs().end();
-
- for (; pit != end; ++pit) {
- pit->rows.clear();
-
- InsetList::iterator ii = pit->insetlist.begin();
- InsetList::iterator iend = pit->insetlist.end();
- for (; ii != iend; ++ii) {
- Dimension dim;
- MetricsInfo m = mi;
-#warning FIXME: pos != 0
- m.base.font = getFont(pit, 0);
- ii->inset->metrics(m, dim);
- }
-
- redoParagraph(pit);
- }
+ width = redoParagraphs(ownerParagraphs().begin(), ownerParagraphs().end());
// final dimension
dim.asc = firstRow()->ascent_of_text();
return;
RowList::iterator rit = cursorRow();
- RowList::iterator next_rit = boost::next(rit);
- RowList::iterator end = boost::next(rit);
ParagraphList::iterator pit = cursor.par();
- pos_type last_pos = lastPos(*pit, rit);
-
- if (next_rit == end) {
- ++last_pos;
- } else {
- if (pit->empty() ||
- (pit->getChar(last_pos) != ' ' && !pit->isNewline(last_pos))) {
- ++last_pos;
- }
- }
-
- setCursor(pit, last_pos);
+ pos_type pos = lastPos(*pit, rit);
+ /* cursor should be before a hard newline only */
+ if (!pit->isNewline(pos))
+ ++pos;
+ setCursor(pit, pos);
}
else if (selection.start.par() != selection.end.par())
bv()->owner()->message(_("Cannot index more than one paragraph!"));
else
- idxstring = selectionAsString(bv()->buffer(), false);
+ idxstring = selectionAsString(*bv()->buffer(), false);
// Reset cursors to their original position.
cursor = reset_cursor;
setSelection();
setCursor(tmpcursor.par(), tmpcursor.pos());
if (inset_owner)
- bv()->updateInset();
+ bv()->updateInset(inset_owner);
}
// set the counter of a paragraph. This includes the labels
-void LyXText::setCounter(Buffer const * buf, ParagraphList::iterator pit)
+void LyXText::setCounter(Buffer const & buf, ParagraphList::iterator pit)
{
- LyXTextClass const & textclass = buf->params.getLyXTextClass();
+ LyXTextClass const & textclass = buf.params.getLyXTextClass();
LyXLayout_ptr const & layout = pit->layout();
if (pit != ownerParagraphs().begin()) {
ostringstream s;
- if (i >= 0 && i <= buf->params.secnumdepth) {
+ if (i >= 0 && i <= buf.params.secnumdepth) {
string numbertype;
string langtype;
// Is there a label? Useful for Chapter layout
if (!pit->params().appendix()) {
- s << buf->B_(layout->labelstring());
+ s << buf.B_(layout->labelstring());
} else {
- s << buf->B_(layout->labelstring_appendix());
+ s << buf.B_(layout->labelstring_appendix());
}
// Use of an integer is here less than elegant. For now.
numbertype = "sectioning";
} else {
numbertype = "appendix";
- if (pit->isRightToLeftPar(buf->params))
+ if (pit->isRightToLeftPar(buf.params))
langtype = "hebrew";
else
langtype = "latin";
}
// In biblio should't be following counters but...
} else {
- string s = buf->B_(layout->labelstring());
+ string s = buf.B_(layout->labelstring());
// the caption hack:
if (layout->labeltype == LABEL_SENSITIVE) {
isOK = true;
break;
} else {
+ Paragraph const * owner = &ownerPar(buf, in);
tmppit = ownerParagraphs().begin();
for ( ; tmppit != end; ++tmppit)
- if (&*tmppit == in->parOwner())
+ if (&*tmppit == owner)
break;
}
}
textclass.counters().step(fl.type());
// Doesn't work... yet.
- s = bformat(_("%1$s #:"), buf->B_(fl.name()));
+ s = bformat(_("%1$s #:"), buf.B_(fl.name()));
} else {
// par->SetLayout(0);
// s = layout->labelstring;
pit->params().depth(maxdepth);
// setCounter can potentially change the labelString.
- setCounter(bv()->buffer(), pit);
+ setCounter(*bv()->buffer(), pit);
string const & newLabel = pit->params().labelString();
// The character will not be inserted a second time
insertChar(Paragraph::META_INSET);
// If we enter a highly editable inset the cursor should be before
- // the inset. After an Undo LyX tries to call inset->edit(...)
+ // the inset. After an Undo LyX tries to call inset->edit(...)
// and fails if the cursor is behind the inset and getInset
// does not return the inset!
if (isHighlyEditableInset(inset))
// finished. The solution used currently just works, to make it
// faster we need to be more clever and probably also have more
// calls to stuffClipboard. (Lgb)
- bv()->stuffClipboard(selectionAsString(bv()->buffer(), true));
+ bv()->stuffClipboard(selectionAsString(*bv()->buffer(), true));
// This doesn't make sense, if there is no selection
if (!selection.set())
void LyXText::copySelection()
{
// stuff the selection onto the X clipboard, from an explicit copy request
- bv()->stuffClipboard(selectionAsString(bv()->buffer(), true));
+ bv()->stuffClipboard(selectionAsString(*bv()->buffer(), true));
// this doesnt make sense, if there is no selection
if (!selection.set())
return;
// get the cursor y position in text
- int y = 0;
- RowList::iterator row = getRow(pit, pos, y);
- RowList::iterator old_row = row;
- // if we are before the first char of this row and are still in the
- // same paragraph and there is a previous row then put the cursor on
- // the end of the previous row
- cur.iy(y + row->baseline());
- if (row != pit->rows.begin()
- && pos
- && pos < pit->size()
- && pit->getChar(pos) == Paragraph::META_INSET) {
- InsetOld * ins = pit->getInset(pos);
- if (ins && (ins->needFullRow() || ins->display())) {
- --row;
- y -= row->height();
- }
- }
+
+ RowList::iterator row = getRow(pit, pos);
+ int y = row->y();
// y is now the beginning of the cursor row
y += row->baseline();
// y is now the cursor baseline
cur.y(y);
- pos_type last = lastPrintablePos(*pit, old_row);
+ pos_type last = lastPrintablePos(*pit, row);
// None of these should happen, but we're scaredy-cats
if (pos > pit->size()) {
float x = getCursorX(pit, row, pos, last, boundary);
cur.x(int(x));
cur.x_fix(cur.x());
- if (old_row != row) {
- x = getCursorX(pit, old_row, pos, last, boundary);
- cur.ix(int(x));
- } else
- cur.ix(cur.x());
-/* We take out this for the time being because 1) the redraw code is not
- prepared to this yet and 2) because some good policy has yet to be decided
- while editting: for instance how to act on rows being created/deleted
- because of DEPM.
-*/
-#if 0
- //if the cursor is in a visible row, anchor to it
- int topy = top_y();
- if (topy < y && y < topy + bv()->workHeight())
- anchor_row(row);
-#endif
}
float LyXText::getCursorX(ParagraphList::iterator pit, RowList::iterator rit,
pos_type pos, pos_type last, bool boundary) const
{
- pos_type cursor_vpos = 0;
- double x;
- double fill_separator;
- double fill_hfill;
- double fill_label_hfill;
- // This call HAS to be here because of the BidiTables!!!
- prepareToPrint(pit, rit, x, fill_separator, fill_hfill,
- fill_label_hfill);
-
- pos_type const rit_pos = rit->pos();
+ pos_type cursor_vpos = 0;
+ double x = rit->x();
+ double fill_separator = rit->fill_separator();
+ double fill_hfill = rit->fill_hfill();
+ double fill_label_hfill = rit->fill_label_hfill();
+ pos_type const rit_pos = rit->pos();
if (last < rit_pos)
cursor_vpos = rit_pos;
real_current_font = getFont(pit, pos);
if (cursor.pos() == pit->size() &&
- isBoundary(bv()->buffer(), *pit, cursor.pos()) &&
+ isBoundary(*bv()->buffer(), *pit, cursor.pos()) &&
!cursor.boundary()) {
Language const * lang =
pit->getParLanguage(bv()->buffer()->params);
pos_type LyXText::getColumnNearX(ParagraphList::iterator pit,
RowList::iterator rit, int & x, bool & boundary) const
{
- double tmpx = 0;
- double fill_separator;
- double fill_hfill;
- double fill_label_hfill;
-
- prepareToPrint(pit, rit, tmpx, fill_separator, fill_hfill, fill_label_hfill);
+ double tmpx = rit->x();
+ double fill_separator = rit->fill_separator();
+ double fill_hfill = rit->fill_hfill();
+ double fill_label_hfill = rit->fill_label_hfill();
pos_type vc = rit->pos();
pos_type last = lastPrintablePos(*pit, rit);
bool const rtl = (bidi_level(c) % 2 == 1);
if (left_side == rtl) {
++c;
- boundary = isBoundary(bv()->buffer(), *pit, c);
+ boundary = isBoundary(*bv()->buffer(), *pit, c);
}
}
void LyXText::setCursorFromCoordinates(int x, int y)
{
- //LyXCursor old_cursor = cursor;
+ LyXCursor old_cursor = cursor;
setCursorFromCoordinates(cursor, x, y);
setCurrentFont();
-#warning DEPM disabled, otherwise crash when entering new table
- //deleteEmptyParagraphMechanism(old_cursor);
-}
-
-
-namespace {
-
- /**
- * return true if the cursor given is at the end of a row,
- * and the next row is filled by an inset that spans an entire
- * row.
- */
- bool beforeFullRowInset(LyXText & lt, LyXCursor const & cur)
- {
- RowList::iterator row = lt.getRow(cur);
- RowList::iterator next = boost::next(row);
-
- if (next == cur.par()->rows.end() || next->pos() != cur.pos())
- return false;
-
- if (cur.pos() == cur.par()->size() || !cur.par()->isInset(cur.pos()))
- return false;
-
- InsetOld const * inset = cur.par()->getInset(cur.pos());
- if (inset->needFullRow() || inset->display())
- return true;
-
- return false;
- }
+ deleteEmptyParagraphMechanism(old_cursor);
}
{
// Get the row first.
ParagraphList::iterator pit;
- RowList::iterator row = getRowNearY(y, pit);
+ RowList::iterator rit = getRowNearY(y, pit);
+ y = rit->y();
+
bool bound = false;
- pos_type const column = getColumnNearX(pit, row, x, bound);
+ pos_type const column = getColumnNearX(pit, rit, x, bound);
cur.par(pit);
- cur.pos(row->pos() + column);
+ cur.pos(rit->pos() + column);
cur.x(x);
- cur.y(y + row->baseline());
-
-// if (beforeFullRowInset(*this, cur)) {
-// pos_type const last = lastPrintablePos(*this, pit, row);
-// RowList::iterator next_row = nextRow(row);
-// cur.ix(int(getCursorX(pit, next_row, cur.pos(), last, bound)));
-// cur.iy(y + row->height() + next_row->baseline());
-// } else {
- cur.iy(cur.y());
- cur.ix(cur.x());
-// }
+ cur.y(y + rit->baseline());
+
cur.boundary(bound);
}
bool boundary = cursor.boundary();
setCursor(cursor.par(), cursor.pos() - 1, true, false);
if (!internal && !boundary &&
- isBoundary(bv()->buffer(), *cursor.par(), cursor.pos() + 1))
+ isBoundary(*bv()->buffer(), *cursor.par(), cursor.pos() + 1))
setCursor(cursor.par(), cursor.pos() + 1, true, true);
} else if (cursor.par() != ownerParagraphs().begin()) {
// steps into the paragraph above
else if (!at_end) {
setCursor(cursor.par(), cursor.pos() + 1, true, false);
if (!internal &&
- isBoundary(bv()->buffer(), *cursor.par(), cursor.pos()))
+ isBoundary(*bv()->buffer(), *cursor.par(), cursor.pos()))
setCursor(cursor.par(), cursor.pos(), true, true);
} else if (boost::next(cursor.par()) != ownerParagraphs().end())
setCursor(boost::next(cursor.par()), 0);
int y = cursor.y() - cursorRow()->baseline() - 1;
setCursorFromCoordinates(x, y);
if (!selecting) {
- int topy = top_y();
- int y1 = cursor.iy() - topy;
+ int topy = bv_owner->top_y();
+ int y1 = cursor.y() - topy;
int y2 = y1;
y -= topy;
InsetOld * inset_hit = checkInsetHit(x, y1);
int y = cursor.y() - cursorRow()->baseline() + cursorRow()->height() + 1;
setCursorFromCoordinates(x, y);
if (!selecting && cursorRow() == cursorIRow()) {
- int topy = top_y();
- int y1 = cursor.iy() - topy;
+ int topy = bv_owner->top_y();
+ int y1 = cursor.y() - topy;
int y2 = y1;
y -= topy;
InsetOld * inset_hit = checkInsetHit(x, y1);
There are still some small problems that can lead to
double spaces stored in the document file or space at
the beginning of paragraphs. This happens if you have
- the cursor betwenn to spaces and then save. Or if you
+ the cursor between to spaces and then save. Or if you
cut and paste and the selection have a space at the
beginning and then save right after the paste. I am
sure none of these are very hard to fix, but I will
if (old_cursor.par()->empty() ||
(old_cursor.par()->size() == 1 &&
old_cursor.par()->isLineSeparator(0))) {
- // ok, we will delete anything
+ // ok, we will delete something
LyXCursor tmpcursor;
deleted = true;
ParagraphList::iterator endpit = boost::next(old_cursor.par());
while (endpit != ownerParagraphs().end() && endpit->getDepth())
++endpit;
-
+
recordUndo(bv(), Undo::DELETE, old_cursor.par(), boost::prior(endpit));
cursor = tmpcursor;
ParagraphList & LyXText::ownerParagraphs() const
{
- if (inset_owner) {
- return inset_owner->paragraphs;
- }
- return bv_owner->buffer()->paragraphs;
+ return paragraphs_;
}
bool LyXText::isInInset() const
{
// Sub-level has non-null bv owner and non-null inset owner.
- return inset_owner != 0 && bv_owner != 0;
+ return inset_owner != 0;
}