]> git.lyx.org Git - features.git/commitdiff
Real fix for bug 1395 by Stefan Schimanski, this commit replace the one done at revis...
authorAbdelrazak Younes <younes@lyx.org>
Tue, 17 Apr 2007 16:52:43 +0000 (16:52 +0000)
committerAbdelrazak Younes <younes@lyx.org>
Tue, 17 Apr 2007 16:52:43 +0000 (16:52 +0000)
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

src/mathed/InsetMathMacro.C
src/mathed/MathMacroTable.C
src/mathed/MathMacroTable.h
src/mathed/MathMacroTemplate.C

index 43cbed7c315ab6e9bb8d1540c3f8d5bc6f7fcc8c..087aa808076f2089d0bd0d7f1776c83af5fe24f2 100644 (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);
 }
index 961235c2f28a426ebf37353679c170cac43a1f99..20634191947803eeb569279a0ca453996ada38e6 100644 (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)
 {}
 
 
index f6e2db77aa88bbb74ffb60fcaaaebceacbeaf831..eda5a21c2badbec95a6eaaf498cc23c357f6b459 100644 (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é Pönitz
+ * \author Andr P�nitz
  *
  * Full author contact details are available in file CREDITS.
  */
 #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_;
 };
 
 
index 2f6f8b4e79e59a97f6a4d0746ada73d52e6e355f..24cb74a725584b6525e0ad5550b347e30479249c 100644 (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();
 }