-#include <config.h>
-
#ifdef __GNUG__
#pragma implementation
#endif
+#include <vector>
+
#include "math_matrixinset.h"
-#include "math_rowst.h"
-#include "math_xiter.h"
+#include "support.h"
+#include "debug.h"
#include "support/LOstream.h"
+#include "Painter.h"
+#include "LaTeXFeatures.h"
-using std::ostream;
-extern int number_of_newlines;
+namespace {
-MathMatrixInset::MathMatrixInset(int m, int n, short st)
- : MathParInset(st, "array", LM_OT_MATRIX), nc_(m), nr_(0), ws_(m),
- v_align_(0), h_align_(nc_, 'c'), row_(0)
-{
- flag = 15;
- if (n > 0) {
- row_ = new MathedRowSt(nc_ + 1);
- MathedXIter it(this);
- for (int j = 1; j < n; ++j) it.addRow();
- nr_ = n;
- if (nr_ == 1 && nc_ > 1) {
- for (int j = 0; j < nc_ - 1; ++j)
- it.insert('T', LM_TC_TAB);
+ int getCols(MathInsetTypes type)
+ {
+ switch (type) {
+ case LM_OT_EQNARRAY:
+ return 3;
+ case LM_OT_ALIGN:
+ case LM_OT_ALIGNAT:
+ case LM_OT_XALIGNAT:
+ case LM_OT_XXALIGNAT:
+ return 2;
+ default:;
}
- } else if (n < 0) {
- row_ = new MathedRowSt(nc_ + 1);
- nr_ = 1;
+ return 1;
+ }
+
+
+ // returns position of first relation operator in the array
+ // used for "intelligent splitting"
+ int firstRelOp(MathArray const & ar)
+ {
+ for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
+ if ((*it)->isRelOp())
+ return it - ar.begin();
+ return ar.size();
}
+
+
+ char const * star(bool numbered)
+ {
+ return numbered ? "" : "*";
+ }
+
+ MathInsetTypes typecode(string const & s)
+ {
+ if (s == "equation") return LM_OT_EQUATION;
+ if (s == "display") return LM_OT_EQUATION;
+ if (s == "eqnarray") return LM_OT_EQNARRAY;
+ if (s == "align") return LM_OT_ALIGN;
+ if (s == "alignat") return LM_OT_ALIGNAT;
+ if (s == "xalignat") return LM_OT_XALIGNAT;
+ if (s == "xxalignat") return LM_OT_XXALIGNAT;
+ if (s == "multline") return LM_OT_MULTLINE;
+ if (s == "gather") return LM_OT_GATHER;
+ return LM_OT_SIMPLE;
+ }
+
+
+ string normalName(MathInsetTypes t)
+ {
+ switch (t) {
+ case LM_OT_EQUATION: return "equation";
+ case LM_OT_EQNARRAY: return "eqnarray";
+ case LM_OT_ALIGN: return "align";
+ case LM_OT_ALIGNAT: return "alignat";
+ case LM_OT_XALIGNAT: return "xalignat";
+ case LM_OT_XXALIGNAT: return "xxalignat";
+ case LM_OT_MULTLINE: return "multline";
+ case LM_OT_GATHER: return "gather";
+ case LM_OT_SIMPLE: return "simple";
+ default: break;
+ }
+ return "unknown";
+ }
+
+} // end anon namespace
+
+
+MathMatrixInset::MathMatrixInset()
+ : MathGridInset(1, 1), objtype_(LM_OT_SIMPLE), nonum_(1), label_(1)
+{
+ setDefaults();
}
-MathMatrixInset::MathMatrixInset(MathMatrixInset const & mt)
- : MathParInset(mt.GetStyle(), mt.GetName(), mt.GetType()),
- nc_(mt.nc_), nr_(0), ws_(mt.nc_),
- v_align_(mt.v_align_), h_align_(mt.h_align_)
+MathMatrixInset::MathMatrixInset(MathInsetTypes t)
+ : MathGridInset(getCols(t), 1), objtype_(t), nonum_(1), label_(1)
{
- array = mt.GetData();
- if (mt.row_ != 0) {
- MathedRowSt * ro = 0;
- MathedRowSt * mrow = mt.row_;
+ setDefaults();
+}
- while (mrow) {
- MathedRowSt * r = new MathedRowSt(nc_ + 1);
- r->setNumbered(mrow->isNumbered());
- //if (mrow->label)
- r->setLabel(mrow->getLabel());
- if (!ro)
- row_ = r;
- else
- ro->setNext(r);
- mrow = mrow->getNext();
- ro = r;
- ++nr_;
- }
- } else
- row_ = 0;
- flag = mt.flag;
+
+MathMatrixInset::MathMatrixInset(MathInsetTypes t, col_type cols)
+ : MathGridInset(cols, 1), objtype_(t), nonum_(1), label_(1)
+{
+ setDefaults();
}
-MathMatrixInset::~MathMatrixInset()
+MathInset * MathMatrixInset::clone() const
{
- MathedRowSt * r = row_;
- while (r) {
- MathedRowSt * q = r->getNext();
- delete r;
- r = q;
+ return new MathMatrixInset(*this);
+}
+
+
+char MathMatrixInset::defaultColAlign(col_type col)
+{
+ switch (getType()) {
+ case LM_OT_ALIGN:
+ case LM_OT_ALIGNAT:
+ case LM_OT_XALIGNAT:
+ case LM_OT_XXALIGNAT:
+ return "rl"[col & 1];
+ case LM_OT_EQNARRAY:
+ return "rcl"[col];
+ default:;
}
+ return 'c';
}
-MathedInset * MathMatrixInset::Clone()
+int MathMatrixInset::defaultColSpace(col_type col)
{
- return new MathMatrixInset(*this);
+ switch (getType()) {
+ case LM_OT_ALIGN:
+ case LM_OT_ALIGNAT:
+ return 0;
+ case LM_OT_XALIGNAT:
+ return (col & 1) ? 20 : 0;
+ case LM_OT_XXALIGNAT:
+ return (col & 1) ? 40 : 0;
+ default:;
+ }
+ return 10;
}
-void MathMatrixInset::SetAlign(char vv, string const & hh)
+void MathMatrixInset::metrics(MathMetricsInfo const & mi) const
{
- v_align_ = vv;
- h_align_ = hh.substr(0, nc_); // usr just h_align = hh; perhaps
+ mi_ = mi;
+ mi_.style = (getType() == LM_OT_SIMPLE) ? LM_ST_TEXT : LM_ST_DISPLAY;
+
+ // let the cells adjust themselves
+ MathGridInset::metrics(mi_);
+
+ if (display()) {
+ ascent_ += 12;
+ descent_ += 12;
+ }
+
+ if (numberedType()) {
+ int l = 0;
+ for (row_type row = 0; row < nrows(); ++row)
+ l = std::max(l, mathed_string_width(LM_TC_BF, mi_, nicelabel(row)));
+
+ if (l)
+ width_ += 30 + l;
+ }
+
+ // make it at least as high as the current font
+ int asc = 0;
+ int des = 0;
+ math_font_max_dim(LM_TC_TEXTRM, mi_, asc, des);
+ ascent_ = std::max(ascent_, asc);
+ descent_ = std::max(descent_, des);
}
-// Check the number of tabs and crs
-void MathMatrixInset::setData(MathedArray const & a)
+void MathMatrixInset::draw(Painter & pain, int x, int y) const
{
- array = a;
+ MathGridInset::draw(pain, x, y);
- MathedIter it(&array);
- int nn = nc_ - 1;
- nr_ = 1;
- // count tabs per row
- while (it.OK()) {
- if (it.IsTab()) {
- if (nn < 0) {
- it.Delete();
- continue;
- } else {
- // it.Next();
- --nn;
- }
+ if (numberedType()) {
+ int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
+ for (row_type row = 0; row < nrows(); ++row) {
+ int const yy = y + rowinfo_[row].offset_;
+ drawStr(pain, LM_TC_BF, mi_, xx, yy, nicelabel(row));
}
- if (it.IsCR()) {
- while (nn > 0) {
- it.insert(' ', LM_TC_TAB);
- --nn;
- }
- nn = nc_ - 1;
- ++nr_;
+ }
+}
+
+
+void MathMatrixInset::write(MathWriteInfo & os) const
+{
+ header_write(os.os);
+
+ bool n = numberedType();
+
+ for (row_type row = 0; row < nrows(); ++row) {
+ for (col_type col = 0; col < ncols(); ++col)
+ os << cell(index(row, col)) << eocString(col);
+ if (n) {
+ if (!label_[row].empty())
+ os << "\\label{" << label_[row] << "}";
+ if (nonum_[row])
+ os << "\\nonumber ";
}
- it.Next();
+ os << eolString(row);
}
- it.Reset();
-
- // Automatically inserts tabs around bops
- // DISABLED because it's very easy to insert tabs
+
+ footer_write(os.os);
}
-void MathMatrixInset::draw(Painter & pain, int x, int baseline)
+void MathMatrixInset::writeNormal(std::ostream & os) const
{
- MathParInset::draw(pain, x, baseline);
+ os << "[formula " << normalName(getType()) << " ";
+ MathGridInset::writeNormal(os);
+ os << "] ";
}
-void MathMatrixInset::Metrics()
+string MathMatrixInset::label(row_type row) const
{
- if (!row_) {
- // lyxerr << " MIDA ";
- MathedXIter it(this);
- row_ = it.adjustVerticalSt();
- }
-
- // Clean the arrays
- MathedRowSt * cxrow = row_;
- while (cxrow) {
- for (int i = 0; i <= nc_; ++i)
- cxrow->setTab(i, 0);
- cxrow = cxrow->getNext();
- }
-
- // Basic metrics
- MathParInset::Metrics();
-
- if (nc_ <= 1 && !row_->getNext()) {
- row_->ascent(ascent);
- row_->descent(descent);
+ return label_[row];
+}
+
+
+void MathMatrixInset::label(row_type row, string const & label)
+{
+ label_[row] = label;
+}
+
+
+void MathMatrixInset::numbered(row_type row, bool num)
+{
+ nonum_[row] = !num;
+}
+
+
+bool MathMatrixInset::numbered(row_type row) const
+{
+ return !nonum_[row];
+}
+
+
+bool MathMatrixInset::ams() const
+{
+ return true;
+
+ return
+ objtype_ == LM_OT_ALIGN ||
+ objtype_ == LM_OT_MULTLINE ||
+ objtype_ == LM_OT_GATHER ||
+ objtype_ == LM_OT_ALIGNAT ||
+ objtype_ == LM_OT_XALIGNAT ||
+ objtype_ == LM_OT_XXALIGNAT;
+}
+
+
+bool MathMatrixInset::display() const
+{
+ return getType() != LM_OT_SIMPLE;
+}
+
+
+std::vector<string> const MathMatrixInset::getLabelList() const
+{
+ std::vector<string> res;
+ for (row_type row = 0; row < nrows(); ++row)
+ if (!label_[row].empty() && nonum_[row] != 1)
+ res.push_back(label_[row]);
+ return res;
+}
+
+
+bool MathMatrixInset::numberedType() const
+{
+ if (getType() == LM_OT_SIMPLE || getType() == LM_OT_XXALIGNAT)
+ return false;
+ for (row_type row = 0; row < nrows(); ++row)
+ if (!nonum_[row])
+ return true;
+ return false;
+}
+
+
+void MathMatrixInset::validate(LaTeXFeatures & features) const
+{
+ features.amsstyle = ams();
+
+ // Validation is necessary only if not using AMS math.
+ // To be safe, we will always run mathedvalidate.
+ //if (features.amsstyle)
+ // return;
+
+ features.boldsymbol = true;
+ //features.binom = true;
+
+ MathNestInset::validate(features);
+}
+
+
+void MathMatrixInset::header_write(std::ostream & os) const
+{
+ bool n = numberedType();
+
+ switch (getType()) {
+ case LM_OT_SIMPLE:
+ os << '$';
+ if (cell(0).empty())
+ os << ' ';
+ break;
+
+ case LM_OT_EQUATION:
+ if (n)
+ os << "\\begin{equation" << star(n) << "}\n";
+ else
+ os << "\\[\n";
+ break;
+
+ case LM_OT_EQNARRAY:
+ os << "\\begin{eqnarray" << star(n) << "}\n";
+ break;
+
+ case LM_OT_ALIGN:
+ os << "\\begin{align" << star(n) << "}\n";
+ break;
+
+ case LM_OT_ALIGNAT:
+ os << "\\begin{alignat" << star(n) << "}" << "{" << ncols()/2 << "}\n";
+ break;
+
+ case LM_OT_XALIGNAT:
+ os << "\\begin{xalignat" << star(n) << "}" << "{" << ncols()/2 << "}\n";
+ break;
+
+ case LM_OT_XXALIGNAT:
+ os << "\\begin{xxalignat}" << "{" << ncols()/2 << "}\n";
+ break;
+
+ case LM_OT_MULTLINE:
+ os << "\\begin{multline}\n";
+ break;
+
+ case LM_OT_GATHER:
+ os << "\\begin{gather}\n";
+ break;
+
+ default:
+ os << "\\begin{unknown" << star(n) << "}";
}
-
- // Vertical positions of each row
- cxrow = row_;
- MathedRowSt * cprow = 0;
- int h = 0;
- while (cxrow) {
- for (int i = 0; i < nc_; ++i) {
- if (cxrow == row_ || ws_[i] < cxrow->getTab(i))
- ws_[i] = cxrow->getTab(i);
- if (cxrow->getNext() == 0 && ws_[i] == 0)
- ws_[i] = df_width;
- }
-
- cxrow->setBaseline((cxrow == row_) ?
- cxrow->ascent() :
- cxrow->ascent() + cprow->descent()
- + MATH_ROWSEP + cprow->getBaseline());
- h += cxrow->ascent() + cxrow->descent() + MATH_ROWSEP;
- cprow = cxrow;
- cxrow = cxrow->getNext();
+}
+
+
+void MathMatrixInset::footer_write(std::ostream & os) const
+{
+ bool n = numberedType();
+
+ switch (getType()) {
+ case LM_OT_SIMPLE:
+ os << '$';
+ break;
+
+ case LM_OT_EQUATION:
+ if (n)
+ os << "\\end{equation" << star(n) << "}\n";
+ else
+ os << "\\]\n";
+ break;
+
+ case LM_OT_EQNARRAY:
+ os << "\n\\end{eqnarray" << star(n) << "}\n";
+ break;
+
+ case LM_OT_ALIGN:
+ os << "\n\\end{align" << star(n) << "}\n";
+ break;
+
+ case LM_OT_ALIGNAT:
+ os << "\n\\end{alignat" << star(n) << "}\n";
+ break;
+
+ case LM_OT_XALIGNAT:
+ os << "\n\\end{xalignat" << star(n) << "}\n";
+ break;
+
+ case LM_OT_XXALIGNAT:
+ os << "\n\\end{xxalignat}\n";
+ break;
+
+ case LM_OT_MULTLINE:
+ os << "\n\\end{multline}\n";
+ break;
+
+ case LM_OT_GATHER:
+ os << "\n\\end{gather}\n";
+ break;
+
+ default:
+ os << "\\end{unknown" << star(n) << "}";
}
-
- int const hl = Descent();
- h -= MATH_ROWSEP;
-
- // Compute vertical align
- switch (v_align_) {
- case 't':
- ascent = row_->getBaseline();
- break;
- case 'b':
- ascent = h - hl;
- break;
- default:
- ascent = (row_->getNext()) ? h / 2 : h - hl;
- break;
+}
+
+
+void MathMatrixInset::addRow(row_type row)
+{
+ nonum_.insert(nonum_.begin() + row + 1, !numberedType());
+ label_.insert(label_.begin() + row + 1, string());
+ MathGridInset::addRow(row);
+}
+
+
+void MathMatrixInset::appendRow()
+{
+ nonum_.push_back(!numberedType());
+ label_.push_back(string());
+ MathGridInset::appendRow();
+}
+
+
+void MathMatrixInset::delRow(row_type row)
+{
+ MathGridInset::delRow(row);
+ nonum_.erase(nonum_.begin() + row);
+ label_.erase(label_.begin() + row);
+}
+
+
+void MathMatrixInset::addCol(col_type col)
+{
+ switch (getType()) {
+ case LM_OT_EQUATION:
+ mutate(LM_OT_EQNARRAY);
+ break;
+
+ case LM_OT_EQNARRAY:
+ mutate(LM_OT_ALIGN);
+ addCol(col);
+ break;
+
+ case LM_OT_ALIGN:
+ mutate(LM_OT_ALIGNAT);
+ addCol(col);
+ break;
+
+ case LM_OT_ALIGNAT:
+ case LM_OT_XALIGNAT:
+ case LM_OT_XXALIGNAT:
+ MathGridInset::addCol(col);
+ MathGridInset::addCol(col + 1);
+ break;
+
+ default:
+ break;
}
- descent = h - ascent + 2;
-
- // Increase ws_[i] for 'R' columns (except the first one)
- for (int i = 1; i < nc_; ++i)
- if (h_align_[i] == 'R')
- ws_[i] += 10 * df_width;
- // Increase ws_[i] for 'C' column
- if (h_align_[0] == 'C')
- if (ws_[0] < 7 * workWidth / 8)
- ws_[0] = 7 * workWidth / 8;
-
- // Adjust local tabs
- cxrow = row_;
- width = MATH_COLSEP;
- while (cxrow) {
- int rg = MATH_COLSEP;
- int lf = 0;
- for (int i = 0; i < nc_; ++i) {
- bool isvoid = false;
- if (cxrow->getTab(i) <= 0) {
- cxrow->setTab(i, df_width);
- isvoid = true;
- }
- switch (h_align_[i]) {
- case 'l':
- lf = 0;
- break;
- case 'c':
- lf = (ws_[i] - cxrow->getTab(i))/2;
- break;
- case 'r':
- case 'R':
- lf = ws_[i] - cxrow->getTab(i);
- break;
- case 'C':
- if (cxrow == row_)
- lf = 0;
- else if (!cxrow->getNext())
- lf = ws_[i] - cxrow->getTab(i);
- else
- lf = (ws_[i] - cxrow->getTab(i))/2;
- break;
- }
- int const ww = (isvoid) ? lf : lf + cxrow->getTab(i);
- cxrow->setTab(i, lf + rg);
- rg = ws_[i] - ww + MATH_COLSEP;
- if (cxrow == row_)
- width += ws_[i] + MATH_COLSEP;
- }
- cxrow->setBaseline(cxrow->getBaseline() - ascent);
- cxrow = cxrow->getNext();
+}
+
+
+void MathMatrixInset::delCol(col_type col)
+{
+ switch (getType()) {
+ case LM_OT_ALIGNAT:
+ case LM_OT_XALIGNAT:
+ case LM_OT_XXALIGNAT:
+ MathGridInset::delCol(col + 1);
+ MathGridInset::delCol(col);
+ break;
+ default:
+ break;
}
}
-void MathMatrixInset::Write(ostream & os, bool fragile)
+string MathMatrixInset::nicelabel(row_type row) const
{
- if (GetType() == LM_OT_MATRIX) {
- if (fragile)
- os << "\\protect";
- os << "\\begin{"
- << name
- << '}';
- if (v_align_ == 't' || v_align_ == 'b') {
- os << '['
- << char(v_align_)
- << ']';
- }
- os << '{'
- << h_align_
- << "}\n";
- ++number_of_newlines;
+ if (nonum_[row])
+ return string();
+ if (label_[row].empty())
+ return string("(#)");
+ return "(" + label_[row] + ")";
+}
+
+
+void MathMatrixInset::mutate(string const & newtype)
+{
+ if (newtype == "dump") {
+ dump();
+ return;
}
- MathParInset::Write(os, fragile);
- if (GetType() == LM_OT_MATRIX){
- os << "\n";
- if (fragile)
- os << "\\protect";
- os << "\\end{"
- << name
- << '}';
- ++number_of_newlines;
+ //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
+ mutate(typecode(newtype));
+}
+
+
+void MathMatrixInset::glueall()
+{
+ MathArray ar;
+ for (idx_type i = 0; i < nargs(); ++i)
+ ar.push_back(cell(i));
+ *this = MathMatrixInset(LM_OT_SIMPLE);
+ cell(0) = ar;
+}
+
+
+MathInsetTypes MathMatrixInset::getType() const
+{
+ return objtype_;
+}
+
+
+void MathMatrixInset::setType(MathInsetTypes t)
+{
+ objtype_ = t;
+ setDefaults();
+}
+
+
+
+void MathMatrixInset::mutate(MathInsetTypes newtype)
+{
+ //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
+
+ if (newtype == getType())
+ return;
+
+ switch (getType()) {
+ case LM_OT_SIMPLE:
+ setType(LM_OT_EQUATION);
+ numbered(0, false);
+ mutate(newtype);
+ break;
+
+ case LM_OT_EQUATION:
+ switch (newtype) {
+ case LM_OT_SIMPLE:
+ setType(LM_OT_SIMPLE);
+ break;
+
+ case LM_OT_ALIGN:
+ case LM_OT_ALIGNAT:
+ case LM_OT_XALIGNAT:
+ case LM_OT_XXALIGNAT: {
+
+ MathGridInset::addCol(1);
+
+ // split it "nicely"
+ pos_type pos = firstRelOp(cell(0));
+ cell(1) = cell(0);
+ cell(0).erase(pos, cell(0).size());
+ cell(1).erase(0, pos);
+ setType(LM_OT_ALIGN);
+ mutate(newtype);
+ break;
+ }
+
+ case LM_OT_EQNARRAY:
+ default:
+ MathGridInset::addCol(1);
+ MathGridInset::addCol(1);
+
+ // split it "nicely" on the firest relop
+ pos_type pos = firstRelOp(cell(0));
+ cell(1) = cell(0);
+ cell(0).erase(pos, cell(0).size());
+ cell(1).erase(0, pos);
+
+ if (cell(1).size()) {
+ cell(2) = cell(1);
+ cell(1).erase(1, cell(1).size());
+ cell(2).erase(0);
+ }
+
+ setType(LM_OT_EQNARRAY);
+ mutate(newtype);
+ break;
+ }
+ break;
+
+ case LM_OT_EQNARRAY:
+ switch (newtype) {
+ case LM_OT_SIMPLE:
+ case LM_OT_EQUATION: {
+ // set correct (no)numbering
+ bool allnonum = true;
+ for (row_type row = 0; row < nrows(); ++row) {
+ if (!nonum_[row])
+ allnonum = false;
+ }
+
+ // set first non-empty label
+ string label;
+ for (row_type row = 0; row < nrows(); ++row) {
+ if (!label_[row].empty()) {
+ label = label_[row];
+ break;
+ }
+ }
+
+ glueall();
+
+ nonum_[0] = allnonum;
+ label_[0] = label;
+ mutate(newtype);
+ break;
+ }
+
+ case LM_OT_ALIGN:
+ case LM_OT_ALIGNAT:
+ case LM_OT_XALIGNAT:
+ case LM_OT_XXALIGNAT:
+ default: {
+ for (row_type row = 0; row < nrows(); ++row) {
+ idx_type c = 3 * row + 1;
+ cell(c).push_back(cell(c + 1));
+ }
+ MathGridInset::delCol(2);
+ setType(LM_OT_ALIGN);
+ mutate(newtype);
+ break;
+ }
+ }
+ break;
+
+ case LM_OT_ALIGN:
+ switch (newtype) {
+ case LM_OT_SIMPLE:
+ case LM_OT_EQUATION:
+ case LM_OT_EQNARRAY:
+ MathGridInset::addCol(1);
+ setType(LM_OT_EQNARRAY);
+ mutate(newtype);
+ break;
+
+ case LM_OT_ALIGNAT:
+ case LM_OT_XALIGNAT:
+ case LM_OT_XXALIGNAT:
+ setType(newtype);
+ break;
+
+ default:
+ lyxerr << "mutation from '" << getType()
+ << "' to '" << newtype << "' not implemented\n";
+ break;
+ }
+ break;
+
+ case LM_OT_MULTLINE:
+ switch (newtype) {
+ case LM_OT_GATHER:
+ setType(LM_OT_GATHER);
+ break;
+ default:
+ lyxerr << "mutation from '" << getType()
+ << "' to '" << newtype << "' not implemented\n";
+ break;
+ }
+
+ case LM_OT_GATHER:
+ switch (newtype) {
+ case LM_OT_MULTLINE:
+ setType(LM_OT_MULTLINE);
+ break;
+ default:
+ lyxerr << "mutation from '" << getType()
+ << "' to '" << newtype << "' not implemented\n";
+ break;
+ }
+
+ default:
+ lyxerr << "mutation from '" << getType()
+ << "' to '" << newtype << "' not implemented\n";
}
}