lyx_mirror/src/insets/insettext.C

516 lines
11 KiB
C++
Raw Normal View History

/**
* \file insettext.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author J<EFBFBD>rgen Vigna
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "insettext.h"
#include "insetnewline.h"
#include "buffer.h"
#include "bufferparams.h"
#include "BufferView.h"
#include "CutAndPaste.h"
#include "cursor.h"
#include "debug.h"
#include "dispatchresult.h"
#include "errorlist.h"
#include "funcrequest.h"
#include "gettext.h"
#include "intl.h"
#include "LColor.h"
#include "lyxfind.h"
#include "lyxlex.h"
#include "lyxrc.h"
#include "lyxtext.h"
#include "metricsinfo.h"
#include "output_docbook.h"
#include "output_latex.h"
#include "output_linuxdoc.h"
#include "output_plaintext.h"
#include "paragraph.h"
#include "paragraph_funcs.h"
#include "ParagraphParameters.h"
#include "rowpainter.h"
#include "lyxrow.h"
#include "sgml.h"
#include "texrow.h"
#include "undo.h"
#include "frontends/Alert.h"
#include "frontends/font_metrics.h"
#include "frontends/LyXView.h"
#include "frontends/Painter.h"
#include "support/lyxalgo.h" // lyx::count
#include <boost/bind.hpp>
#include <boost/current_function.hpp>
using lyx::pos_type;
using lyx::graphics::PreviewLoader;
using lyx::support::isStrUnsignedInt;
using boost::bind;
using boost::ref;
using std::endl;
using std::for_each;
using std::max;
using std::string;
using std::auto_ptr;
using std::ostream;
using std::vector;
int InsetText::border_ = 2;
InsetText::InsetText(BufferParams const & bp)
: drawFrame_(false), frame_color_(LColor::insetframe), text_(0)
{
paragraphs().push_back(Paragraph());
paragraphs().back().layout(bp.getLyXTextClass().defaultLayout());
if (bp.tracking_changes)
paragraphs().back().trackChanges();
init();
}
InsetText::InsetText(InsetText const & in)
: UpdatableInset(in), text_(in.text_.bv_owner)
{
text_.autoBreakRows_ = in.text_.autoBreakRows_;
drawFrame_ = in.drawFrame_;
frame_color_ = in.frame_color_;
text_.paragraphs() = in.text_.paragraphs();
init();
}
InsetText::InsetText()
: text_(0)
{}
void InsetText::init()
{
for_each(paragraphs().begin(), paragraphs().end(),
bind(&Paragraph::setInsetOwner, _1, this));
old_pit = -1;
}
void InsetText::clear(bool just_mark_erased)
{
ParagraphList & pars = paragraphs();
if (just_mark_erased) {
for_each(pars.begin(), pars.end(),
bind(&Paragraph::markErased, _1));
return;
}
// This is a gross hack...
LyXLayout_ptr old_layout = pars.begin()->layout();
pars.clear();
pars.push_back(Paragraph());
pars.begin()->setInsetOwner(this);
pars.begin()->layout(old_layout);
}
auto_ptr<InsetBase> InsetText::doClone() const
{
return auto_ptr<InsetBase>(new InsetText(*this));
}
void InsetText::write(Buffer const & buf, ostream & os) const
{
os << "Text\n";
text_.write(buf, os);
}
void InsetText::read(Buffer const & buf, LyXLex & lex)
{
clear(false);
#ifdef WITH_WARNINGS
#warning John, look here. Doesnt make much sense.
#endif
if (buf.params().tracking_changes)
paragraphs().begin()->trackChanges();
// delete the initial paragraph
Paragraph oldpar = *paragraphs().begin();
paragraphs().clear();
bool res = text_.read(buf, lex);
init();
if (!res) {
lex.printError("Missing \\end_inset at this point. "
"Read: `$$Token'");
}
// sanity check
// ensure we have at least one paragraph.
if (paragraphs().empty())
paragraphs().push_back(oldpar);
}
void InsetText::metrics(MetricsInfo & mi, Dimension & dim) const
{
//lyxerr << "InsetText::metrics: width: " << mi.base.textwidth << endl;
setViewCache(mi.base.bv);
mi.base.textwidth -= 2 * border_;
font_ = mi.base.font;
text_.font_ = mi.base.font;
text_.metrics(mi, dim);
dim.asc += border_;
dim.des += border_;
dim.wid += 2 * border_;
mi.base.textwidth += 2 * border_;
dim_ = dim;
}
void InsetText::draw(PainterInfo & pi, int x, int y) const
{
BOOST_ASSERT(!text_.paragraphs().front().rows().empty());
// update our idea of where we are
setPosCache(pi, x, y);
BufferView * bv = pi.base.bv;
bv->hideCursor();
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
x += scroll();
text_.draw(pi, x + border_, y);
if (drawFrame_)
drawFrame(pi.pain, x, y);
}
void InsetText::drawSelection(PainterInfo & pi, int x, int y) const
{
// repaint the background if needed
if (backgroundColor() != LColor::background)
clearInset(pi.pain, x, y);
text_.drawSelection(pi, x, y);
}
void InsetText::drawFrame(Painter & pain, int x, int y) const
{
int const w = text_.width() + 2 * border_;
int const a = text_.ascent() + border_;
int const h = a + text_.descent() + border_;
pain.rectangle(x, y - a, w, h, frameColor());
}
void InsetText::clearInset(Painter & pain, int x, int y) const
{
int const w = text_.width() + 2 * border_;
int const a = text_.ascent() + border_;
int const h = a + text_.descent() + border_;
pain.fillRectangle(x, y - a, w, h, backgroundColor());
}
void InsetText::updateLocal(LCursor & cur)
{
if (!text_.autoBreakRows_ && paragraphs().size() > 1) {
// collapse paragraphs
while (paragraphs().size() > 1) {
ParagraphList::iterator const first = paragraphs().begin();
ParagraphList::iterator second = first;
++second;
size_t const first_par_size = first->size();
if (!first->empty() &&
!second->empty() &&
!first->isSeparator(first_par_size - 1)) {
first->insertChar(first_par_size, ' ');
}
cur.clearSelection();
mergeParagraph(cur.buffer().params(), paragraphs(), 0);
}
}
if (!cur.selection())
cur.resetAnchor();
LyXView * lv = cur.bv().owner();
lv->view_state_changed();
lv->updateMenubar();
lv->updateToolbars();
if (old_pit != cur.pit()) {
lv->setLayout(text_.getPar(cur.pit()).layout()->name());
old_pit = cur.pit();
}
}
string const InsetText::editMessage() const
{
return _("Opened Text Inset");
}
void InsetText::edit(LCursor & cur, bool left)
{
//lyxerr << "InsetText: edit left/right" << endl;
old_pit = -1;
setViewCache(&cur.bv());
int const pit = left ? 0 : paragraphs().size() - 1;
int const pos = left ? 0 : paragraphs().back().size();
text_.setCursor(cur.top(), pit, pos);
cur.clearSelection();
finishUndo();
#ifdef WITH_WARNINGS
#warning can someone check if/when this is needed?
#endif
//Andre?
// updateLocal(cur);
}
InsetBase * InsetText::editXY(LCursor & cur, int x, int y) const
{
old_pit = -1;
return text_.editXY(cur, x, y);
//sanitizeEmptyText(cur.bv());
//updateLocal(cur);
}
void InsetText::doDispatch(LCursor & cur, FuncRequest & cmd)
{
lyxerr[Debug::DEBUG]
<< BOOST_CURRENT_FUNCTION
<< " [ cmd.action = " << cmd.action << ']'
<< endl;
setViewCache(&cur.bv());
text_.dispatch(cur, cmd);
}
bool InsetText::getStatus(LCursor & cur, FuncRequest const & cmd,
FuncStatus & status) const
{
return text_.getStatus(cur, cmd, status);
}
int InsetText::latex(Buffer const & buf, ostream & os,
OutputParams const & runparams) const
{
TexRow texrow;
latexParagraphs(buf, paragraphs(), os, texrow, runparams);
return texrow.rows();
}
int InsetText::plaintext(Buffer const & buf, ostream & os,
OutputParams const & runparams) const
{
ParagraphList::const_iterator beg = paragraphs().begin();
ParagraphList::const_iterator end = paragraphs().end();
ParagraphList::const_iterator it = beg;
for (; it != end; ++it)
asciiParagraph(buf, *it, os, runparams, it == beg);
// FIXME: Give the total numbers of lines
return 0;
}
int InsetText::linuxdoc(Buffer const & buf, ostream & os,
OutputParams const & runparams) const
{
linuxdocParagraphs(buf, paragraphs(), os, runparams);
return 0;
}
int InsetText::docbook(Buffer const & buf, ostream & os,
OutputParams const & runparams) const
{
docbookParagraphs(paragraphs(), buf, os, runparams);
return 0;
}
void InsetText::validate(LaTeXFeatures & features) const
{
for_each(paragraphs().begin(), paragraphs().end(),
bind(&Paragraph::validate, _1, ref(features)));
}
void InsetText::getCursorPos(CursorSlice const & sl, int & x, int & y) const
{
x = text_.cursorX(sl) + border_;
y = text_.cursorY(sl);
}
bool InsetText::showInsetDialog(BufferView *) const
{
return false;
}
void InsetText::getLabelList(Buffer const & buffer,
std::vector<string> & list) const
{
ParagraphList::const_iterator pit = paragraphs().begin();
ParagraphList::const_iterator pend = paragraphs().end();
for (; pit != pend; ++pit) {
InsetList::const_iterator beg = pit->insetlist.begin();
InsetList::const_iterator end = pit->insetlist.end();
for (; beg != end; ++beg)
beg->inset->getLabelList(buffer, list);
}
}
void InsetText::markNew(bool track_changes)
{
ParagraphList::iterator pit = paragraphs().begin();
ParagraphList::iterator end = paragraphs().end();
for (; pit != end; ++pit) {
if (track_changes) {
pit->trackChanges();
} else {
// no-op when not tracking
pit->cleanChanges();
}
}
}
void InsetText::setText(string const & data, LyXFont const & font)
{
clear(false);
Paragraph & first = paragraphs().front();
for (unsigned int i = 0; i < data.length(); ++i)
first.insertChar(i, data[i], font);
}
void InsetText::setAutoBreakRows(bool flag)
{
if (flag != text_.autoBreakRows_) {
text_.autoBreakRows_ = flag;
if (!flag)
removeNewlines();
}
}
void InsetText::setDrawFrame(bool flag)
{
drawFrame_ = flag;
}
LColor_color InsetText::frameColor() const
{
return LColor::color(frame_color_);
}
void InsetText::setFrameColor(LColor_color col)
{
frame_color_ = col;
}
void InsetText::setViewCache(BufferView const * bv) const
{
if (bv && bv != text_.bv_owner) {
//lyxerr << "setting view cache from "
// << text_.bv_owner << " to " << bv << "\n";
text_.bv_owner = const_cast<BufferView *>(bv);
}
}
void InsetText::removeNewlines()
{
ParagraphList::iterator it = paragraphs().begin();
ParagraphList::iterator end = paragraphs().end();
for (; it != end; ++it)
for (int i = 0; i < it->size(); ++i)
if (it->isNewline(i))
it->erase(i);
}
LyXText * InsetText::getText(int i) const
{
return (i == 0) ? const_cast<LyXText*>(&text_) : 0;
}
void InsetText::appendParagraphs(Buffer * buffer, ParagraphList & plist)
{
#ifdef WITH_WARNINGS
#warning FIXME Check if Changes stuff needs changing here. (Lgb)
// And it probably does. You have to take a look at this John. (Lgb)
#warning John, have a look here. (Lgb)
#endif
ParagraphList & pl = paragraphs();
ParagraphList::iterator pit = plist.begin();
ParagraphList::iterator ins = pl.insert(pl.end(), *pit);
++pit;
mergeParagraph(buffer->params(), pl, ins - pl.begin() - 1);
for_each(pit, plist.end(),
bind(&ParagraphList::push_back, ref(pl), _1));
}
void InsetText::addPreview(PreviewLoader & loader) const
{
ParagraphList::const_iterator pit = paragraphs().begin();
ParagraphList::const_iterator pend = paragraphs().end();
for (; pit != pend; ++pit) {
InsetList::const_iterator it = pit->insetlist.begin();
InsetList::const_iterator end = pit->insetlist.end();
for (; it != end; ++it)
it->inset->addPreview(loader);
}
}
ParagraphList const & InsetText::paragraphs() const
{
return text_.paragraphs();
}
ParagraphList & InsetText::paragraphs()
{
return text_.paragraphs();
}