--- /dev/null
+/**
+ * \file InsetCitation.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Angus Leeming
+ * \author Herbert Voß
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "InsetCitation.h"
+
+#include "buffer.h"
+#include "bufferparams.h"
+#include "debug.h"
+#include "dispatchresult.h"
+#include "funcrequest.h"
+#include "LaTeXFeatures.h"
+
+#include "frontends/controllers/biblio.h"
+
+#include "support/fs_extras.h"
+#include "support/lstrings.h"
+
+#include <algorithm>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/exception.hpp>
+
+
+namespace lyx {
+
+using support::ascii_lowercase;
+using support::contains;
+using support::FileName;
+using support::getStringFromVector;
+using support::getVectorFromString;
+using support::ltrim;
+using support::rtrim;
+using support::split;
+using support::tokenPos;
+
+using std::endl;
+using std::replace;
+using std::string;
+using std::ostream;
+using std::vector;
+using std::map;
+
+namespace fs = boost::filesystem;
+
+
+namespace {
+
+docstring const getNatbibLabel(Buffer const & buffer,
+ string const & citeType, string const & keyList,
+ docstring const & before, docstring const & after,
+ biblio::CiteEngine engine)
+{
+ // Only start the process off after the buffer is loaded from file.
+ if (!buffer.fully_loaded())
+ return docstring();
+
+ // Cache the labels
+ typedef std::map<Buffer const *, biblio::InfoMap> CachedMap;
+ static CachedMap cached_keys;
+
+ // and cache the timestamp of the bibliography files.
+ static std::map<FileName, time_t> bibfileStatus;
+
+ biblio::InfoMap infomap;
+
+ vector<FileName> const & bibfilesCache = buffer.getBibfilesCache();
+ // compare the cached timestamps with the actual ones.
+ bool changed = false;
+ for (vector<FileName>::const_iterator it = bibfilesCache.begin();
+ it != bibfilesCache.end(); ++ it) {
+ FileName const f = *it;
+ try {
+ std::time_t lastw = fs::last_write_time(f.toFilesystemEncoding());
+ if (lastw != bibfileStatus[f]) {
+ changed = true;
+ bibfileStatus[f] = lastw;
+ }
+ }
+ catch (fs::filesystem_error & fserr) {
+ changed = true;
+ lyxerr << "Couldn't find or read bibtex file "
+ << f << endl;
+ LYXERR(Debug::DEBUG) << "Fs error: "
+ << fserr.what() << endl;
+ }
+ }
+
+ // build the keylist only if the bibfiles have been changed
+ if (cached_keys[&buffer].empty() || bibfileStatus.empty() || changed) {
+ typedef vector<std::pair<string, docstring> > InfoType;
+ InfoType bibkeys;
+ buffer.fillWithBibKeys(bibkeys);
+
+ InfoType::const_iterator bit = bibkeys.begin();
+ InfoType::const_iterator bend = bibkeys.end();
+
+ for (; bit != bend; ++bit)
+ infomap[bit->first] = bit->second;
+
+ cached_keys[&buffer] = infomap;
+ } else
+ // use the cached keys
+ infomap = cached_keys[&buffer];
+
+ if (infomap.empty())
+ return docstring();
+
+ // the natbib citation-styles
+ // CITET: author (year)
+ // CITEP: (author,year)
+ // CITEALT: author year
+ // CITEALP: author, year
+ // CITEAUTHOR: author
+ // CITEYEAR: year
+ // CITEYEARPAR: (year)
+ // jurabib supports these plus
+ // CITE: author/<before field>
+
+ // We don't currently use the full or forceUCase fields.
+ string cite_type = biblio::asValidLatexCommand(citeType, engine);
+ if (cite_type[0] == 'C')
+ cite_type = string(1, 'c') + cite_type.substr(1);
+ if (cite_type[cite_type.size() - 1] == '*')
+ cite_type = cite_type.substr(0, cite_type.size() - 1);
+
+ docstring before_str;
+ if (!before.empty()) {
+ // In CITET and CITEALT mode, the "before" string is
+ // attached to the label associated with each and every key.
+ // In CITEP, CITEALP and CITEYEARPAR mode, it is attached
+ // to the front of the whole only.
+ // In other modes, it is not used at all.
+ if (cite_type == "citet" ||
+ cite_type == "citealt" ||
+ cite_type == "citep" ||
+ cite_type == "citealp" ||
+ cite_type == "citeyearpar")
+ before_str = before + ' ';
+ // In CITE (jurabib), the "before" string is used to attach
+ // the annotator (of legal texts) to the author(s) of the
+ // first reference.
+ else if (cite_type == "cite")
+ before_str = '/' + before;
+ }
+
+ docstring after_str;
+ if (!after.empty()) {
+ // The "after" key is appended only to the end of the whole.
+ after_str = ", " + after;
+ }
+
+ // One day, these might be tunable (as they are in BibTeX).
+ char const op = '('; // opening parenthesis.
+ char const cp = ')'; // closing parenthesis.
+ // puctuation mark separating citation entries.
+ char const * const sep = ";";
+
+ docstring const op_str(' ' + docstring(1, op));
+ docstring const cp_str(docstring(1, cp) + ' ');
+ docstring const sep_str(from_ascii(sep) + ' ');
+
+ docstring label;
+ vector<string> keys = getVectorFromString(keyList);
+ vector<string>::const_iterator it = keys.begin();
+ vector<string>::const_iterator end = keys.end();
+ for (; it != end; ++it) {
+ // get the bibdata corresponding to the key
+ docstring const author(biblio::getAbbreviatedAuthor(infomap, *it));
+ docstring const year(biblio::getYear(infomap, *it));
+
+ // Something isn't right. Fail safely.
+ if (author.empty() || year.empty())
+ return docstring();
+
+ // authors1/<before>; ... ;
+ // authors_last, <after>
+ if (cite_type == "cite" && engine == biblio::ENGINE_JURABIB) {
+ if (it == keys.begin())
+ label += author + before_str + sep_str;
+ else
+ label += author + sep_str;
+
+ // (authors1 (<before> year); ... ;
+ // authors_last (<before> year, <after>)
+ } else if (cite_type == "citet") {
+ switch (engine) {
+ case biblio::ENGINE_NATBIB_AUTHORYEAR:
+ label += author + op_str + before_str +
+ year + cp + sep_str;
+ break;
+ case biblio::ENGINE_NATBIB_NUMERICAL:
+ // FIXME UNICODE
+ label += author + op_str + before_str +
+ '#' + from_utf8(*it) + cp + sep_str;
+ break;
+ case biblio::ENGINE_JURABIB:
+ label += before_str + author + op_str +
+ year + cp + sep_str;
+ break;
+ case biblio::ENGINE_BASIC:
+ break;
+ }
+
+ // author, year; author, year; ...
+ } else if (cite_type == "citep" ||
+ cite_type == "citealp") {
+ if (engine == biblio::ENGINE_NATBIB_NUMERICAL) {
+ // FIXME UNICODE
+ label += from_utf8(*it) + sep_str;
+ } else {
+ label += author + ", " + year + sep_str;
+ }
+
+ // (authors1 <before> year;
+ // authors_last <before> year, <after>)
+ } else if (cite_type == "citealt") {
+ switch (engine) {
+ case biblio::ENGINE_NATBIB_AUTHORYEAR:
+ label += author + ' ' + before_str +
+ year + sep_str;
+ break;
+ case biblio::ENGINE_NATBIB_NUMERICAL:
+ // FIXME UNICODE
+ label += author + ' ' + before_str +
+ '#' + from_utf8(*it) + sep_str;
+ break;
+ case biblio::ENGINE_JURABIB:
+ label += before_str + author + ' ' +
+ year + sep_str;
+ break;
+ case biblio::ENGINE_BASIC:
+ break;
+ }
+
+ // author; author; ...
+ } else if (cite_type == "citeauthor") {
+ label += author + sep_str;
+
+ // year; year; ...
+ } else if (cite_type == "citeyear" ||
+ cite_type == "citeyearpar") {
+ label += year + sep_str;
+ }
+ }
+ label = rtrim(rtrim(label), sep);
+
+ if (!after_str.empty()) {
+ if (cite_type == "citet") {
+ // insert "after" before last ')'
+ label.insert(label.size() - 1, after_str);
+ } else {
+ bool const add =
+ !(engine == biblio::ENGINE_NATBIB_NUMERICAL &&
+ (cite_type == "citeauthor" ||
+ cite_type == "citeyear"));
+ if (add)
+ label += after_str;
+ }
+ }
+
+ if (!before_str.empty() && (cite_type == "citep" ||
+ cite_type == "citealp" ||
+ cite_type == "citeyearpar")) {
+ label = before_str + label;
+ }
+
+ if (cite_type == "citep" || cite_type == "citeyearpar")
+ label = op + label + cp;
+
+ return label;
+}
+
+
+docstring const getBasicLabel(docstring const & keyList, docstring const & after)
+{
+ docstring keys(keyList);
+ docstring label;
+
+ if (contains(keys, ',')) {
+ // Final comma allows while loop to cover all keys
+ keys = ltrim(split(keys, label, ',')) + ',';
+ while (contains(keys, ',')) {
+ docstring key;
+ keys = ltrim(split(keys, key, ','));
+ label += ", " + key;
+ }
+ } else
+ label = keys;
+
+ if (!after.empty())
+ label += ", " + after;
+
+ return '[' + label + ']';
+}
+
+} // anon namespace
+
+
+InsetCitation::InsetCitation(InsetCommandParams const & p)
+ : InsetCommand(p, "citation")
+{}
+
+
+docstring const InsetCitation::generateLabel(Buffer const & buffer) const
+{
+ docstring const before = getParam("before");
+ docstring const after = getParam("after");
+
+ docstring label;
+ biblio::CiteEngine const engine = buffer.params().getEngine();
+ if (engine != biblio::ENGINE_BASIC) {
+ // FIXME UNICODE
+ label = getNatbibLabel(buffer, getCmdName(), to_utf8(getParam("key")),
+ before, after, engine);
+ }
+
+ // Fallback to fail-safe
+ if (label.empty()) {
+ label = getBasicLabel(getParam("key"), after);
+ }
+
+ return label;
+}
+
+
+docstring const InsetCitation::getScreenLabel(Buffer const & buffer) const
+{
+ biblio::CiteEngine const engine = buffer.params().getEngine();
+ if (cache.params == params() && cache.engine == engine)
+ return cache.screen_label;
+
+ // The label has changed, so we have to re-create it.
+ docstring const glabel = generateLabel(buffer);
+
+ unsigned int const maxLabelChars = 45;
+
+ docstring label = glabel;
+ if (label.size() > maxLabelChars) {
+ label.erase(maxLabelChars-3);
+ label += "...";
+ }
+
+ cache.engine = engine;
+ cache.params = params();
+ cache.generated_label = glabel;
+ cache.screen_label = label;
+
+ return label;
+}
+
+
+int InsetCitation::plaintext(Buffer const & buffer, odocstream & os,
+ OutputParams const &) const
+{
+ docstring str;
+
+ if (cache.params == params() &&
+ cache.engine == buffer.params().getEngine())
+ str = cache.generated_label;
+ else
+ str = generateLabel(buffer);
+
+ os << str;
+ return str.size();
+}
+
+
+namespace {
+
+docstring const cleanupWhitespace(docstring const & citelist)
+{
+ docstring::const_iterator it = citelist.begin();
+ docstring::const_iterator end = citelist.end();
+ // Paranoia check: make sure that there is no whitespace in here
+ // -- at least not behind commas or at the beginning
+ docstring result;
+ char_type last = ',';
+ for (; it != end; ++it) {
+ if (*it != ' ')
+ last = *it;
+ if (*it != ' ' || last != ',')
+ result += *it;
+ }
+ return result;
+}
+
+// end anon namyspace
+}
+
+int InsetCitation::docbook(Buffer const &, odocstream & os,
+ OutputParams const &) const
+{
+ os << "<citation>"
+ << cleanupWhitespace(getParam("key"))
+ << "</citation>";
+ return 0;
+}
+
+
+int InsetCitation::textString(Buffer const & buf, odocstream & os,
+ OutputParams const & op) const
+{
+ return plaintext(buf, os, op);
+}
+
+
+// Have to overwrite the default InsetCommand method in order to check that
+// the \cite command is valid. Eg, the user has natbib enabled, inputs some
+// citations and then changes his mind, turning natbib support off. The output
+// should revert to \cite[]{}
+int InsetCitation::latex(Buffer const & buffer, odocstream & os,
+ OutputParams const &) const
+{
+ biblio::CiteEngine cite_engine = buffer.params().getEngine();
+ // FIXME UNICODE
+ docstring const cite_str = from_utf8(
+ biblio::asValidLatexCommand(getCmdName(), cite_engine));
+
+ os << "\\" << cite_str;
+
+ docstring const & before = getParam("before");
+ docstring const & after = getParam("after");
+ if (!before.empty() && cite_engine != biblio::ENGINE_BASIC)
+ os << '[' << before << "][" << after << ']';
+ else if (!after.empty())
+ os << '[' << after << ']';
+
+ os << '{' << cleanupWhitespace(getParam("key")) << '}';
+
+ return 0;
+}
+
+
+void InsetCitation::validate(LaTeXFeatures & features) const
+{
+ switch (features.bufferParams().getEngine()) {
+ case biblio::ENGINE_BASIC:
+ break;
+ case biblio::ENGINE_NATBIB_AUTHORYEAR:
+ case biblio::ENGINE_NATBIB_NUMERICAL:
+ features.require("natbib");
+ break;
+ case biblio::ENGINE_JURABIB:
+ features.require("jurabib");
+ break;
+ }
+}
+
+
+void InsetCitation::replaceContents(string const & from, string const & to)
+{
+ if (tokenPos(getContents(), ',', from) != -1) {
+ vector<string> items = getVectorFromString(getContents());
+ replace(items.begin(), items.end(), from, to);
+ setContents(getStringFromVector(items));
+ }
+}
+
+
+} // namespace lyx
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file InsetCitation.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Angus Leeming
+ * \author Herbert Voß
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef INSET_CITE_H
+#define INSET_CITE_H
+
+
+#include "InsetCommand.h"
+
+#include "frontends/controllers/biblio.h"
+
+
+namespace lyx {
+
+
+/** Used to insert citations
+ */
+class InsetCitation : public InsetCommand {
+public:
+ ///
+ InsetCitation(InsetCommandParams const &);
+ ///
+ docstring const getScreenLabel(Buffer const &) const;
+ ///
+ EDITABLE editable() const { return IS_EDITABLE; }
+ ///
+ InsetBase::Code lyxCode() const { return InsetBase::CITE_CODE; }
+ ///
+ int latex(Buffer const &, odocstream &,
+ OutputParams const &) const;
+ ///
+ int plaintext(Buffer const &, odocstream &,
+ OutputParams const &) const;
+ ///
+ int docbook(Buffer const &, odocstream &,
+ OutputParams const &) const;
+ /// the string that is passed to the TOC
+ virtual int textString(Buffer const &, odocstream &,
+ OutputParams const &) const;
+ ///
+ void validate(LaTeXFeatures &) const;
+ ///
+ void replaceContents(std::string const & from, std::string const & to);
+
+private:
+ virtual std::auto_ptr<InsetBase> doClone() const
+ {
+ return std::auto_ptr<InsetBase>(new InsetCitation(params()));
+ }
+
+ /// This function does the donkey work of creating the pretty label
+ docstring const generateLabel(Buffer const &) const;
+
+ class Cache {
+ public:
+ ///
+ Cache() : engine(biblio::ENGINE_BASIC), params("cite") {}
+ ///
+ biblio::CiteEngine engine;
+ ///
+ InsetCommandParams params;
+ ///
+ docstring generated_label;
+ ///
+ docstring screen_label;
+ };
+ ///
+ mutable Cache cache;
+};
+
+
+} // namespace lyx
+
+#endif // INSET_CITE_H
+++ /dev/null
-/**
- * \file InsetCitation.cpp
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author Angus Leeming
- * \author Herbert Voß
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#include <config.h>
-
-#include "InsetCitation.h"
-
-#include "buffer.h"
-#include "bufferparams.h"
-#include "debug.h"
-#include "dispatchresult.h"
-#include "funcrequest.h"
-#include "LaTeXFeatures.h"
-
-#include "frontends/controllers/biblio.h"
-
-#include "support/fs_extras.h"
-#include "support/lstrings.h"
-
-#include <algorithm>
-
-#include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/exception.hpp>
-
-
-namespace lyx {
-
-using support::ascii_lowercase;
-using support::contains;
-using support::FileName;
-using support::getStringFromVector;
-using support::getVectorFromString;
-using support::ltrim;
-using support::rtrim;
-using support::split;
-using support::tokenPos;
-
-using std::endl;
-using std::replace;
-using std::string;
-using std::ostream;
-using std::vector;
-using std::map;
-
-namespace fs = boost::filesystem;
-
-
-namespace {
-
-docstring const getNatbibLabel(Buffer const & buffer,
- string const & citeType, string const & keyList,
- docstring const & before, docstring const & after,
- biblio::CiteEngine engine)
-{
- // Only start the process off after the buffer is loaded from file.
- if (!buffer.fully_loaded())
- return docstring();
-
- // Cache the labels
- typedef std::map<Buffer const *, biblio::InfoMap> CachedMap;
- static CachedMap cached_keys;
-
- // and cache the timestamp of the bibliography files.
- static std::map<FileName, time_t> bibfileStatus;
-
- biblio::InfoMap infomap;
-
- vector<FileName> const & bibfilesCache = buffer.getBibfilesCache();
- // compare the cached timestamps with the actual ones.
- bool changed = false;
- for (vector<FileName>::const_iterator it = bibfilesCache.begin();
- it != bibfilesCache.end(); ++ it) {
- FileName const f = *it;
- try {
- std::time_t lastw = fs::last_write_time(f.toFilesystemEncoding());
- if (lastw != bibfileStatus[f]) {
- changed = true;
- bibfileStatus[f] = lastw;
- }
- }
- catch (fs::filesystem_error & fserr) {
- changed = true;
- lyxerr << "Couldn't find or read bibtex file "
- << f << endl;
- LYXERR(Debug::DEBUG) << "Fs error: "
- << fserr.what() << endl;
- }
- }
-
- // build the keylist only if the bibfiles have been changed
- if (cached_keys[&buffer].empty() || bibfileStatus.empty() || changed) {
- typedef vector<std::pair<string, docstring> > InfoType;
- InfoType bibkeys;
- buffer.fillWithBibKeys(bibkeys);
-
- InfoType::const_iterator bit = bibkeys.begin();
- InfoType::const_iterator bend = bibkeys.end();
-
- for (; bit != bend; ++bit)
- infomap[bit->first] = bit->second;
-
- cached_keys[&buffer] = infomap;
- } else
- // use the cached keys
- infomap = cached_keys[&buffer];
-
- if (infomap.empty())
- return docstring();
-
- // the natbib citation-styles
- // CITET: author (year)
- // CITEP: (author,year)
- // CITEALT: author year
- // CITEALP: author, year
- // CITEAUTHOR: author
- // CITEYEAR: year
- // CITEYEARPAR: (year)
- // jurabib supports these plus
- // CITE: author/<before field>
-
- // We don't currently use the full or forceUCase fields.
- string cite_type = biblio::asValidLatexCommand(citeType, engine);
- if (cite_type[0] == 'C')
- cite_type = string(1, 'c') + cite_type.substr(1);
- if (cite_type[cite_type.size() - 1] == '*')
- cite_type = cite_type.substr(0, cite_type.size() - 1);
-
- docstring before_str;
- if (!before.empty()) {
- // In CITET and CITEALT mode, the "before" string is
- // attached to the label associated with each and every key.
- // In CITEP, CITEALP and CITEYEARPAR mode, it is attached
- // to the front of the whole only.
- // In other modes, it is not used at all.
- if (cite_type == "citet" ||
- cite_type == "citealt" ||
- cite_type == "citep" ||
- cite_type == "citealp" ||
- cite_type == "citeyearpar")
- before_str = before + ' ';
- // In CITE (jurabib), the "before" string is used to attach
- // the annotator (of legal texts) to the author(s) of the
- // first reference.
- else if (cite_type == "cite")
- before_str = '/' + before;
- }
-
- docstring after_str;
- if (!after.empty()) {
- // The "after" key is appended only to the end of the whole.
- after_str = ", " + after;
- }
-
- // One day, these might be tunable (as they are in BibTeX).
- char const op = '('; // opening parenthesis.
- char const cp = ')'; // closing parenthesis.
- // puctuation mark separating citation entries.
- char const * const sep = ";";
-
- docstring const op_str(' ' + docstring(1, op));
- docstring const cp_str(docstring(1, cp) + ' ');
- docstring const sep_str(from_ascii(sep) + ' ');
-
- docstring label;
- vector<string> keys = getVectorFromString(keyList);
- vector<string>::const_iterator it = keys.begin();
- vector<string>::const_iterator end = keys.end();
- for (; it != end; ++it) {
- // get the bibdata corresponding to the key
- docstring const author(biblio::getAbbreviatedAuthor(infomap, *it));
- docstring const year(biblio::getYear(infomap, *it));
-
- // Something isn't right. Fail safely.
- if (author.empty() || year.empty())
- return docstring();
-
- // authors1/<before>; ... ;
- // authors_last, <after>
- if (cite_type == "cite" && engine == biblio::ENGINE_JURABIB) {
- if (it == keys.begin())
- label += author + before_str + sep_str;
- else
- label += author + sep_str;
-
- // (authors1 (<before> year); ... ;
- // authors_last (<before> year, <after>)
- } else if (cite_type == "citet") {
- switch (engine) {
- case biblio::ENGINE_NATBIB_AUTHORYEAR:
- label += author + op_str + before_str +
- year + cp + sep_str;
- break;
- case biblio::ENGINE_NATBIB_NUMERICAL:
- // FIXME UNICODE
- label += author + op_str + before_str +
- '#' + from_utf8(*it) + cp + sep_str;
- break;
- case biblio::ENGINE_JURABIB:
- label += before_str + author + op_str +
- year + cp + sep_str;
- break;
- case biblio::ENGINE_BASIC:
- break;
- }
-
- // author, year; author, year; ...
- } else if (cite_type == "citep" ||
- cite_type == "citealp") {
- if (engine == biblio::ENGINE_NATBIB_NUMERICAL) {
- // FIXME UNICODE
- label += from_utf8(*it) + sep_str;
- } else {
- label += author + ", " + year + sep_str;
- }
-
- // (authors1 <before> year;
- // authors_last <before> year, <after>)
- } else if (cite_type == "citealt") {
- switch (engine) {
- case biblio::ENGINE_NATBIB_AUTHORYEAR:
- label += author + ' ' + before_str +
- year + sep_str;
- break;
- case biblio::ENGINE_NATBIB_NUMERICAL:
- // FIXME UNICODE
- label += author + ' ' + before_str +
- '#' + from_utf8(*it) + sep_str;
- break;
- case biblio::ENGINE_JURABIB:
- label += before_str + author + ' ' +
- year + sep_str;
- break;
- case biblio::ENGINE_BASIC:
- break;
- }
-
- // author; author; ...
- } else if (cite_type == "citeauthor") {
- label += author + sep_str;
-
- // year; year; ...
- } else if (cite_type == "citeyear" ||
- cite_type == "citeyearpar") {
- label += year + sep_str;
- }
- }
- label = rtrim(rtrim(label), sep);
-
- if (!after_str.empty()) {
- if (cite_type == "citet") {
- // insert "after" before last ')'
- label.insert(label.size() - 1, after_str);
- } else {
- bool const add =
- !(engine == biblio::ENGINE_NATBIB_NUMERICAL &&
- (cite_type == "citeauthor" ||
- cite_type == "citeyear"));
- if (add)
- label += after_str;
- }
- }
-
- if (!before_str.empty() && (cite_type == "citep" ||
- cite_type == "citealp" ||
- cite_type == "citeyearpar")) {
- label = before_str + label;
- }
-
- if (cite_type == "citep" || cite_type == "citeyearpar")
- label = op + label + cp;
-
- return label;
-}
-
-
-docstring const getBasicLabel(docstring const & keyList, docstring const & after)
-{
- docstring keys(keyList);
- docstring label;
-
- if (contains(keys, ',')) {
- // Final comma allows while loop to cover all keys
- keys = ltrim(split(keys, label, ',')) + ',';
- while (contains(keys, ',')) {
- docstring key;
- keys = ltrim(split(keys, key, ','));
- label += ", " + key;
- }
- } else
- label = keys;
-
- if (!after.empty())
- label += ", " + after;
-
- return '[' + label + ']';
-}
-
-} // anon namespace
-
-
-InsetCitation::InsetCitation(InsetCommandParams const & p)
- : InsetCommand(p, "citation")
-{}
-
-
-docstring const InsetCitation::generateLabel(Buffer const & buffer) const
-{
- docstring const before = getParam("before");
- docstring const after = getParam("after");
-
- docstring label;
- biblio::CiteEngine const engine = buffer.params().getEngine();
- if (engine != biblio::ENGINE_BASIC) {
- // FIXME UNICODE
- label = getNatbibLabel(buffer, getCmdName(), to_utf8(getParam("key")),
- before, after, engine);
- }
-
- // Fallback to fail-safe
- if (label.empty()) {
- label = getBasicLabel(getParam("key"), after);
- }
-
- return label;
-}
-
-
-docstring const InsetCitation::getScreenLabel(Buffer const & buffer) const
-{
- biblio::CiteEngine const engine = buffer.params().getEngine();
- if (cache.params == params() && cache.engine == engine)
- return cache.screen_label;
-
- // The label has changed, so we have to re-create it.
- docstring const glabel = generateLabel(buffer);
-
- unsigned int const maxLabelChars = 45;
-
- docstring label = glabel;
- if (label.size() > maxLabelChars) {
- label.erase(maxLabelChars-3);
- label += "...";
- }
-
- cache.engine = engine;
- cache.params = params();
- cache.generated_label = glabel;
- cache.screen_label = label;
-
- return label;
-}
-
-
-int InsetCitation::plaintext(Buffer const & buffer, odocstream & os,
- OutputParams const &) const
-{
- docstring str;
-
- if (cache.params == params() &&
- cache.engine == buffer.params().getEngine())
- str = cache.generated_label;
- else
- str = generateLabel(buffer);
-
- os << str;
- return str.size();
-}
-
-
-namespace {
-
-docstring const cleanupWhitespace(docstring const & citelist)
-{
- docstring::const_iterator it = citelist.begin();
- docstring::const_iterator end = citelist.end();
- // Paranoia check: make sure that there is no whitespace in here
- // -- at least not behind commas or at the beginning
- docstring result;
- char_type last = ',';
- for (; it != end; ++it) {
- if (*it != ' ')
- last = *it;
- if (*it != ' ' || last != ',')
- result += *it;
- }
- return result;
-}
-
-// end anon namyspace
-}
-
-int InsetCitation::docbook(Buffer const &, odocstream & os,
- OutputParams const &) const
-{
- os << "<citation>"
- << cleanupWhitespace(getParam("key"))
- << "</citation>";
- return 0;
-}
-
-
-int InsetCitation::textString(Buffer const & buf, odocstream & os,
- OutputParams const & op) const
-{
- return plaintext(buf, os, op);
-}
-
-
-// Have to overwrite the default InsetCommand method in order to check that
-// the \cite command is valid. Eg, the user has natbib enabled, inputs some
-// citations and then changes his mind, turning natbib support off. The output
-// should revert to \cite[]{}
-int InsetCitation::latex(Buffer const & buffer, odocstream & os,
- OutputParams const &) const
-{
- biblio::CiteEngine cite_engine = buffer.params().getEngine();
- // FIXME UNICODE
- docstring const cite_str = from_utf8(
- biblio::asValidLatexCommand(getCmdName(), cite_engine));
-
- os << "\\" << cite_str;
-
- docstring const & before = getParam("before");
- docstring const & after = getParam("after");
- if (!before.empty() && cite_engine != biblio::ENGINE_BASIC)
- os << '[' << before << "][" << after << ']';
- else if (!after.empty())
- os << '[' << after << ']';
-
- os << '{' << cleanupWhitespace(getParam("key")) << '}';
-
- return 0;
-}
-
-
-void InsetCitation::validate(LaTeXFeatures & features) const
-{
- switch (features.bufferParams().getEngine()) {
- case biblio::ENGINE_BASIC:
- break;
- case biblio::ENGINE_NATBIB_AUTHORYEAR:
- case biblio::ENGINE_NATBIB_NUMERICAL:
- features.require("natbib");
- break;
- case biblio::ENGINE_JURABIB:
- features.require("jurabib");
- break;
- }
-}
-
-
-void InsetCitation::replaceContents(string const & from, string const & to)
-{
- if (tokenPos(getContents(), ',', from) != -1) {
- vector<string> items = getVectorFromString(getContents());
- replace(items.begin(), items.end(), from, to);
- setContents(getStringFromVector(items));
- }
-}
-
-
-} // namespace lyx
+++ /dev/null
-// -*- C++ -*-
-/**
- * \file InsetCitation.h
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author Angus Leeming
- * \author Herbert Voß
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#ifndef INSET_CITE_H
-#define INSET_CITE_H
-
-
-#include "InsetCommand.h"
-
-#include "frontends/controllers/biblio.h"
-
-
-namespace lyx {
-
-
-/** Used to insert citations
- */
-class InsetCitation : public InsetCommand {
-public:
- ///
- InsetCitation(InsetCommandParams const &);
- ///
- docstring const getScreenLabel(Buffer const &) const;
- ///
- EDITABLE editable() const { return IS_EDITABLE; }
- ///
- InsetBase::Code lyxCode() const { return InsetBase::CITE_CODE; }
- ///
- int latex(Buffer const &, odocstream &,
- OutputParams const &) const;
- ///
- int plaintext(Buffer const &, odocstream &,
- OutputParams const &) const;
- ///
- int docbook(Buffer const &, odocstream &,
- OutputParams const &) const;
- /// the string that is passed to the TOC
- virtual int textString(Buffer const &, odocstream &,
- OutputParams const &) const;
- ///
- void validate(LaTeXFeatures &) const;
- ///
- void replaceContents(std::string const & from, std::string const & to);
-
-private:
- virtual std::auto_ptr<InsetBase> doClone() const
- {
- return std::auto_ptr<InsetBase>(new InsetCitation(params()));
- }
-
- /// This function does the donkey work of creating the pretty label
- docstring const generateLabel(Buffer const &) const;
-
- class Cache {
- public:
- ///
- Cache() : engine(biblio::ENGINE_BASIC), params("cite") {}
- ///
- biblio::CiteEngine engine;
- ///
- InsetCommandParams params;
- ///
- docstring generated_label;
- ///
- docstring screen_label;
- };
- ///
- mutable Cache cache;
-};
-
-
-} // namespace lyx
-
-#endif // INSET_CITE_H
+++ /dev/null
-/**
- * \file InsetPagebreak.cpp
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author André Pönitz
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#include <config.h>
-
-#include "InsetPagebreak.h"
-
-#include "debug.h"
-#include "gettext.h"
-#include "LColor.h"
-#include "lyxtext.h"
-#include "metricsinfo.h"
-#include "outputparams.h"
-#include "TextMetrics.h"
-
-#include "frontends/FontMetrics.h"
-#include "frontends/Painter.h"
-
-
-namespace lyx {
-
-using frontend::Painter;
-
-using std::endl;
-using std::ostream;
-
-
-void InsetPagebreak::read(Buffer const &, LyXLex &)
-{
- /* Nothing to read */
-}
-
-
-void InsetPagebreak::write(Buffer const &, ostream & os) const
-{
- os << "\n" << getCmdName() << '\n';
-}
-
-
-bool InsetPagebreak::metrics(MetricsInfo & mi, Dimension & dim) const
-{
- dim.asc = defaultRowHeight();
- dim.des = defaultRowHeight();
- dim.wid = mi.base.textwidth;
- bool const changed = dim_ != dim;
- dim_ = dim;
- return changed;
-}
-
-
-void InsetPagebreak::draw(PainterInfo & pi, int x, int y) const
-{
- LyXFont font;
- font.setColor(LColor::pagebreak);
- font.decSize();
-
- int w = 0;
- int a = 0;
- int d = 0;
- theFontMetrics(font).rectText(insetLabel(), w, a, d);
-
- int const text_start = int(x + (dim_.wid - w) / 2);
- int const text_end = text_start + w;
-
- pi.pain.rectText(text_start, y + d, insetLabel(), font,
- LColor::none, LColor::none);
-
- pi.pain.line(x, y, text_start, y,
- LColor::pagebreak, Painter::line_onoffdash);
- pi.pain.line(text_end, y, int(x + dim_.wid), y,
- LColor::pagebreak, Painter::line_onoffdash);
-}
-
-
-int InsetPagebreak::latex(Buffer const &, odocstream & os,
- OutputParams const &) const
-{
- os << from_ascii(getCmdName()) << "{}";
- return 0;
-}
-
-
-int InsetPagebreak::plaintext(Buffer const &, odocstream & os,
- OutputParams const &) const
-{
- os << '\n';
- return PLAINTEXT_NEWLINE;
-}
-
-
-int InsetPagebreak::docbook(Buffer const &, odocstream & os,
- OutputParams const &) const
-{
- os << '\n';
- return 0;
-}
-
-
-} // namespace lyx
+++ /dev/null
-// -*- C++ -*-
-/**
- * \file InsetPagebreak.h
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author André Pönitz
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#ifndef INSET_PAGEBREAK_H
-#define INSET_PAGEBREAK_H
-
-
-#include "Inset.h"
-#include "gettext.h"
-
-
-namespace lyx {
-
-class InsetPagebreak : public InsetOld {
-public:
- InsetPagebreak() {}
-
- InsetBase::Code lyxCode() const { return InsetBase::PAGEBREAK_CODE; }
-
- bool metrics(MetricsInfo &, Dimension &) const;
-
- void draw(PainterInfo & pi, int x, int y) const;
-
- int latex(Buffer const &, odocstream &,
- OutputParams const &) const;
-
- int plaintext(Buffer const &, odocstream &,
- OutputParams const &) const;
-
- int docbook(Buffer const &, odocstream &,
- OutputParams const &) const;
-
- void read(Buffer const &, LyXLex & lex);
-
- virtual void write(Buffer const & buf, std::ostream & os) const;
- /// We don't need \begin_inset and \end_inset
- bool directWrite() const { return true; }
-
- bool display() const { return true; }
-
- virtual docstring insetLabel() const { return _("Page Break"); }
-
- virtual std::string getCmdName() const { return "\\newpage"; }
-
-private:
- virtual std::auto_ptr<InsetBase> doClone() const
- {
- return std::auto_ptr<InsetBase>(new InsetPagebreak);
- }
-};
-
-
-class InsetClearPage : public InsetPagebreak {
-public:
- InsetClearPage() {}
-
- docstring insetLabel() const { return _("Clear Page"); }
-
- std::string getCmdName() const { return "\\clearpage"; }
-
-private:
- virtual std::auto_ptr<InsetBase> doClone() const
- {
- return std::auto_ptr<InsetBase>(new InsetClearPage);
- }
-};
-
-
-class InsetClearDoublePage : public InsetPagebreak {
-public:
- InsetClearDoublePage() {}
-
- docstring insetLabel() const { return _("Clear Double Page"); }
-
- std::string getCmdName() const { return "\\cleardoublepage"; }
-
-private:
- virtual std::auto_ptr<InsetBase> doClone() const
- {
- return std::auto_ptr<InsetBase>(new InsetClearDoublePage);
- }
-};
-
-} // namespace lyx
-
-#endif // INSET_PAGEBREAK_H
--- /dev/null
+/**
+ * \file InsetPagebreak.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "InsetPagebreak.h"
+
+#include "debug.h"
+#include "gettext.h"
+#include "LColor.h"
+#include "lyxtext.h"
+#include "metricsinfo.h"
+#include "outputparams.h"
+#include "TextMetrics.h"
+
+#include "frontends/FontMetrics.h"
+#include "frontends/Painter.h"
+
+
+namespace lyx {
+
+using frontend::Painter;
+
+using std::endl;
+using std::ostream;
+
+
+void InsetPagebreak::read(Buffer const &, LyXLex &)
+{
+ /* Nothing to read */
+}
+
+
+void InsetPagebreak::write(Buffer const &, ostream & os) const
+{
+ os << "\n" << getCmdName() << '\n';
+}
+
+
+bool InsetPagebreak::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+ dim.asc = defaultRowHeight();
+ dim.des = defaultRowHeight();
+ dim.wid = mi.base.textwidth;
+ bool const changed = dim_ != dim;
+ dim_ = dim;
+ return changed;
+}
+
+
+void InsetPagebreak::draw(PainterInfo & pi, int x, int y) const
+{
+ LyXFont font;
+ font.setColor(LColor::pagebreak);
+ font.decSize();
+
+ int w = 0;
+ int a = 0;
+ int d = 0;
+ theFontMetrics(font).rectText(insetLabel(), w, a, d);
+
+ int const text_start = int(x + (dim_.wid - w) / 2);
+ int const text_end = text_start + w;
+
+ pi.pain.rectText(text_start, y + d, insetLabel(), font,
+ LColor::none, LColor::none);
+
+ pi.pain.line(x, y, text_start, y,
+ LColor::pagebreak, Painter::line_onoffdash);
+ pi.pain.line(text_end, y, int(x + dim_.wid), y,
+ LColor::pagebreak, Painter::line_onoffdash);
+}
+
+
+int InsetPagebreak::latex(Buffer const &, odocstream & os,
+ OutputParams const &) const
+{
+ os << from_ascii(getCmdName()) << "{}";
+ return 0;
+}
+
+
+int InsetPagebreak::plaintext(Buffer const &, odocstream & os,
+ OutputParams const &) const
+{
+ os << '\n';
+ return PLAINTEXT_NEWLINE;
+}
+
+
+int InsetPagebreak::docbook(Buffer const &, odocstream & os,
+ OutputParams const &) const
+{
+ os << '\n';
+ return 0;
+}
+
+
+} // namespace lyx
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file InsetPagebreak.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef INSET_PAGEBREAK_H
+#define INSET_PAGEBREAK_H
+
+
+#include "Inset.h"
+#include "gettext.h"
+
+
+namespace lyx {
+
+class InsetPagebreak : public InsetOld {
+public:
+ InsetPagebreak() {}
+
+ InsetBase::Code lyxCode() const { return InsetBase::PAGEBREAK_CODE; }
+
+ bool metrics(MetricsInfo &, Dimension &) const;
+
+ void draw(PainterInfo & pi, int x, int y) const;
+
+ int latex(Buffer const &, odocstream &,
+ OutputParams const &) const;
+
+ int plaintext(Buffer const &, odocstream &,
+ OutputParams const &) const;
+
+ int docbook(Buffer const &, odocstream &,
+ OutputParams const &) const;
+
+ void read(Buffer const &, LyXLex & lex);
+
+ virtual void write(Buffer const & buf, std::ostream & os) const;
+ /// We don't need \begin_inset and \end_inset
+ bool directWrite() const { return true; }
+
+ bool display() const { return true; }
+
+ virtual docstring insetLabel() const { return _("Page Break"); }
+
+ virtual std::string getCmdName() const { return "\\newpage"; }
+
+private:
+ virtual std::auto_ptr<InsetBase> doClone() const
+ {
+ return std::auto_ptr<InsetBase>(new InsetPagebreak);
+ }
+};
+
+
+class InsetClearPage : public InsetPagebreak {
+public:
+ InsetClearPage() {}
+
+ docstring insetLabel() const { return _("Clear Page"); }
+
+ std::string getCmdName() const { return "\\clearpage"; }
+
+private:
+ virtual std::auto_ptr<InsetBase> doClone() const
+ {
+ return std::auto_ptr<InsetBase>(new InsetClearPage);
+ }
+};
+
+
+class InsetClearDoublePage : public InsetPagebreak {
+public:
+ InsetClearDoublePage() {}
+
+ docstring insetLabel() const { return _("Clear Double Page"); }
+
+ std::string getCmdName() const { return "\\cleardoublepage"; }
+
+private:
+ virtual std::auto_ptr<InsetBase> doClone() const
+ {
+ return std::auto_ptr<InsetBase>(new InsetClearDoublePage);
+ }
+};
+
+} // namespace lyx
+
+#endif // INSET_PAGEBREAK_H
--- /dev/null
+/**
+ * \file CommandInset.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "CommandInset.h"
+#include "MathArray.h"
+#include "MathStream.h"
+#include "dispatchresult.h"
+#include "funcrequest.h"
+
+#include <sstream>
+
+
+namespace lyx {
+
+using std::auto_ptr;
+using std::string;
+
+CommandInset::CommandInset(docstring const & name)
+ : InsetMathNest(2), name_(name), set_label_(false)
+{
+ lock_ = true;
+}
+
+
+auto_ptr<InsetBase> CommandInset::doClone() const
+{
+ return auto_ptr<InsetBase>(new CommandInset(*this));
+}
+
+
+bool CommandInset::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+ if (!set_label_) {
+ set_label_ = true;
+ button_.update(screenLabel(), true);
+ }
+ button_.metrics(mi, dim);
+ if (dim_ == dim)
+ return false;
+ dim_ = dim;
+ return true;
+}
+
+
+InsetBase * CommandInset::editXY(LCursor & cur, int /*x*/, int /*y*/)
+{
+ edit(cur, true);
+ return this;
+}
+
+
+void CommandInset::draw(PainterInfo & pi, int x, int y) const
+{
+ button_.draw(pi, x, y);
+ setPosCache(pi, x, y);
+}
+
+
+void CommandInset::write(WriteStream & os) const
+{
+ os << '\\' << name_.c_str();
+ if (cell(1).size())
+ os << '[' << cell(1) << ']';
+ os << '{' << cell(0) << '}';
+}
+
+
+docstring const CommandInset::screenLabel() const
+{
+ return name_;
+}
+
+} // namespace lyx
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file CommandInset.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+
+#ifndef COMMAND_INSET_H
+#define COMMAND_INSET_H
+
+#include "InsetMathNest.h"
+
+#include "insets/RenderButton.h"
+
+
+namespace lyx {
+
+
+/// Inset for things like \name[options]{contents}
+class CommandInset : public InsetMathNest {
+public:
+ ///
+ explicit CommandInset(docstring const & name);
+ ///
+ bool metrics(MetricsInfo & mi, Dimension & dim) const;
+ ///
+ void draw(PainterInfo & pi, int x, int y) const;
+ ///
+ InsetBase * editXY(LCursor &, int, int);
+ ///
+ void write(WriteStream & os) const;
+ //
+ // void infoize(odocstream & os) const;
+ ///
+ virtual docstring const screenLabel() const;
+ ///
+ docstring const & commandname() const { return name_; }
+private:
+ virtual std::auto_ptr<InsetBase> doClone() const;
+
+ ///
+ docstring name_;
+ ///
+ mutable bool set_label_;
+ ///
+ mutable RenderButton button_;
+};
+
+
+} // namespace lyx
+
+#endif
+++ /dev/null
-/**
- * \file CommandInset.cpp
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author André Pönitz
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#include <config.h>
-
-#include "CommandInset.h"
-#include "MathArray.h"
-#include "MathStream.h"
-#include "dispatchresult.h"
-#include "funcrequest.h"
-
-#include <sstream>
-
-
-namespace lyx {
-
-using std::auto_ptr;
-using std::string;
-
-CommandInset::CommandInset(docstring const & name)
- : InsetMathNest(2), name_(name), set_label_(false)
-{
- lock_ = true;
-}
-
-
-auto_ptr<InsetBase> CommandInset::doClone() const
-{
- return auto_ptr<InsetBase>(new CommandInset(*this));
-}
-
-
-bool CommandInset::metrics(MetricsInfo & mi, Dimension & dim) const
-{
- if (!set_label_) {
- set_label_ = true;
- button_.update(screenLabel(), true);
- }
- button_.metrics(mi, dim);
- if (dim_ == dim)
- return false;
- dim_ = dim;
- return true;
-}
-
-
-InsetBase * CommandInset::editXY(LCursor & cur, int /*x*/, int /*y*/)
-{
- edit(cur, true);
- return this;
-}
-
-
-void CommandInset::draw(PainterInfo & pi, int x, int y) const
-{
- button_.draw(pi, x, y);
- setPosCache(pi, x, y);
-}
-
-
-void CommandInset::write(WriteStream & os) const
-{
- os << '\\' << name_.c_str();
- if (cell(1).size())
- os << '[' << cell(1) << ']';
- os << '{' << cell(0) << '}';
-}
-
-
-docstring const CommandInset::screenLabel() const
-{
- return name_;
-}
-
-} // namespace lyx
+++ /dev/null
-// -*- C++ -*-
-/**
- * \file CommandInset.h
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author André Pönitz
- *
- * Full author contact details are available in file CREDITS.
- */
-
-
-#ifndef COMMAND_INSET_H
-#define COMMAND_INSET_H
-
-#include "InsetMathNest.h"
-
-#include "insets/RenderButton.h"
-
-
-namespace lyx {
-
-
-/// Inset for things like \name[options]{contents}
-class CommandInset : public InsetMathNest {
-public:
- ///
- explicit CommandInset(docstring const & name);
- ///
- bool metrics(MetricsInfo & mi, Dimension & dim) const;
- ///
- void draw(PainterInfo & pi, int x, int y) const;
- ///
- InsetBase * editXY(LCursor &, int, int);
- ///
- void write(WriteStream & os) const;
- //
- // void infoize(odocstream & os) const;
- ///
- virtual docstring const screenLabel() const;
- ///
- docstring const & commandname() const { return name_; }
-private:
- virtual std::auto_ptr<InsetBase> doClone() const;
-
- ///
- docstring name_;
- ///
- mutable bool set_label_;
- ///
- mutable RenderButton button_;
-};
-
-
-} // namespace lyx
-
-#endif
+++ /dev/null
-/**
- * \file MathMacro.cpp
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author Alejandro Aguilar Sierra
- * \author André Pönitz
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#include <config.h>
-
-#include "MathMacro.h"
-#include "MathSupport.h"
-#include "MathExtern.h"
-#include "MathStream.h"
-
-#include "buffer.h"
-#include "cursor.h"
-#include "debug.h"
-#include "BufferView.h"
-#include "LaTeXFeatures.h"
-#include "frontends/Painter.h"
-
-
-namespace lyx {
-
-using std::string;
-using std::max;
-using std::auto_ptr;
-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)
-{}
-
-
-auto_ptr<InsetBase> MathMacro::doClone() const
-{
- return auto_ptr<InsetBase>(new MathMacro(*this));
-}
-
-
-docstring MathMacro::name() const
-{
- return name_;
-}
-
-
-void MathMacro::cursorPos(BufferView const & bv,
- CursorSlice const & sl, bool boundary, int & x, int & y) const
-{
- // We may have 0 arguments, but InsetMathNest requires at least one.
- if (nargs() > 0)
- InsetMathNest::cursorPos(bv, sl, boundary, x, y);
-}
-
-
-bool MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
-{
- if (!MacroTable::globalMacros().has(name())) {
- mathed_string_dim(mi.base.font, "Unknown: " + name(), dim);
- } else {
- 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)
- return false;
- dim_ = dim;
- return true;
-}
-
-
-void MathMacro::draw(PainterInfo & pi, int x, int y) const
-{
- if (!MacroTable::globalMacros().has(name())) {
- // FIXME UNICODE
- drawStrRed(pi, x, y, "Unknown: " + name());
- } else {
- 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;
- 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 {
- MacroTable::globalMacros().get(name()).lock();
- expanded_.draw(pi, x, y);
- MacroTable::globalMacros().get(name()).unlock();
- }
- }
- drawMarkers2(pi, x, y);
-}
-
-
-void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const
-{
- // We may have 0 arguments, but InsetMathNest requires at least one.
- if (nargs() > 0)
- InsetMathNest::drawSelection(pi, x, y);
-}
-
-
-void MathMacro::validate(LaTeXFeatures & features) const
-{
- if (name() == "binom" || name() == "mathcircumflex")
- features.require(to_utf8(name()));
-}
-
-
-InsetBase * MathMacro::editXY(LCursor & cur, int x, int y)
-{
- // We may have 0 arguments, but InsetMathNest requires at least one.
- if (nargs() > 0) {
- // Prevent crash due to cold coordcache
- // FIXME: This is only a workaround, the call of
- // InsetMathNest::editXY is correct. The correct fix would
- // ensure that the coordcache of the arguments is valid.
- if (!editing(&cur.bv())) {
- edit(cur, true);
- return this;
- }
- return InsetMathNest::editXY(cur, x, y);
- }
- return this;
-}
-
-
-bool MathMacro::idxFirst(LCursor & cur) const
-{
- cur.updateFlags(Update::Force);
- return InsetMathNest::idxFirst(cur);
-}
-
-
-bool MathMacro::idxLast(LCursor & cur) const
-{
- cur.updateFlags(Update::Force);
- return InsetMathNest::idxLast(cur);
-}
-
-
-bool MathMacro::notifyCursorLeaves(LCursor & cur)
-{
- cur.updateFlags(Update::Force);
- return InsetMathNest::notifyCursorLeaves(cur);
-}
-
-
-void MathMacro::maple(MapleStream & os) const
-{
- updateExpansion();
- lyx::maple(expanded_, os);
-}
-
-
-void MathMacro::mathmlize(MathStream & os) const
-{
- updateExpansion();
- lyx::mathmlize(expanded_, os);
-}
-
-
-void MathMacro::octave(OctaveStream & os) const
-{
- updateExpansion();
- lyx::octave(expanded_, os);
-}
-
-
-void MathMacro::updateExpansion() const
-{
- //expanded_.substitute(*this);
-}
-
-
-void MathMacro::infoize(odocstream & os) const
-{
- os << "Macro: " << name();
-}
-
-
-void MathMacro::infoize2(odocstream & os) const
-{
- os << "Macro: " << name();
-
-}
-
-
-} // namespace lyx
+++ /dev/null
-// -*- C++ -*-
-/**
- * \file MathMacro.h
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author Alejandro Aguilar Sierra
- * \author André Pönitz
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#ifndef MATH_MACRO_H
-#define MATH_MACRO_H
-
-#include "InsetMathNest.h"
-#include "MathArray.h"
-#include "InsetMathNest.h"
-#include "MathMacroTable.h"
-
-
-namespace lyx {
-
-
-/// This class contains the data for a macro.
-class MathMacro : public InsetMathNest {
-public:
- /// A macro can be built from an existing template
- MathMacro(docstring const & name, int numargs);
- ///
- void draw(PainterInfo & pi, int x, int y) const;
- ///
- void drawExpanded(PainterInfo & pi, int x, int y) const;
- /// draw selection background
- void drawSelection(PainterInfo & pi, int x, int y) const;
- /// draw decorations.
- void drawDecoration(PainterInfo & pi, int x, int y) const
- { drawMarkers2(pi, x, y); }
- ///
- bool metrics(MetricsInfo & mi, Dimension & dim) const;
- /// get cursor position
- void cursorPos(BufferView const & bv, CursorSlice const & sl,
- bool boundary, int & x, int & y) const;
- ///
- InsetBase * editXY(LCursor & cur, int x, int y);
- /// target pos when we enter the inset from the left by pressing "Right"
- bool idxFirst(LCursor &) const;
- /// target pos when we enter the inset from the right by pressing "Left"
- bool idxLast(LCursor &) const;
- ///
- virtual bool notifyCursorLeaves(LCursor &);
- ///
- docstring name() const;
- ///
- void setExpansion(MathArray const & exp, MathArray const & args) const;
-
- ///
- void validate(LaTeXFeatures &) const;
-
- ///
- void maple(MapleStream &) const;
- ///
- void mathmlize(MathStream &) const;
- ///
- void octave(OctaveStream &) const;
- ///
- void infoize(odocstream &) const;
- ///
- void infoize2(odocstream &) const;
-
-private:
- virtual std::auto_ptr<InsetBase> doClone() const;
- ///
- void updateExpansion() const;
- ///
- void expand() const;
-
- /// name of macro
- docstring name_;
- /// the unexpanded macro defintition
- mutable MathArray tmpl_;
- /// the macro substituted with our args
- mutable MathArray expanded_;
-};
-
-
-
-
-} // namespace lyx
-#endif
--- /dev/null
+/**
+ * \file MathArray.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "MathArray.h"
+#include "InsetMathFont.h"
+#include "InsetMathScript.h"
+#include "MathMacro.h"
+#include "MathMacroTable.h"
+#include "MathStream.h"
+#include "MathSupport.h"
+#include "ReplaceData.h"
+
+#include "BufferView.h"
+#include "buffer.h"
+#include "cursor.h"
+#include "debug.h"
+#include "LColor.h"
+
+#include "frontends/FontMetrics.h"
+#include "frontends/Painter.h"
+
+#include <boost/assert.hpp>
+
+
+namespace lyx {
+
+using std::abs;
+using std::endl;
+using std::min;
+using std::ostringstream;
+using std::string;
+using std::vector;
+
+
+MathArray::MathArray(const_iterator from, const_iterator to)
+ : base_type(from, to)
+{}
+
+
+MathAtom & MathArray::operator[](pos_type pos)
+{
+ BOOST_ASSERT(pos < size());
+ return base_type::operator[](pos);
+}
+
+
+MathAtom const & MathArray::operator[](pos_type pos) const
+{
+ BOOST_ASSERT(pos < size());
+ return base_type::operator[](pos);
+}
+
+
+void MathArray::insert(size_type pos, MathAtom const & t)
+{
+ base_type::insert(begin() + pos, t);
+}
+
+
+void MathArray::insert(size_type pos, MathArray const & ar)
+{
+ BOOST_ASSERT(pos <= size());
+ base_type::insert(begin() + pos, ar.begin(), ar.end());
+}
+
+
+void MathArray::append(MathArray const & ar)
+{
+ insert(size(), ar);
+}
+
+
+void MathArray::erase(size_type pos)
+{
+ if (pos < size())
+ erase(pos, pos + 1);
+}
+
+
+void MathArray::erase(iterator pos1, iterator pos2)
+{
+ base_type::erase(pos1, pos2);
+}
+
+
+void MathArray::erase(iterator pos)
+{
+ base_type::erase(pos);
+}
+
+
+void MathArray::erase(size_type pos1, size_type pos2)
+{
+ base_type::erase(begin() + pos1, begin() + pos2);
+}
+
+
+void MathArray::dump2() const
+{
+ odocstringstream os;
+ NormalStream ns(os);
+ for (const_iterator it = begin(); it != end(); ++it)
+ ns << *it << ' ';
+ lyxerr << to_utf8(os.str());
+}
+
+
+void MathArray::dump() const
+{
+ odocstringstream os;
+ NormalStream ns(os);
+ for (const_iterator it = begin(); it != end(); ++it)
+ ns << '<' << *it << '>';
+ lyxerr << to_utf8(os.str());
+}
+
+
+void MathArray::validate(LaTeXFeatures & features) const
+{
+ for (const_iterator it = begin(); it != end(); ++it)
+ (*it)->validate(features);
+}
+
+
+bool MathArray::match(MathArray const & ar) const
+{
+ return size() == ar.size() && matchpart(ar, 0);
+}
+
+
+bool MathArray::matchpart(MathArray const & ar, pos_type pos) const
+{
+ if (size() < ar.size() + pos)
+ return false;
+ const_iterator it = begin() + pos;
+ for (const_iterator jt = ar.begin(); jt != ar.end(); ++jt, ++it)
+ if (asString(*it) != asString(*jt))
+ return false;
+ return true;
+}
+
+
+void MathArray::replace(ReplaceData & rep)
+{
+ for (size_type i = 0; i < size(); ++i) {
+ if (find1(rep.from, i)) {
+ // match found
+ lyxerr << "match found!" << endl;
+ erase(i, i + rep.from.size());
+ insert(i, rep.to);
+ }
+ }
+
+#ifdef WITH_WARNINGS
+#warning temporarily disabled
+ // for (const_iterator it = begin(); it != end(); ++it)
+ // it->nucleus()->replace(rep);
+#endif
+}
+
+
+bool MathArray::find1(MathArray const & ar, size_type pos) const
+{
+ lyxerr << "finding '" << ar << "' in '" << *this << "'" << endl;
+ for (size_type i = 0, n = ar.size(); i < n; ++i)
+ if (asString(operator[](pos + i)) != asString(ar[i]))
+ return false;
+ return true;
+}
+
+
+MathArray::size_type MathArray::find(MathArray const & ar) const
+{
+ for (int i = 0, last = size() - ar.size(); i < last; ++i)
+ if (find1(ar, i))
+ return i;
+ return size();
+}
+
+
+MathArray::size_type MathArray::find_last(MathArray const & ar) const
+{
+ for (int i = size() - ar.size(); i >= 0; --i)
+ if (find1(ar, i))
+ return i;
+ return size();
+}
+
+
+bool MathArray::contains(MathArray const & ar) const
+{
+ if (find(ar) != size())
+ return true;
+ for (const_iterator it = begin(); it != end(); ++it)
+ if ((*it)->contains(ar))
+ return true;
+ return false;
+}
+
+
+void MathArray::touch() const
+{
+}
+
+
+bool MathArray::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+ dim = dim_;
+ metrics(mi);
+ if (dim_ == dim)
+ return false;
+ dim = dim_;
+ return true;
+}
+
+
+namespace {
+
+bool isInside(DocIterator const & it, MathArray const & ar,
+ pos_type p1, pos_type p2)
+{
+ for (size_t i = 0; i != it.depth(); ++i) {
+ CursorSlice const & sl = it[i];
+ if (sl.inset().inMathed() && &sl.cell() == &ar)
+ return p1 <= sl.pos() && sl.pos() < p2;
+ }
+ return false;
+}
+
+}
+
+
+
+void MathArray::metrics(MetricsInfo & mi) const
+{
+ frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
+ dim_ = fm.dimension('I');
+ int xascent = fm.dimension('x').ascent();
+ if (xascent >= dim_.asc)
+ xascent = (2 * dim_.asc) / 3;
+ minasc_ = xascent;
+ mindes_ = (3 * xascent) / 4;
+ slevel_ = (4 * xascent) / 5;
+ sshift_ = xascent / 4;
+ kerning_ = 0;
+
+ if (empty())
+ return;
+
+ dim_.asc = 0;
+ dim_.wid = 0;
+ Dimension d;
+ //BufferView & bv = *mi.base.bv;
+ //Buffer const & buf = *bv.buffer();
+ for (size_t i = 0, n = size(); i != n; ++i) {
+ MathAtom const & at = operator[](i);
+#if 0
+ MathMacro const * mac = at->asMacro();
+ if (mac && buf.hasMacro(mac->name())) {
+ MacroData const & tmpl = buf.getMacro(mac->name());
+ int numargs = tmpl.numargs();
+ if (i + numargs > n)
+ numargs = n - i - 1;
+ lyxerr << "metrics:found macro: " << mac->name()
+ << " numargs: " << numargs << endl;
+ if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) {
+ MathArray args(begin() + i + 1, begin() + i + numargs + 1);
+ MathArray exp;
+ tmpl.expand(args, exp);
+ mac->setExpansion(exp, args);
+ mac->metricsExpanded(mi, d);
+ dim_.wid += mac->widthExpanded();
+ i += numargs;
+ continue;
+ }
+ }
+#endif
+ at->metrics(mi, d);
+ dim_ += d;
+ if (i == n - 1)
+ kerning_ = at->kerning();
+ }
+}
+
+
+void MathArray::draw(PainterInfo & pi, int x, int y) const
+{
+ //lyxerr << "MathArray::draw: x: " << x << " y: " << y << endl;
+ BufferView & bv = *pi.base.bv;
+ setXY(bv, x, y);
+
+ if (empty()) {
+ pi.pain.rectangle(x, y - ascent(), width(), height(), LColor::mathline);
+ return;
+ }
+
+ // don't draw outside the workarea
+ if (y + descent() <= 0
+ || y - ascent() >= bv.workHeight()
+ || x + width() <= 0
+ || x >= bv. workWidth())
+ return;
+
+ for (size_t i = 0, n = size(); i != n; ++i) {
+ MathAtom const & at = operator[](i);
+#if 0
+ Buffer const & buf = bv.buffer();
+ // special macro handling
+ MathMacro const * mac = at->asMacro();
+ if (mac && buf.hasMacro(mac->name())) {
+ MacroData const & tmpl = buf.getMacro(mac->name());
+ int numargs = tmpl.numargs();
+ if (i + numargs > n)
+ numargs = n - i - 1;
+ if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) {
+ mac->drawExpanded(pi, x, y);
+ x += mac->widthExpanded();
+ i += numargs;
+ continue;
+ }
+ }
+#endif
+ bv.coordCache().insets().add(at.nucleus(), x, y);
+ at->drawSelection(pi, x, y);
+ at->draw(pi, x, y);
+ x += at->width();
+ }
+}
+
+
+void MathArray::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
+{
+ dim.clear();
+ Dimension d;
+ for (const_iterator it = begin(); it != end(); ++it) {
+ (*it)->metricsT(mi, d);
+ dim += d;
+ }
+}
+
+
+void MathArray::drawT(TextPainter & pain, int x, int y) const
+{
+ //lyxerr << "x: " << x << " y: " << y << ' ' << pain.workAreaHeight() << endl;
+
+ // FIXME: Abdel 16/10/2006
+ // This drawT() method is never used, this is dead code.
+
+ for (const_iterator it = begin(), et = end(); it != et; ++it) {
+ (*it)->drawT(pain, x, y);
+ //x += (*it)->width_;
+ x += 2;
+ }
+}
+
+
+int MathArray::pos2x(size_type pos) const
+{
+ return pos2x(pos, 0);
+}
+
+
+int MathArray::pos2x(size_type pos, int glue) const
+{
+ int x = 0;
+ size_type target = min(pos, size());
+ for (size_type i = 0; i < target; ++i) {
+ const_iterator it = begin() + i;
+ if ((*it)->getChar() == ' ')
+ x += glue;
+ //lyxerr << "char: " << (*it)->getChar()
+ // << "width: " << (*it)->width() << std::endl;
+ x += (*it)->width();
+ }
+ return x;
+}
+
+
+MathArray::size_type MathArray::x2pos(int targetx) const
+{
+ return x2pos(targetx, 0);
+}
+
+
+MathArray::size_type MathArray::x2pos(int targetx, int glue) const
+{
+ const_iterator it = begin();
+ int lastx = 0;
+ int currx = 0;
+ // find first position after targetx
+ for (; currx < targetx && it < end(); ++it) {
+ lastx = currx;
+ if ((*it)->getChar() == ' ')
+ currx += glue;
+ currx += (*it)->width();
+ }
+
+ /**
+ * If we are not at the beginning of the array, go to the left
+ * of the inset if one of the following two condition holds:
+ * - the current inset is editable (so that the cursor tip is
+ * deeper than us): in this case, we want all intermediate
+ * cursor slices to be before insets;
+ * - the mouse is closer to the left side of the inset than to
+ * the right one.
+ * See bug 1918 for details.
+ **/
+ if (it != begin() && currx >= targetx
+ && ((*boost::prior(it))->asNestInset()
+ || abs(lastx - targetx) < abs(currx - targetx))) {
+ --it;
+ }
+
+ return it - begin();
+}
+
+
+int MathArray::dist(BufferView const & bv, int x, int y) const
+{
+ int xx = 0;
+ int yy = 0;
+
+ const int xo_ = xo(bv);
+ const int yo_ = yo(bv);
+
+ if (x < xo_)
+ xx = xo_ - x;
+ else if (x > xo_ + width())
+ xx = x - xo_ - width();
+
+ if (y < yo_ - ascent())
+ yy = yo_ - ascent() - y;
+ else if (y > yo_ + descent())
+ yy = y - yo_ - descent();
+
+ return xx + yy;
+}
+
+
+void MathArray::setXY(BufferView & bv, int x, int y) const
+{
+ //lyxerr << "setting position cache for MathArray " << this << std::endl;
+ bv.coordCache().arrays().add(this, x, y);
+}
+
+
+int MathArray::xo(BufferView const & bv) const
+{
+ return bv.coordCache().getArrays().x(this);
+}
+
+
+int MathArray::yo(BufferView const & bv) const
+{
+ return bv.coordCache().getArrays().y(this);
+}
+
+
+std::ostream & operator<<(std::ostream & os, MathArray const & ar)
+{
+ odocstringstream oss;
+ NormalStream ns(oss);
+ ns << ar;
+ return os << to_utf8(oss.str());
+}
+
+
+odocstream & operator<<(odocstream & os, MathArray const & ar)
+{
+ NormalStream ns(os);
+ ns << ar;
+ return os;
+}
+
+
+} // namespace lyx
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file MathArray.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Alejandro Aguilar Sierra
+ * \author André Pönitz
+ * \author Lars Gullik Bjønnes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef MATH_DATA_H
+#define MATH_DATA_H
+
+#include <vector>
+
+#include "MathAtom.h"
+#include "dimension.h"
+
+#include "support/docstream.h"
+
+
+namespace lyx {
+
+class BufferView;
+class LaTeXFeatures;
+class ReplaceData;
+class MetricsInfo;
+class PainterInfo;
+class TextMetricsInfo;
+class TextPainter;
+
+
+class MathArray : private std::vector<MathAtom> {
+public:
+ /// re-use inhertited stuff
+ typedef std::vector<MathAtom> base_type;
+ using base_type::const_iterator;
+ using base_type::iterator;
+ using base_type::size_type;
+ using base_type::difference_type;
+ using base_type::size;
+ using base_type::empty;
+ using base_type::clear;
+ using base_type::begin;
+ using base_type::end;
+ using base_type::push_back;
+ using base_type::pop_back;
+ using base_type::back;
+ using base_type::front;
+ ///
+ typedef size_type idx_type;
+ typedef size_type pos_type;
+
+public:
+ ///
+ MathArray() {}
+ ///
+ MathArray(const_iterator from, const_iterator to);
+ ///
+ void append(MathArray const & ar);
+
+ /// inserts single atom at position pos
+ void insert(size_type pos, MathAtom const & at);
+ /// inserts multiple atoms at position pos
+ void insert(size_type pos, MathArray const & ar);
+
+ /// erase range from pos1 to pos2
+ void erase(iterator pos1, iterator pos2);
+ /// erase single atom
+ void erase(iterator pos);
+ /// erase range from pos1 to pos2
+ void erase(size_type pos1, size_type pos2);
+ /// erase single atom
+ void erase(size_type pos);
+
+ ///
+ void dump() const;
+ ///
+ void dump2() const;
+ ///
+ void replace(ReplaceData &);
+ ///
+ void substitute(MathArray const & m);
+
+ /// looks for exact match
+ bool match(MathArray const & ar) const;
+ /// looks for inclusion match starting at pos
+ bool matchpart(MathArray const & ar, pos_type pos) const;
+ /// looks for containment, return == size mean not found
+ size_type find(MathArray const & ar) const;
+ /// looks for containment, return == size mean not found
+ size_type find_last(MathArray const & ar) const;
+ ///
+ bool contains(MathArray const & ar) const;
+ ///
+ void validate(LaTeXFeatures &) const;
+
+ /// checked write access
+ MathAtom & operator[](pos_type);
+ /// checked read access
+ MathAtom const & operator[](pos_type) const;
+ /// rebuild cached metrics information
+ void metrics(MetricsInfo & mi) const;
+ /// rebuild cached metrics information
+ bool metrics(MetricsInfo & mi, Dimension & dim) const;
+ /// redraw cell using cache metrics information
+ void draw(PainterInfo & pi, int x, int y) const;
+ /// rebuild cached metrics information
+ void metricsT(TextMetricsInfo const & mi, Dimension & dim) const;
+ /// redraw cell using cache metrics information
+ void drawT(TextPainter & pi, int x, int y) const;
+ /// mark cell for re-drawing
+ void touch() const;
+
+ /// access to cached x coordinate of last drawing
+ int xo(BufferView const & bv) const;
+ /// access to cached y coordinate of last drawing
+ int yo(BufferView const & bv) const;
+ /// access to cached x coordinate of mid point of last drawing
+ int xm(BufferView const & bv) const { return xo(bv) + dim_.wid / 2; }
+ /// access to cached y coordinate of mid point of last drawing
+ int ym(BufferView const & bv) const { return yo(bv) + (dim_.des - dim_.asc) / 2; }
+ /// write access to coordinate;
+ void setXY(BufferView & bv, int x, int y) const;
+ /// returns x coordinate of given position in the array
+ int pos2x(size_type pos) const;
+ /// returns position of given x coordinate
+ int pos2x(size_type pos, int glue) const;
+ /// returns position of given x coordinate
+ size_type x2pos(int pos) const;
+ /// returns position of given x coordinate fstarting from a certain pos
+ size_type x2pos(int targetx, int glue) const;
+ /// returns distance of this cell to the point given by x and y
+ // assumes valid position and size cache
+ int dist(BufferView const & bv, int x, int y) const;
+
+ /// ascent of this cell above the baseline
+ int ascent() const { return dim_.asc; }
+ /// descent of this cell below the baseline
+ int descent() const { return dim_.des; }
+ /// height of the cell
+ int height() const { return dim_.asc + dim_.des; }
+ /// width of this cell
+ int width() const { return dim_.wid; }
+ /// dimensions of cell
+ Dimension const & dim() const { return dim_; }
+ /// dimensions of cell
+ void setDim(Dimension const & d) const { dim_ = d; }
+ /// minimum ascent offset for superscript
+ int minasc() const { return minasc_; }
+ /// minimum descent offset for subscript
+ int mindes() const { return mindes_; }
+ /// level above/below which super/subscript should extend
+ int slevel() const { return slevel_; }
+ /// additional super/subscript shift
+ int sshift() const { return sshift_; }
+ /// superscript kerning
+ int kerning() const { return kerning_; }
+ ///
+ void swap(MathArray & ar) { base_type::swap(ar); }
+
+protected:
+ /// cached dimensions of cell
+ mutable Dimension dim_;
+ /// cached values for super/subscript placement
+ mutable int minasc_;
+ mutable int mindes_;
+ mutable int slevel_;
+ mutable int sshift_;
+ mutable int kerning_;
+
+private:
+ /// is this an exact match at this position?
+ bool find1(MathArray const & ar, size_type pos) const;
+};
+
+///
+std::ostream & operator<<(std::ostream & os, MathArray const & ar);
+///
+odocstream & operator<<(odocstream & os, MathArray const & ar);
+
+
+} // namespace lyx
+
+#endif
+++ /dev/null
-/**
- * \file MathArray.cpp
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author André Pönitz
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#include <config.h>
-
-#include "MathArray.h"
-#include "InsetMathFont.h"
-#include "InsetMathScript.h"
-#include "MathMacro.h"
-#include "MathMacroTable.h"
-#include "MathStream.h"
-#include "MathSupport.h"
-#include "ReplaceData.h"
-
-#include "BufferView.h"
-#include "buffer.h"
-#include "cursor.h"
-#include "debug.h"
-#include "LColor.h"
-
-#include "frontends/FontMetrics.h"
-#include "frontends/Painter.h"
-
-#include <boost/assert.hpp>
-
-
-namespace lyx {
-
-using std::abs;
-using std::endl;
-using std::min;
-using std::ostringstream;
-using std::string;
-using std::vector;
-
-
-MathArray::MathArray(const_iterator from, const_iterator to)
- : base_type(from, to)
-{}
-
-
-MathAtom & MathArray::operator[](pos_type pos)
-{
- BOOST_ASSERT(pos < size());
- return base_type::operator[](pos);
-}
-
-
-MathAtom const & MathArray::operator[](pos_type pos) const
-{
- BOOST_ASSERT(pos < size());
- return base_type::operator[](pos);
-}
-
-
-void MathArray::insert(size_type pos, MathAtom const & t)
-{
- base_type::insert(begin() + pos, t);
-}
-
-
-void MathArray::insert(size_type pos, MathArray const & ar)
-{
- BOOST_ASSERT(pos <= size());
- base_type::insert(begin() + pos, ar.begin(), ar.end());
-}
-
-
-void MathArray::append(MathArray const & ar)
-{
- insert(size(), ar);
-}
-
-
-void MathArray::erase(size_type pos)
-{
- if (pos < size())
- erase(pos, pos + 1);
-}
-
-
-void MathArray::erase(iterator pos1, iterator pos2)
-{
- base_type::erase(pos1, pos2);
-}
-
-
-void MathArray::erase(iterator pos)
-{
- base_type::erase(pos);
-}
-
-
-void MathArray::erase(size_type pos1, size_type pos2)
-{
- base_type::erase(begin() + pos1, begin() + pos2);
-}
-
-
-void MathArray::dump2() const
-{
- odocstringstream os;
- NormalStream ns(os);
- for (const_iterator it = begin(); it != end(); ++it)
- ns << *it << ' ';
- lyxerr << to_utf8(os.str());
-}
-
-
-void MathArray::dump() const
-{
- odocstringstream os;
- NormalStream ns(os);
- for (const_iterator it = begin(); it != end(); ++it)
- ns << '<' << *it << '>';
- lyxerr << to_utf8(os.str());
-}
-
-
-void MathArray::validate(LaTeXFeatures & features) const
-{
- for (const_iterator it = begin(); it != end(); ++it)
- (*it)->validate(features);
-}
-
-
-bool MathArray::match(MathArray const & ar) const
-{
- return size() == ar.size() && matchpart(ar, 0);
-}
-
-
-bool MathArray::matchpart(MathArray const & ar, pos_type pos) const
-{
- if (size() < ar.size() + pos)
- return false;
- const_iterator it = begin() + pos;
- for (const_iterator jt = ar.begin(); jt != ar.end(); ++jt, ++it)
- if (asString(*it) != asString(*jt))
- return false;
- return true;
-}
-
-
-void MathArray::replace(ReplaceData & rep)
-{
- for (size_type i = 0; i < size(); ++i) {
- if (find1(rep.from, i)) {
- // match found
- lyxerr << "match found!" << endl;
- erase(i, i + rep.from.size());
- insert(i, rep.to);
- }
- }
-
-#ifdef WITH_WARNINGS
-#warning temporarily disabled
- // for (const_iterator it = begin(); it != end(); ++it)
- // it->nucleus()->replace(rep);
-#endif
-}
-
-
-bool MathArray::find1(MathArray const & ar, size_type pos) const
-{
- lyxerr << "finding '" << ar << "' in '" << *this << "'" << endl;
- for (size_type i = 0, n = ar.size(); i < n; ++i)
- if (asString(operator[](pos + i)) != asString(ar[i]))
- return false;
- return true;
-}
-
-
-MathArray::size_type MathArray::find(MathArray const & ar) const
-{
- for (int i = 0, last = size() - ar.size(); i < last; ++i)
- if (find1(ar, i))
- return i;
- return size();
-}
-
-
-MathArray::size_type MathArray::find_last(MathArray const & ar) const
-{
- for (int i = size() - ar.size(); i >= 0; --i)
- if (find1(ar, i))
- return i;
- return size();
-}
-
-
-bool MathArray::contains(MathArray const & ar) const
-{
- if (find(ar) != size())
- return true;
- for (const_iterator it = begin(); it != end(); ++it)
- if ((*it)->contains(ar))
- return true;
- return false;
-}
-
-
-void MathArray::touch() const
-{
-}
-
-
-bool MathArray::metrics(MetricsInfo & mi, Dimension & dim) const
-{
- dim = dim_;
- metrics(mi);
- if (dim_ == dim)
- return false;
- dim = dim_;
- return true;
-}
-
-
-namespace {
-
-bool isInside(DocIterator const & it, MathArray const & ar,
- pos_type p1, pos_type p2)
-{
- for (size_t i = 0; i != it.depth(); ++i) {
- CursorSlice const & sl = it[i];
- if (sl.inset().inMathed() && &sl.cell() == &ar)
- return p1 <= sl.pos() && sl.pos() < p2;
- }
- return false;
-}
-
-}
-
-
-
-void MathArray::metrics(MetricsInfo & mi) const
-{
- frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
- dim_ = fm.dimension('I');
- int xascent = fm.dimension('x').ascent();
- if (xascent >= dim_.asc)
- xascent = (2 * dim_.asc) / 3;
- minasc_ = xascent;
- mindes_ = (3 * xascent) / 4;
- slevel_ = (4 * xascent) / 5;
- sshift_ = xascent / 4;
- kerning_ = 0;
-
- if (empty())
- return;
-
- dim_.asc = 0;
- dim_.wid = 0;
- Dimension d;
- //BufferView & bv = *mi.base.bv;
- //Buffer const & buf = *bv.buffer();
- for (size_t i = 0, n = size(); i != n; ++i) {
- MathAtom const & at = operator[](i);
-#if 0
- MathMacro const * mac = at->asMacro();
- if (mac && buf.hasMacro(mac->name())) {
- MacroData const & tmpl = buf.getMacro(mac->name());
- int numargs = tmpl.numargs();
- if (i + numargs > n)
- numargs = n - i - 1;
- lyxerr << "metrics:found macro: " << mac->name()
- << " numargs: " << numargs << endl;
- if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) {
- MathArray args(begin() + i + 1, begin() + i + numargs + 1);
- MathArray exp;
- tmpl.expand(args, exp);
- mac->setExpansion(exp, args);
- mac->metricsExpanded(mi, d);
- dim_.wid += mac->widthExpanded();
- i += numargs;
- continue;
- }
- }
-#endif
- at->metrics(mi, d);
- dim_ += d;
- if (i == n - 1)
- kerning_ = at->kerning();
- }
-}
-
-
-void MathArray::draw(PainterInfo & pi, int x, int y) const
-{
- //lyxerr << "MathArray::draw: x: " << x << " y: " << y << endl;
- BufferView & bv = *pi.base.bv;
- setXY(bv, x, y);
-
- if (empty()) {
- pi.pain.rectangle(x, y - ascent(), width(), height(), LColor::mathline);
- return;
- }
-
- // don't draw outside the workarea
- if (y + descent() <= 0
- || y - ascent() >= bv.workHeight()
- || x + width() <= 0
- || x >= bv. workWidth())
- return;
-
- for (size_t i = 0, n = size(); i != n; ++i) {
- MathAtom const & at = operator[](i);
-#if 0
- Buffer const & buf = bv.buffer();
- // special macro handling
- MathMacro const * mac = at->asMacro();
- if (mac && buf.hasMacro(mac->name())) {
- MacroData const & tmpl = buf.getMacro(mac->name());
- int numargs = tmpl.numargs();
- if (i + numargs > n)
- numargs = n - i - 1;
- if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) {
- mac->drawExpanded(pi, x, y);
- x += mac->widthExpanded();
- i += numargs;
- continue;
- }
- }
-#endif
- bv.coordCache().insets().add(at.nucleus(), x, y);
- at->drawSelection(pi, x, y);
- at->draw(pi, x, y);
- x += at->width();
- }
-}
-
-
-void MathArray::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
-{
- dim.clear();
- Dimension d;
- for (const_iterator it = begin(); it != end(); ++it) {
- (*it)->metricsT(mi, d);
- dim += d;
- }
-}
-
-
-void MathArray::drawT(TextPainter & pain, int x, int y) const
-{
- //lyxerr << "x: " << x << " y: " << y << ' ' << pain.workAreaHeight() << endl;
-
- // FIXME: Abdel 16/10/2006
- // This drawT() method is never used, this is dead code.
-
- for (const_iterator it = begin(), et = end(); it != et; ++it) {
- (*it)->drawT(pain, x, y);
- //x += (*it)->width_;
- x += 2;
- }
-}
-
-
-int MathArray::pos2x(size_type pos) const
-{
- return pos2x(pos, 0);
-}
-
-
-int MathArray::pos2x(size_type pos, int glue) const
-{
- int x = 0;
- size_type target = min(pos, size());
- for (size_type i = 0; i < target; ++i) {
- const_iterator it = begin() + i;
- if ((*it)->getChar() == ' ')
- x += glue;
- //lyxerr << "char: " << (*it)->getChar()
- // << "width: " << (*it)->width() << std::endl;
- x += (*it)->width();
- }
- return x;
-}
-
-
-MathArray::size_type MathArray::x2pos(int targetx) const
-{
- return x2pos(targetx, 0);
-}
-
-
-MathArray::size_type MathArray::x2pos(int targetx, int glue) const
-{
- const_iterator it = begin();
- int lastx = 0;
- int currx = 0;
- // find first position after targetx
- for (; currx < targetx && it < end(); ++it) {
- lastx = currx;
- if ((*it)->getChar() == ' ')
- currx += glue;
- currx += (*it)->width();
- }
-
- /**
- * If we are not at the beginning of the array, go to the left
- * of the inset if one of the following two condition holds:
- * - the current inset is editable (so that the cursor tip is
- * deeper than us): in this case, we want all intermediate
- * cursor slices to be before insets;
- * - the mouse is closer to the left side of the inset than to
- * the right one.
- * See bug 1918 for details.
- **/
- if (it != begin() && currx >= targetx
- && ((*boost::prior(it))->asNestInset()
- || abs(lastx - targetx) < abs(currx - targetx))) {
- --it;
- }
-
- return it - begin();
-}
-
-
-int MathArray::dist(BufferView const & bv, int x, int y) const
-{
- int xx = 0;
- int yy = 0;
-
- const int xo_ = xo(bv);
- const int yo_ = yo(bv);
-
- if (x < xo_)
- xx = xo_ - x;
- else if (x > xo_ + width())
- xx = x - xo_ - width();
-
- if (y < yo_ - ascent())
- yy = yo_ - ascent() - y;
- else if (y > yo_ + descent())
- yy = y - yo_ - descent();
-
- return xx + yy;
-}
-
-
-void MathArray::setXY(BufferView & bv, int x, int y) const
-{
- //lyxerr << "setting position cache for MathArray " << this << std::endl;
- bv.coordCache().arrays().add(this, x, y);
-}
-
-
-int MathArray::xo(BufferView const & bv) const
-{
- return bv.coordCache().getArrays().x(this);
-}
-
-
-int MathArray::yo(BufferView const & bv) const
-{
- return bv.coordCache().getArrays().y(this);
-}
-
-
-std::ostream & operator<<(std::ostream & os, MathArray const & ar)
-{
- odocstringstream oss;
- NormalStream ns(oss);
- ns << ar;
- return os << to_utf8(oss.str());
-}
-
-
-odocstream & operator<<(odocstream & os, MathArray const & ar)
-{
- NormalStream ns(os);
- ns << ar;
- return os;
-}
-
-
-} // namespace lyx
+++ /dev/null
-// -*- C++ -*-
-/**
- * \file MathArray.h
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author Alejandro Aguilar Sierra
- * \author André Pönitz
- * \author Lars Gullik Bjønnes
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#ifndef MATH_DATA_H
-#define MATH_DATA_H
-
-#include <vector>
-
-#include "MathAtom.h"
-#include "dimension.h"
-
-#include "support/docstream.h"
-
-
-namespace lyx {
-
-class BufferView;
-class LaTeXFeatures;
-class ReplaceData;
-class MetricsInfo;
-class PainterInfo;
-class TextMetricsInfo;
-class TextPainter;
-
-
-class MathArray : private std::vector<MathAtom> {
-public:
- /// re-use inhertited stuff
- typedef std::vector<MathAtom> base_type;
- using base_type::const_iterator;
- using base_type::iterator;
- using base_type::size_type;
- using base_type::difference_type;
- using base_type::size;
- using base_type::empty;
- using base_type::clear;
- using base_type::begin;
- using base_type::end;
- using base_type::push_back;
- using base_type::pop_back;
- using base_type::back;
- using base_type::front;
- ///
- typedef size_type idx_type;
- typedef size_type pos_type;
-
-public:
- ///
- MathArray() {}
- ///
- MathArray(const_iterator from, const_iterator to);
- ///
- void append(MathArray const & ar);
-
- /// inserts single atom at position pos
- void insert(size_type pos, MathAtom const & at);
- /// inserts multiple atoms at position pos
- void insert(size_type pos, MathArray const & ar);
-
- /// erase range from pos1 to pos2
- void erase(iterator pos1, iterator pos2);
- /// erase single atom
- void erase(iterator pos);
- /// erase range from pos1 to pos2
- void erase(size_type pos1, size_type pos2);
- /// erase single atom
- void erase(size_type pos);
-
- ///
- void dump() const;
- ///
- void dump2() const;
- ///
- void replace(ReplaceData &);
- ///
- void substitute(MathArray const & m);
-
- /// looks for exact match
- bool match(MathArray const & ar) const;
- /// looks for inclusion match starting at pos
- bool matchpart(MathArray const & ar, pos_type pos) const;
- /// looks for containment, return == size mean not found
- size_type find(MathArray const & ar) const;
- /// looks for containment, return == size mean not found
- size_type find_last(MathArray const & ar) const;
- ///
- bool contains(MathArray const & ar) const;
- ///
- void validate(LaTeXFeatures &) const;
-
- /// checked write access
- MathAtom & operator[](pos_type);
- /// checked read access
- MathAtom const & operator[](pos_type) const;
- /// rebuild cached metrics information
- void metrics(MetricsInfo & mi) const;
- /// rebuild cached metrics information
- bool metrics(MetricsInfo & mi, Dimension & dim) const;
- /// redraw cell using cache metrics information
- void draw(PainterInfo & pi, int x, int y) const;
- /// rebuild cached metrics information
- void metricsT(TextMetricsInfo const & mi, Dimension & dim) const;
- /// redraw cell using cache metrics information
- void drawT(TextPainter & pi, int x, int y) const;
- /// mark cell for re-drawing
- void touch() const;
-
- /// access to cached x coordinate of last drawing
- int xo(BufferView const & bv) const;
- /// access to cached y coordinate of last drawing
- int yo(BufferView const & bv) const;
- /// access to cached x coordinate of mid point of last drawing
- int xm(BufferView const & bv) const { return xo(bv) + dim_.wid / 2; }
- /// access to cached y coordinate of mid point of last drawing
- int ym(BufferView const & bv) const { return yo(bv) + (dim_.des - dim_.asc) / 2; }
- /// write access to coordinate;
- void setXY(BufferView & bv, int x, int y) const;
- /// returns x coordinate of given position in the array
- int pos2x(size_type pos) const;
- /// returns position of given x coordinate
- int pos2x(size_type pos, int glue) const;
- /// returns position of given x coordinate
- size_type x2pos(int pos) const;
- /// returns position of given x coordinate fstarting from a certain pos
- size_type x2pos(int targetx, int glue) const;
- /// returns distance of this cell to the point given by x and y
- // assumes valid position and size cache
- int dist(BufferView const & bv, int x, int y) const;
-
- /// ascent of this cell above the baseline
- int ascent() const { return dim_.asc; }
- /// descent of this cell below the baseline
- int descent() const { return dim_.des; }
- /// height of the cell
- int height() const { return dim_.asc + dim_.des; }
- /// width of this cell
- int width() const { return dim_.wid; }
- /// dimensions of cell
- Dimension const & dim() const { return dim_; }
- /// dimensions of cell
- void setDim(Dimension const & d) const { dim_ = d; }
- /// minimum ascent offset for superscript
- int minasc() const { return minasc_; }
- /// minimum descent offset for subscript
- int mindes() const { return mindes_; }
- /// level above/below which super/subscript should extend
- int slevel() const { return slevel_; }
- /// additional super/subscript shift
- int sshift() const { return sshift_; }
- /// superscript kerning
- int kerning() const { return kerning_; }
- ///
- void swap(MathArray & ar) { base_type::swap(ar); }
-
-protected:
- /// cached dimensions of cell
- mutable Dimension dim_;
- /// cached values for super/subscript placement
- mutable int minasc_;
- mutable int mindes_;
- mutable int slevel_;
- mutable int sshift_;
- mutable int kerning_;
-
-private:
- /// is this an exact match at this position?
- bool find1(MathArray const & ar, size_type pos) const;
-};
-
-///
-std::ostream & operator<<(std::ostream & os, MathArray const & ar);
-///
-odocstream & operator<<(odocstream & os, MathArray const & ar);
-
-
-} // namespace lyx
-
-#endif
--- /dev/null
+/**
+ * \file MathMacro.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Alejandro Aguilar Sierra
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "MathMacro.h"
+#include "MathSupport.h"
+#include "MathExtern.h"
+#include "MathStream.h"
+
+#include "buffer.h"
+#include "cursor.h"
+#include "debug.h"
+#include "BufferView.h"
+#include "LaTeXFeatures.h"
+#include "frontends/Painter.h"
+
+
+namespace lyx {
+
+using std::string;
+using std::max;
+using std::auto_ptr;
+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)
+{}
+
+
+auto_ptr<InsetBase> MathMacro::doClone() const
+{
+ return auto_ptr<InsetBase>(new MathMacro(*this));
+}
+
+
+docstring MathMacro::name() const
+{
+ return name_;
+}
+
+
+void MathMacro::cursorPos(BufferView const & bv,
+ CursorSlice const & sl, bool boundary, int & x, int & y) const
+{
+ // We may have 0 arguments, but InsetMathNest requires at least one.
+ if (nargs() > 0)
+ InsetMathNest::cursorPos(bv, sl, boundary, x, y);
+}
+
+
+bool MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+ if (!MacroTable::globalMacros().has(name())) {
+ mathed_string_dim(mi.base.font, "Unknown: " + name(), dim);
+ } else {
+ 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)
+ return false;
+ dim_ = dim;
+ return true;
+}
+
+
+void MathMacro::draw(PainterInfo & pi, int x, int y) const
+{
+ if (!MacroTable::globalMacros().has(name())) {
+ // FIXME UNICODE
+ drawStrRed(pi, x, y, "Unknown: " + name());
+ } else {
+ 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;
+ 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 {
+ MacroTable::globalMacros().get(name()).lock();
+ expanded_.draw(pi, x, y);
+ MacroTable::globalMacros().get(name()).unlock();
+ }
+ }
+ drawMarkers2(pi, x, y);
+}
+
+
+void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const
+{
+ // We may have 0 arguments, but InsetMathNest requires at least one.
+ if (nargs() > 0)
+ InsetMathNest::drawSelection(pi, x, y);
+}
+
+
+void MathMacro::validate(LaTeXFeatures & features) const
+{
+ if (name() == "binom" || name() == "mathcircumflex")
+ features.require(to_utf8(name()));
+}
+
+
+InsetBase * MathMacro::editXY(LCursor & cur, int x, int y)
+{
+ // We may have 0 arguments, but InsetMathNest requires at least one.
+ if (nargs() > 0) {
+ // Prevent crash due to cold coordcache
+ // FIXME: This is only a workaround, the call of
+ // InsetMathNest::editXY is correct. The correct fix would
+ // ensure that the coordcache of the arguments is valid.
+ if (!editing(&cur.bv())) {
+ edit(cur, true);
+ return this;
+ }
+ return InsetMathNest::editXY(cur, x, y);
+ }
+ return this;
+}
+
+
+bool MathMacro::idxFirst(LCursor & cur) const
+{
+ cur.updateFlags(Update::Force);
+ return InsetMathNest::idxFirst(cur);
+}
+
+
+bool MathMacro::idxLast(LCursor & cur) const
+{
+ cur.updateFlags(Update::Force);
+ return InsetMathNest::idxLast(cur);
+}
+
+
+bool MathMacro::notifyCursorLeaves(LCursor & cur)
+{
+ cur.updateFlags(Update::Force);
+ return InsetMathNest::notifyCursorLeaves(cur);
+}
+
+
+void MathMacro::maple(MapleStream & os) const
+{
+ updateExpansion();
+ lyx::maple(expanded_, os);
+}
+
+
+void MathMacro::mathmlize(MathStream & os) const
+{
+ updateExpansion();
+ lyx::mathmlize(expanded_, os);
+}
+
+
+void MathMacro::octave(OctaveStream & os) const
+{
+ updateExpansion();
+ lyx::octave(expanded_, os);
+}
+
+
+void MathMacro::updateExpansion() const
+{
+ //expanded_.substitute(*this);
+}
+
+
+void MathMacro::infoize(odocstream & os) const
+{
+ os << "Macro: " << name();
+}
+
+
+void MathMacro::infoize2(odocstream & os) const
+{
+ os << "Macro: " << name();
+
+}
+
+
+} // namespace lyx
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file MathMacro.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Alejandro Aguilar Sierra
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef MATH_MACRO_H
+#define MATH_MACRO_H
+
+#include "InsetMathNest.h"
+#include "MathArray.h"
+#include "InsetMathNest.h"
+#include "MathMacroTable.h"
+
+
+namespace lyx {
+
+
+/// This class contains the data for a macro.
+class MathMacro : public InsetMathNest {
+public:
+ /// A macro can be built from an existing template
+ MathMacro(docstring const & name, int numargs);
+ ///
+ void draw(PainterInfo & pi, int x, int y) const;
+ ///
+ void drawExpanded(PainterInfo & pi, int x, int y) const;
+ /// draw selection background
+ void drawSelection(PainterInfo & pi, int x, int y) const;
+ /// draw decorations.
+ void drawDecoration(PainterInfo & pi, int x, int y) const
+ { drawMarkers2(pi, x, y); }
+ ///
+ bool metrics(MetricsInfo & mi, Dimension & dim) const;
+ /// get cursor position
+ void cursorPos(BufferView const & bv, CursorSlice const & sl,
+ bool boundary, int & x, int & y) const;
+ ///
+ InsetBase * editXY(LCursor & cur, int x, int y);
+ /// target pos when we enter the inset from the left by pressing "Right"
+ bool idxFirst(LCursor &) const;
+ /// target pos when we enter the inset from the right by pressing "Left"
+ bool idxLast(LCursor &) const;
+ ///
+ virtual bool notifyCursorLeaves(LCursor &);
+ ///
+ docstring name() const;
+ ///
+ void setExpansion(MathArray const & exp, MathArray const & args) const;
+
+ ///
+ void validate(LaTeXFeatures &) const;
+
+ ///
+ void maple(MapleStream &) const;
+ ///
+ void mathmlize(MathStream &) const;
+ ///
+ void octave(OctaveStream &) const;
+ ///
+ void infoize(odocstream &) const;
+ ///
+ void infoize2(odocstream &) const;
+
+private:
+ virtual std::auto_ptr<InsetBase> doClone() const;
+ ///
+ void updateExpansion() const;
+ ///
+ void expand() const;
+
+ /// name of macro
+ docstring name_;
+ /// the unexpanded macro defintition
+ mutable MathArray tmpl_;
+ /// the macro substituted with our args
+ mutable MathArray expanded_;
+};
+
+
+
+
+} // namespace lyx
+#endif
+++ /dev/null
-// -*- C++ -*-
-/**
- * \file ReplaceData.h
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author André Pönitz
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#ifndef MATH_REPLACE_H
-#define MATH_REPLACE_H
-
-
-#include "MathArray.h"
-
-
-namespace lyx {
-
-class ReplaceData {
-public:
- ///
- MathArray from;
- ///
- MathArray to;
-};
-
-
-} // namespace lyx
-
-#endif
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file ReplaceData.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef MATH_REPLACE_H
+#define MATH_REPLACE_H
+
+
+#include "MathArray.h"
+
+
+namespace lyx {
+
+class ReplaceData {
+public:
+ ///
+ MathArray from;
+ ///
+ MathArray to;
+};
+
+
+} // namespace lyx
+
+#endif