summaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2013-08-09 11:47:56 +0000
committerJaviertxo <jtx@jtx.marker.es>2013-08-09 11:47:56 +0000
commit4e358f420a7a1512c722d9eccd864416bc4c075b (patch)
tree223e826158e09ab2c864abf0214fe1e6a714ab61 /src/util
parentUpdate to trunk (diff)
parentRemove missing files from POTFILES.in (diff)
downloadinkscape-4e358f420a7a1512c722d9eccd864416bc4c075b.tar.gz
inkscape-4e358f420a7a1512c722d9eccd864416bc4c075b.zip
update to trunk
(bzr r11950.1.127)
Diffstat (limited to 'src/util')
-rw-r--r--src/util/expression-evaluator.cpp4
-rw-r--r--src/util/units.cpp384
-rw-r--r--src/util/units.h77
3 files changed, 297 insertions, 168 deletions
diff --git a/src/util/expression-evaluator.cpp b/src/util/expression-evaluator.cpp
index 3e1bab6bc..dc59c67f4 100644
--- a/src/util/expression-evaluator.cpp
+++ b/src/util/expression-evaluator.cpp
@@ -29,6 +29,8 @@
#include <string.h>
+using Inkscape::Util::unit_table;
+
namespace Inkscape {
namespace Util {
@@ -77,8 +79,6 @@ typedef struct
*/
static bool unitresolverproc (const gchar* identifier, GimpEevlQuantity *result, Unit* unit)
{
- static UnitTable unit_table;
-
if (!unit) {
result->value = 1;
result->dimension = 1;
diff --git a/src/util/units.cpp b/src/util/units.cpp
index d1275b082..7bc910fcc 100644
--- a/src/util/units.cpp
+++ b/src/util/units.cpp
@@ -1,12 +1,26 @@
+/*
+ * Inkscape Units
+ *
+ * Authors:
+ * Matthew Petroff <matthew@mpetroff.net>
+ *
+ * Copyright (C) 2013 Matthew Petroff
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <cmath>
#include <cerrno>
+#include <iomanip>
#include <glib.h>
+#include <glibmm/regex.h>
+#include <glibmm/fileutils.h>
+#include <glibmm/markup.h>
-#include "io/simple-sax.h"
#include "util/units.h"
#include "path-prefix.h"
#include "streq.h"
@@ -47,27 +61,31 @@ std::map<Glib::ustring, Inkscape::Util::UnitType> &getTypeMappings()
namespace Inkscape {
namespace Util {
-class UnitsSAXHandler : public Inkscape::IO::FlatSaxHandler
+class UnitParser : public Glib::Markup::Parser
{
public:
- UnitsSAXHandler(UnitTable *table);
- virtual ~UnitsSAXHandler() {}
+ typedef Glib::Markup::Parser::AttributeMap AttrMap;
+ typedef Glib::Markup::ParseContext Ctx;
+
+ UnitParser(UnitTable *table);
+ virtual ~UnitParser() {}
- virtual void _startElement(xmlChar const *name, xmlChar const **attrs);
- virtual void _endElement(xmlChar const *name);
+protected:
+ virtual void on_start_element(Ctx &ctx, Glib::ustring const &name, AttrMap const &attrs);
+ virtual void on_end_element(Ctx &ctx, Glib::ustring const &name);
+ virtual void on_text(Ctx &ctx, Glib::ustring const &text);
+public:
UnitTable *tbl;
bool primary;
bool skip;
Unit unit;
};
-UnitsSAXHandler::UnitsSAXHandler(UnitTable *table) :
- FlatSaxHandler(),
+UnitParser::UnitParser(UnitTable *table) :
tbl(table),
- primary(0),
- skip(0),
- unit()
+ primary(false),
+ skip(false)
{
}
@@ -103,7 +121,8 @@ void Unit::clear()
*this = Unit();
}
-int Unit::defaultDigits() const {
+int Unit::defaultDigits() const
+{
int factor_digits = int(log10(factor));
if (factor_digits < 0) {
g_warning("factor = %f, factor_digits = %d", factor, factor_digits);
@@ -113,30 +132,87 @@ int Unit::defaultDigits() const {
return factor_digits;
}
+bool Unit::compatibleWith(const Unit &u) const
+{
+ // Percentages
+ if (type == UNIT_TYPE_DIMENSIONLESS || u.type == UNIT_TYPE_DIMENSIONLESS) {
+ return true;
+ }
+
+ // Other units with same type
+ if (type == u.type) {
+ return true;
+ }
+
+ // Different, incompatible types
+ return false;
+}
+bool Unit::compatibleWith(const Glib::ustring u) const
+{
+ static UnitTable unit_table;
+ return compatibleWith(unit_table.getUnit(u));
+}
+
+bool operator== (const Unit &u1, const Unit &u2)
+{
+ return (u1.type == u2.type && u1.name.compare(u2.name) == 0);
+}
+
+bool operator!= (const Unit &u1, const Unit &u2)
+{
+ return !(u1 == u2);
+}
+
+int Unit::svgUnit() const
+{
+ if (!abbr.compare("px"))
+ return 1;
+ if (!abbr.compare("pt"))
+ return 2;
+ if (!abbr.compare("pc"))
+ return 3;
+ if (!abbr.compare("mm"))
+ return 4;
+ if (!abbr.compare("cm"))
+ return 5;
+ if (!abbr.compare("in"))
+ return 6;
+ if (!abbr.compare("ft"))
+ return 7;
+ if (!abbr.compare("em"))
+ return 8;
+ if (!abbr.compare("ex"))
+ return 9;
+ if (!abbr.compare("%"))
+ return 10;
+ return 0;
+}
+
UnitTable::UnitTable()
{
- // if we swich to the xml file, don't forget to force locale to 'C'
- // load("share/ui/units.xml"); // <-- Buggy
- gchar *filename = g_build_filename(INKSCAPE_UIDIR, "units.txt", NULL);
- loadText(filename);
+ gchar *filename = g_build_filename(INKSCAPE_UIDIR, "units.xml", NULL);
+ load(filename);
g_free(filename);
}
-UnitTable::~UnitTable() {
+UnitTable::~UnitTable()
+{
for (UnitMap::iterator iter = _unit_map.begin(); iter != _unit_map.end(); ++iter)
{
delete (*iter).second;
}
}
-void UnitTable::addUnit(Unit const &u, bool primary) {
+void UnitTable::addUnit(Unit const &u, bool primary)
+{
_unit_map[u.abbr] = new Unit(u);
if (primary) {
_primary_unit[u.type] = u.abbr;
}
}
-Unit UnitTable::getUnit(Glib::ustring const &unit_abbr) const {
+Unit UnitTable::getUnit(Glib::ustring const &unit_abbr) const
+{
UnitMap::const_iterator iter = _unit_map.find(unit_abbr);
if (iter != _unit_map.end()) {
return *((*iter).second);
@@ -145,7 +221,29 @@ Unit UnitTable::getUnit(Glib::ustring const &unit_abbr) const {
}
}
-bool UnitTable::deleteUnit(Unit const &u) {
+Quantity UnitTable::getQuantity(Glib::ustring const& q) const
+{
+ Glib::MatchInfo match_info;
+
+ // Extract value
+ double value = 0;
+ Glib::RefPtr<Glib::Regex> value_regex = Glib::Regex::create("[-+]*[\\d+]*\\.*[\\d+]*[eE]*[-+]*\\d+");
+ if (value_regex->match(q, match_info)) {
+ value = atof(match_info.fetch(0).c_str());
+ }
+
+ // Extract unit abbreviation
+ Glib::ustring abbr;
+ Glib::RefPtr<Glib::Regex> unit_regex = Glib::Regex::create("[A-z%]+");
+ if (unit_regex->match(q, match_info)) {
+ abbr = match_info.fetch(0);
+ }
+
+ return Quantity(value, abbr);
+}
+
+bool UnitTable::deleteUnit(Unit const &u)
+{
bool deleted = false;
// Cannot delete the primary unit type since it's
// used for conversions
@@ -183,172 +281,148 @@ Glib::ustring UnitTable::primary(UnitType type) const
return _primary_unit[type];
}
-bool UnitTable::loadText(Glib::ustring const &filename)
-{
- char buf[BUFSIZE] = {0};
-
- // Open file for reading
- FILE * f = fopen(filename.c_str(), "r");
- if (f == NULL) {
- g_warning("Could not open units file '%s': %s\n",
- filename.c_str(), strerror(errno));
- g_warning("* INKSCAPE_DATADIR is: '%s'\n", INKSCAPE_DATADIR);
- g_warning("* INKSCAPE_UIDIR is: '%s'\n", INKSCAPE_UIDIR);
- return false;
- }
-
- /** @todo fix this to use C++ means and explicit locale to avoid need to change. */
- // bypass current locale in order to make
- // sscanf read floats with '.' as a separator
- // set locale to 'C' and keep old locale
- char *old_locale = g_strdup(setlocale(LC_NUMERIC, NULL));
- setlocale (LC_NUMERIC, "C");
-
- while (fgets(buf, BUFSIZE, f) != NULL) {
- char name[BUFSIZE] = {0};
- char plural[BUFSIZE] = {0};
- char abbr[BUFSIZE] = {0};
- char type[BUFSIZE] = {0};
- double factor = 0.0;
- char primary[BUFSIZE] = {0};
-
- int nchars = 0;
- // locale is set to C, scanning %lf should work _everywhere_
- /** @todo address %15n, which causes a warning: */
- if (sscanf(buf, "%15s %15s %15s %15s %8lf %1s %15n",
- name, plural, abbr, type, &factor, primary, &nchars) != 6)
- {
- // Skip the line - doesn't appear to be valid
- continue;
- }
-
- g_assert(nchars < BUFSIZE);
-
- char *desc = buf;
- desc += nchars; // buf is now only the description
-
- // insert into _unit_map
- if (getTypeMappings().find(type) == getTypeMappings().end())
- {
- g_warning("Skipping unknown unit type '%s' for %s.\n", type, name);
- continue;
- }
- UnitType utype = getTypeMappings()[type];
-
- Unit u(utype, factor, name, plural, abbr, desc);
-
- // if primary is 'Y', list this unit as a primary
- addUnit(u, (primary[0]=='Y' || primary[0]=='y'));
- }
-
- // set back the saved locale
- setlocale (LC_NUMERIC, old_locale);
- g_free (old_locale);
-
- // close file
- if (fclose(f) != 0) {
- g_warning("Error closing units file '%s': %s\n", filename.c_str(), strerror(errno));
- return false;
- }
-
- return true;
-}
-
-bool UnitTable::load(Glib::ustring const &filename) {
- UnitsSAXHandler handler(this);
+bool UnitTable::load(std::string const &filename) {
+ UnitParser uparser(this);
+ Glib::Markup::ParseContext ctx(uparser);
- int result = handler.parseFile( filename.c_str() );
- if ( result != 0 ) {
- // perhaps
- g_warning("Problem loading units file '%s': %d\n", filename.c_str(), result);
+ try {
+ Glib::ustring unitfile = Glib::file_get_contents(filename);
+ ctx.parse(unitfile);
+ ctx.end_parse();
+ } catch (Glib::MarkupError const &e) {
+ g_warning("Problem loading units file '%s': %s\n", filename.c_str(), e.what().c_str());
return false;
}
-
return true;
}
-bool UnitTable::save(Glib::ustring const &filename) {
+bool UnitTable::save(std::string const &filename) {
- // open file for writing
- FILE *f = fopen(filename.c_str(), "w");
- if (f == NULL) {
- g_warning("Could not open units file '%s': %s\n", filename.c_str(), strerror(errno));
- return false;
- }
-
- // write out header
- // foreach item in _unit_map, sorted alphabetically by type and then unit name
- // sprintf a line
- // name
- // name_plural
- // abbr
- // type
- // factor
- // PRI - if listed in primary unit table, 'Y', else 'N'
- // description
- // write line to the file
-
- // close file
- if (fclose(f) != 0) {
- g_warning("Error closing units file '%s': %s\n", filename.c_str(), strerror(errno));
- return false;
- }
+ g_warning("UnitTable::save(): not implemented");
return true;
}
+Inkscape::Util::UnitTable unit_table;
-void UnitsSAXHandler::_startElement(xmlChar const *name, xmlChar const **attrs)
+void UnitParser::on_start_element(Ctx &ctx, Glib::ustring const &name, AttrMap const &attrs)
{
- if (streq("unit", (char const *)name)) {
+ if (name == "unit") {
// reset for next use
unit.clear();
primary = false;
skip = false;
- for ( int i = 0; attrs[i]; i += 2 ) {
- char const *const key = (char const *)attrs[i];
- if (streq("type", key)) {
- char const *type = (char const*)attrs[i+1];
- if (getTypeMappings().find(type) != getTypeMappings().end())
- {
- unit.type = getTypeMappings()[type];
- } else {
- g_warning("Skipping unknown unit type '%s' for %s.\n", type, name);
- skip = true;
- }
- } else if (streq("pri", key)) {
- primary = attrs[i+1][0] == 'y' || attrs[i+1][0] == 'Y';
+ AttrMap::const_iterator f;
+ if ((f = attrs.find("type")) != attrs.end()) {
+ Glib::ustring type = f->second;
+ if (getTypeMappings().find(type) != getTypeMappings().end()) {
+ unit.type = getTypeMappings()[type];
+ } else {
+ g_warning("Skipping unknown unit type '%s'.\n", type.c_str());
+ skip = true;
}
}
+ if ((f = attrs.find("pri")) != attrs.end()) {
+ primary = (f->second[0] == 'y' || f->second[0] == 'Y');
+ }
}
}
-void UnitsSAXHandler::_endElement(xmlChar const *xname)
+void UnitParser::on_text(Ctx &ctx, Glib::ustring const &text)
{
- char const *const name = (char const *) xname;
- if (streq("name", name)) {
- unit.name = data;
- } else if (streq("plural", name)) {
- unit.name_plural = data;
- } else if (streq("abbr", name)) {
- unit.abbr = data;
- } else if (streq("factor", name)) {
+ Glib::ustring element = ctx.get_element();
+ if (element == "name") {
+ unit.name = text;
+ } else if (element == "plural") {
+ unit.name_plural = text;
+ } else if (element == "abbr") {
+ unit.abbr = text;
+ } else if (element == "factor") {
// TODO make sure we use the right conversion
- unit.factor = atol(data.c_str());
- } else if (streq("description", name)) {
- unit.description = data;
- } else if (streq("unit", name)) {
- if (!skip) {
- tbl->addUnit(unit, primary);
- }
+ unit.factor = g_ascii_strtod(text.c_str(), NULL);
+ } else if (element == "description") {
+ unit.description = text;
+ }
+}
+
+void UnitParser::on_end_element(Ctx &ctx, Glib::ustring const &name)
+{
+ if (name == "unit" && !skip) {
+ tbl->addUnit(unit, primary);
}
}
+Quantity::Quantity(double q, const Unit &u)
+{
+ unit = new Unit(u);
+ quantity = q;
+}
+Quantity::Quantity(double q, const Glib::ustring u)
+{
+ unit = new Unit(unit_table.getUnit(u));
+ quantity = q;
+}
+
+bool Quantity::compatibleWith(const Unit &u) const
+{
+ return unit->compatibleWith(u);
+}
+bool Quantity::compatibleWith(const Glib::ustring u) const
+{
+ return compatibleWith(unit_table.getUnit(u));
+}
+
+double Quantity::value(const Unit &u) const
+{
+ return convert(quantity, *unit, u);
+}
+double Quantity::value(const Glib::ustring u) const
+{
+ return value(unit_table.getUnit(u));
+}
+
+Glib::ustring Quantity::string(const Unit &u) const {
+ return Glib::ustring::format(std::fixed, std::setprecision(2), value(u)) + " " + unit->abbr;
+}
+Glib::ustring Quantity::string(const Glib::ustring u) const {
+ return string(unit_table.getUnit(u));
+}
+Glib::ustring Quantity::string() const {
+ return string(*unit);
+}
+
+double Quantity::convert(const double from_dist, const Unit &from, const Unit &to)
+{
+ // Percentage
+ if (to.type == UNIT_TYPE_DIMENSIONLESS) {
+ return from_dist * to.factor;
+ }
+
+ // Incompatible units
+ if (from.type != to.type) {
+ return -1;
+ }
+
+ // Compatible units
+ return from_dist * from.factor / to.factor;
+}
+double Quantity::convert(const double from_dist, const Glib::ustring from, const Unit &to)
+{
+ return convert(from_dist, unit_table.getUnit(from), to);
+}
+double Quantity::convert(const double from_dist, const Unit &from, const Glib::ustring to)
+{
+ return convert(from_dist, from, unit_table.getUnit(to));
+}
+double Quantity::convert(const double from_dist, const Glib::ustring from, const Glib::ustring to)
+{
+ return convert(from_dist, unit_table.getUnit(from), unit_table.getUnit(to));
+}
+
} // namespace Util
} // namespace Inkscape
-
/*
Local Variables:
mode:c++
diff --git a/src/util/units.h b/src/util/units.h
index 40c89a4a0..bb202b96a 100644
--- a/src/util/units.h
+++ b/src/util/units.h
@@ -1,4 +1,15 @@
/*
+ * Inkscape Units
+ *
+ * Authors:
+ * Matthew Petroff <matthew@mpetroff.net>
+ *
+ * Copyright (C) 2013 Matthew Petroff
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+/*
This is a rough draft of a global 'units' thingee, to allow dialogs and
the ruler to share info about unit systems... Dunno if this is the
right kind of object though, so we may have to redo this or shift things
@@ -54,12 +65,53 @@ class Unit {
*/
int defaultDigits() const;
+ /** Checks if a unit is compatible with the specified unit. */
+ bool compatibleWith(const Unit &u) const;
+ bool compatibleWith(const Glib::ustring) const;
+
UnitType type;
double factor;
Glib::ustring name;
Glib::ustring name_plural;
Glib::ustring abbr;
Glib::ustring description;
+
+ /** Check if units are equal. */
+ friend bool operator== (const Unit &u1, const Unit &u2);
+ /** Check if units are not equal. */
+ friend bool operator!= (const Unit &u1, const Unit &u2);
+
+ /** Get SVG unit. */
+ int svgUnit() const;
+};
+
+class Quantity {
+public:
+ const Unit *unit;
+ double quantity;
+
+ /** Initialize a quantity. */
+ Quantity(double q, const Unit &u); // constructor
+ Quantity(double q, const Glib::ustring u); // constructor
+
+ /** Checks if a quantity is compatible with the specified unit. */
+ bool compatibleWith(const Unit &u) const;
+ bool compatibleWith(const Glib::ustring u) const;
+
+ /** Return the quantity's value in the specified unit. */
+ double value(const Unit &u) const;
+ double value(const Glib::ustring u) const;
+
+ /** Return a printable string of the value in the specified unit. */
+ Glib::ustring string(const Unit &u) const;
+ Glib::ustring string(const Glib::ustring u) const;
+ Glib::ustring string() const;
+
+ /** Convert distances. */
+ static double convert(const double from_dist, const Unit &from, const Unit &to);
+ static double convert(const double from_dist, const Glib::ustring from, const Unit &to);
+ static double convert(const double from_dist, const Unit &from, const Glib::ustring to);
+ static double convert(const double from_dist, const Glib::ustring from, const Glib::ustring to);
};
class UnitTable {
@@ -75,13 +127,16 @@ class UnitTable {
typedef std::map<Glib::ustring, Unit*> UnitMap;
/** Add a new unit to the table */
- void addUnit(Unit const& u, bool primary);
+ void addUnit(Unit const &u, bool primary);
/** Retrieve a given unit based on its string identifier */
- Unit getUnit(Glib::ustring const& name) const;
+ Unit getUnit(Glib::ustring const &name) const;
+
+ /** Retrieve a quantity based on its string identifier */
+ Quantity getQuantity(Glib::ustring const &q) const;
/** Remove a unit definition from the given unit type table */
- bool deleteUnit(Unit const& u);
+ bool deleteUnit(Unit const &u);
/** Returns true if the given string 'name' is a valid unit in the table */
bool hasUnit(Glib::ustring const &name) const;
@@ -96,19 +151,17 @@ class UnitTable {
void setScale();
- bool load(Glib::ustring const &filename);
-
- /** Loads units from a text file.
+ /** Load units from an XML file.
*
- * loadText loads and merges the contents of the given file into the UnitTable,
+ * Loads and merges the contents of the given file into the UnitTable,
* possibly overwriting existing unit definitions.
*
* @param filename file to be loaded
*/
- bool loadText(Glib::ustring const &filename);
+ bool load(std::string const &filename);
/** Saves the current UnitTable to the given file. */
- bool save(Glib::ustring const &filename);
+ bool save(std::string const &filename);
protected:
UnitTable::UnitMap _unit_map;
@@ -117,11 +170,13 @@ class UnitTable {
double _linear_scale;
private:
- UnitTable(UnitTable const& t);
- UnitTable operator=(UnitTable const& t);
+ UnitTable(UnitTable const &t);
+ UnitTable operator=(UnitTable const &t);
};
+extern UnitTable unit_table;
+
} // namespace Util
} // namespace Inkscape