Real fix for bug 1395 by Stefan Schimanski, this commit replace the one done at revision 17836 which was reverted!

Locking counter added to MacroData: it is increased before drawing/
metric calculations and decreased afterwards in InsetMathMacro. If a  
macro is already locked at that point, "Self reference: \foo" is  
drawn instead of the macro definition to avoid endless loops.  
Moreover inside of the arguments of the macro the counter is  
temporarily decreased as those cases do not cause loops. (fixes bug  
#1395)

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@17841 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2007-04-17 16:52:43 +00:00
parent 86c1053f51
commit 49395dd85e
4 changed files with 139 additions and 44 deletions

View File

@ -33,6 +33,54 @@ using std::endl;
using std::vector;
/// This class is the value of a macro argument, technically
/// a wrapper of the cells of MathMacro.
class MathMacroArgumentValue : public InsetMathDim {
public:
///
MathMacroArgumentValue(MathArray const * value, docstring const & macroName)
: value_(value), macroName_(macroName) {}
///
bool metrics(MetricsInfo & mi, Dimension & dim) const;
///
void draw(PainterInfo &, int x, int y) const;
private:
std::auto_ptr<InsetBase> doClone() const;
MathArray const * value_;
docstring macroName_;
};
auto_ptr<InsetBase> MathMacroArgumentValue::doClone() const
{
return auto_ptr<InsetBase>(new MathMacroArgumentValue(*this));
}
bool MathMacroArgumentValue::metrics(MetricsInfo & mi, Dimension & dim) const
{
// unlock outer macro in arguments, and lock it again later
MacroTable::globalMacros().get(macroName_).unlock();
value_->metrics(mi, dim);
MacroTable::globalMacros().get(macroName_).lock();
metricsMarkers2(dim);
if (dim_ == dim)
return false;
dim_ = dim;
return true;
}
void MathMacroArgumentValue::draw(PainterInfo & pi, int x, int y) const
{
// unlock outer macro in arguments, and lock it again later
MacroTable::globalMacros().get(macroName_).unlock();
value_->draw(pi, x, y);
MacroTable::globalMacros().get(macroName_).lock();
}
MathMacro::MathMacro(docstring const & name, int numargs)
: InsetMathNest(numargs), name_(name)
{}
@ -63,25 +111,39 @@ bool MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
{
if (!MacroTable::globalMacros().has(name())) {
mathed_string_dim(mi.base.font, "Unknown: " + name(), dim);
} else if (editing(mi.base.bv)) {
// FIXME UNICODE
asArray(MacroTable::globalMacros().get(name()).def(), tmpl_);
LyXFont font = mi.base.font;
augmentFont(font, from_ascii("lyxtex"));
tmpl_.metrics(mi, dim);
// FIXME UNICODE
dim.wid += mathed_string_width(font, name()) + 10;
// FIXME UNICODE
int ww = mathed_string_width(font, from_ascii("#1: "));
for (idx_type i = 0; i < nargs(); ++i) {
MathArray const & c = cell(i);
c.metrics(mi);
dim.wid = max(dim.wid, c.width() + ww);
dim.des += c.height() + 10;
}
} else {
MacroTable::globalMacros().get(name()).expand(cells_, expanded_);
expanded_.metrics(mi, dim);
MacroData const & macro = MacroTable::globalMacros().get(name());
if (macro.locked()) {
mathed_string_dim(mi.base.font, "Self reference: " + name(), dim);
expanded_ = MathArray();
} else if (editing(mi.base.bv)) {
// FIXME UNICODE
asArray(macro.def(), tmpl_);
LyXFont font = mi.base.font;
augmentFont(font, from_ascii("lyxtex"));
tmpl_.metrics(mi, dim);
// FIXME UNICODE
dim.wid += mathed_string_width(font, name()) + 10;
// FIXME UNICODE
int ww = mathed_string_width(font, from_ascii("#1: "));
for (idx_type i = 0; i < nargs(); ++i) {
MathArray const & c = cell(i);
c.metrics(mi);
dim.wid = max(dim.wid, c.width() + ww);
dim.des += c.height() + 10;
}
} else {
// create MathMacroArgumentValue object pointing to the cells of the macro
MacroData const & macro = MacroTable::globalMacros().get(name());
vector<MathArray> values(nargs());
for (size_t i = 0; i != nargs(); ++i)
values[i].insert(0, MathAtom(new MathMacroArgumentValue(&cells_[i], name())));
macro.expand(values, expanded_);
MacroTable::globalMacros().get(name()).lock();
expanded_.metrics(mi, dim);
MacroTable::globalMacros().get(name()).unlock();
}
}
metricsMarkers2(dim);
if (dim_ == dim)
@ -96,28 +158,36 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const
if (!MacroTable::globalMacros().has(name())) {
// FIXME UNICODE
drawStrRed(pi, x, y, "Unknown: " + name());
} else if (editing(pi.base.bv)) {
LyXFont font = pi.base.font;
augmentFont(font, from_ascii("lyxtex"));
int h = y - dim_.ascent() + 2 + tmpl_.ascent();
pi.pain.text(x + 3, h, name(), font);
int const w = mathed_string_width(font, name());
tmpl_.draw(pi, x + w + 12, h);
h += tmpl_.descent();
Dimension ldim;
docstring t = from_ascii("#1: ");
mathed_string_dim(font, t, ldim);
for (idx_type i = 0; i < nargs(); ++i) {
MathArray const & c = cell(i);
h += max(c.ascent(), ldim.asc) + 5;
c.draw(pi, x + ldim.wid, h);
char_type str[] = { '#', '1', ':', '\0' };
str[1] += static_cast<char_type>(i);
pi.pain.text(x + 3, h, str, font);
h += max(c.descent(), ldim.des) + 5;
}
} else {
expanded_.draw(pi, x, y);
MacroData const & macro = MacroTable::globalMacros().get(name());
if (macro.locked()) {
// FIXME UNICODE
drawStrRed(pi, x, y, "Self reference: " + name());
} else if (editing(pi.base.bv)) {
LyXFont font = pi.base.font;
augmentFont(font, from_ascii("lyxtex"));
int h = y - dim_.ascent() + 2 + tmpl_.ascent();
pi.pain.text(x + 3, h, name(), font);
int const w = mathed_string_width(font, name());
tmpl_.draw(pi, x + w + 12, h);
h += tmpl_.descent();
Dimension ldim;
string t = "#1: ";
mathed_string_dim(font, name(), ldim);
for (idx_type i = 0; i < nargs(); ++i) {
MathArray const & c = cell(i);
h += max(c.ascent(), ldim.asc) + 5;
c.draw(pi, x + ldim.wid, h);
char_type str[] = { '#', '1', ':', '\0' };
str[1] += static_cast<char_type>(i);
pi.pain.text(x + 3, h, str, font);
h += max(c.descent(), ldim.des) + 5;
}
} else {
MacroTable::globalMacros().get(name()).lock();
expanded_.draw(pi, x, y);
MacroTable::globalMacros().get(name()).unlock();
}
}
drawMarkers2(pi, x, y);
}

View File

@ -36,12 +36,12 @@ using std::size_t;
MacroData::MacroData()
: numargs_(0)
: numargs_(0), lockCount_(0)
{}
MacroData::MacroData(docstring const & def, int numargs, docstring const & disp, string const & requires)
: def_(def), numargs_(numargs), disp_(disp), requires_(requires)
: def_(def), numargs_(numargs), disp_(disp), requires_(requires), lockCount_(0)
{}

View File

@ -4,7 +4,7 @@
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author André nitz
* \author Andr P<EFBFBD>nitz
*
* Full author contact details are available in file CREDITS.
*/
@ -12,11 +12,13 @@
#ifndef MATH_MACROTABLE_H
#define MATH_MACROTABLE_H
#include "support/docstring.h"
#include <boost/assert.hpp>
#include <map>
#include <vector>
#include "support/docstring.h"
namespace lyx {
class MathArray;
@ -40,6 +42,12 @@ public:
std::string requires() const { return requires_; }
///
std::string & requires() { return requires_; }
/// lock while being drawn
int lock() const { return ++lockCount_; }
/// is it being drawn?
bool locked() const { return lockCount_ != 0; }
///
void unlock() const { --lockCount_; BOOST_ASSERT(lockCount_ >= 0); }
private:
///
@ -50,6 +58,8 @@ private:
docstring disp_;
///
std::string requires_;
///
mutable int lockCount_;
};

View File

@ -111,6 +111,10 @@ docstring MathMacroTemplate::prefix() const
bool MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
{
bool lockMacro = MacroTable::globalMacros().has(name_);
if (lockMacro)
MacroTable::globalMacros().get(name_).lock();
cell(0).metrics(mi);
cell(1).metrics(mi);
docstring dp = prefix();
@ -118,6 +122,10 @@ bool MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
+ theFontMetrics(mi.base.font).width(dp);
dim.asc = std::max(cell(0).ascent(), cell(1).ascent()) + 7;
dim.des = std::max(cell(0).descent(), cell(1).descent()) + 7;
if (lockMacro)
MacroTable::globalMacros().get(name_).unlock();
if (dim_ == dim)
return false;
dim_ = dim;
@ -127,6 +135,10 @@ bool MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
void MathMacroTemplate::draw(PainterInfo & p, int x, int y) const
{
bool lockMacro = MacroTable::globalMacros().has(name_);
if (lockMacro)
MacroTable::globalMacros().get(name_).lock();
setPosCache(p, x, y);
// label
@ -167,6 +179,9 @@ void MathMacroTemplate::draw(PainterInfo & p, int x, int y) const
cell(1).draw(pi, x + 8 + w0, y + 1);
pi.pain.rectangle(x + w0 + 6, y - dim_.ascent() + 3,
w1 + 4, dim_.height() - 6, LColor::mathline);
if (lockMacro)
MacroTable::globalMacros().get(name_).unlock();
}