X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fpreferences.cpp;h=3815d44c563eaf32d19a1af7a03e835a79ae079b;hb=c7cf14ac71346f76ae219ce67fb88c1bd34832e2;hp=a6409b5ba4e6d226939f69d2697831a939240a03;hpb=b50bd4043d21611cc8301b731f60b4b0cd27bfb8;p=inkscape.git diff --git a/src/preferences.cpp b/src/preferences.cpp index a6409b5ba..3815d44c5 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -11,10 +11,12 @@ */ #include +#include #include #include #include #include +#include #include "preferences.h" #include "preferences-skeleton.h" #include "inkscape.h" @@ -26,6 +28,34 @@ namespace Inkscape { +static Inkscape::XML::Document *loadImpl( std::string const& prefsFilename, Glib::ustring & errMsg ); +static void migrateDetails( Inkscape::XML::Document *from, Inkscape::XML::Document *to ); + +static Inkscape::XML::Document *migrateFromDoc = 0; + +// TODO clean up. Function copied from file.cpp: +// what gets passed here is not actually an URI... it is an UTF-8 encoded filename (!) +static void file_add_recent(gchar const *uri) +{ + if (!uri) { + g_warning("file_add_recent: uri == NULL"); + } else { + GtkRecentManager *recent = gtk_recent_manager_get_default(); + gchar *fn = g_filename_from_utf8(uri, -1, NULL, NULL, NULL); + if (fn) { + if (g_file_test(fn, G_FILE_TEST_EXISTS)) { + gchar *uriToAdd = g_filename_to_uri(fn, NULL, NULL); + if (uriToAdd) { + gtk_recent_manager_add_item(recent, uriToAdd); + g_free(uriToAdd); + } + } + g_free(fn); + } + } +} + + // private inner class definition /** @@ -47,30 +77,30 @@ private: Glib::ustring const _filter; }; - Preferences::Preferences() : _prefs_basename(PREFERENCES_FILE_NAME), _prefs_dir(""), _prefs_filename(""), _prefs_doc(0), _errorHandler(0), - _writable(false) + _writable(false), + _hasError(false) { // profile_path essentailly returns the argument prefixed by the profile directory. gchar *path = profile_path(NULL); _prefs_dir = path; g_free(path); - - path = profile_path(_prefs_basename.data()); + + path = profile_path(_prefs_basename.c_str()); _prefs_filename = path; g_free(path); - + _loadDefaults(); _load(); } Preferences::~Preferences() -{ +{ // delete all PrefNodeObservers for (_ObsMap::iterator i = _observer_map.begin(); i != _observer_map.end(); ) { delete (*i++).second; // avoids reference to a deleted key @@ -96,115 +126,132 @@ void Preferences::_loadDefaults() * Tries to load the user's preferences.xml file. If there is none, creates it. */ void Preferences::_load() -{ +{ Glib::ustring const not_saved = _("Inkscape will run with default settings, " "and new settings will not be saved. "); // NOTE: After we upgrade to Glib 2.16, use Glib::ustring::compose - + // 1. Does the file exist? - if (!g_file_test(_prefs_filename.data(), G_FILE_TEST_EXISTS)) { + if (!g_file_test(_prefs_filename.c_str(), G_FILE_TEST_EXISTS)) { // No - we need to create one. // Does the profile directory exist? - if (!g_file_test(_prefs_dir.data(), G_FILE_TEST_EXISTS)) { + if (!g_file_test(_prefs_dir.c_str(), G_FILE_TEST_EXISTS)) { // No - create the profile directory - if (g_mkdir(_prefs_dir.data(), 0755)) { + if (g_mkdir(_prefs_dir.c_str(), 0755)) { // the creation failed //_reportError(Glib::ustring::compose(_("Cannot create profile directory %1."), // Glib::filename_to_utf8(_prefs_dir)), not_saved); gchar *msg = g_strdup_printf(_("Cannot create profile directory %s."), - Glib::filename_to_utf8(_prefs_dir).data()); + Glib::filename_to_utf8(_prefs_dir).c_str()); _reportError(msg, not_saved); g_free(msg); return; } // create some subdirectories for user stuff char const *user_dirs[] = {"keys", "templates", "icons", "extensions", "palettes", NULL}; - for(int i=0; user_dirs[i]; ++i) { + for (int i=0; user_dirs[i]; ++i) { char *dir = profile_path(user_dirs[i]); g_mkdir(dir, 0755); g_free(dir); } - - } else if (!g_file_test(_prefs_dir.data(), G_FILE_TEST_IS_DIR)) { + + } else if (!g_file_test(_prefs_dir.c_str(), G_FILE_TEST_IS_DIR)) { // The profile dir is not actually a directory //_reportError(Glib::ustring::compose(_("%1 is not a valid directory."), // Glib::filename_to_utf8(_prefs_dir)), not_saved); gchar *msg = g_strdup_printf(_("%s is not a valid directory."), - Glib::filename_to_utf8(_prefs_dir).data()); + Glib::filename_to_utf8(_prefs_dir).c_str()); _reportError(msg, not_saved); g_free(msg); return; } // The profile dir exists and is valid. - if (!g_file_set_contents(_prefs_filename.data(), preferences_skeleton, PREFERENCES_SKELETON_SIZE, NULL)) { + if (!g_file_set_contents(_prefs_filename.c_str(), preferences_skeleton, PREFERENCES_SKELETON_SIZE, NULL)) { // The write failed. //_reportError(Glib::ustring::compose(_("Failed to create the preferences file %1."), // Glib::filename_to_utf8(_prefs_filename)), not_saved); gchar *msg = g_strdup_printf(_("Failed to create the preferences file %s."), - Glib::filename_to_utf8(_prefs_filename).data()); + Glib::filename_to_utf8(_prefs_filename).c_str()); _reportError(msg, not_saved); g_free(msg); return; } - + + if ( migrateFromDoc ) { + migrateDetails( migrateFromDoc, _prefs_doc ); + } + // The prefs file was just created. // We can return now and skip the rest of the load process. _writable = true; return; } - + // Yes, the pref file exists. + Glib::ustring errMsg; + Inkscape::XML::Document *prefs_read = loadImpl( _prefs_filename, errMsg ); + + if ( prefs_read ) { + // Merge the loaded prefs with defaults. + _prefs_doc->root()->mergeFrom(prefs_read->root(), "id"); + Inkscape::GC::release(prefs_read); + _writable = true; + } else { + _reportError(errMsg, not_saved); + } +} + +//_reportError(msg, not_saved); +static Inkscape::XML::Document *loadImpl( std::string const& prefsFilename, Glib::ustring & errMsg ) +{ // 2. Is it a regular file? - if (!g_file_test(_prefs_filename.data(), G_FILE_TEST_IS_REGULAR)) { - //_reportError(Glib::ustring::compose(_("The preferences file %1 is not a regular file."), - // Glib::filename_to_utf8(_prefs_filename)), not_saved); + if (!g_file_test(prefsFilename.c_str(), G_FILE_TEST_IS_REGULAR)) { gchar *msg = g_strdup_printf(_("The preferences file %s is not a regular file."), - Glib::filename_to_utf8(_prefs_filename).data()); - _reportError(msg, not_saved); + Glib::filename_to_utf8(prefsFilename).c_str()); + errMsg = msg; g_free(msg); - return; + return 0; } - + // 3. Is the file readable? gchar *prefs_xml = NULL; gsize len = 0; - if (!g_file_get_contents(_prefs_filename.data(), &prefs_xml, &len, NULL)) { - //_reportError(Glib::ustring::compose(_("The preferences file %1 could not be read."), - // Glib::filename_to_utf8(_prefs_filename)), not_saved); + if (!g_file_get_contents(prefsFilename.c_str(), &prefs_xml, &len, NULL)) { gchar *msg = g_strdup_printf(_("The preferences file %s could not be read."), - Glib::filename_to_utf8(_prefs_filename).data()); - _reportError(msg, not_saved); + Glib::filename_to_utf8(prefsFilename).c_str()); + errMsg = msg; g_free(msg); - return; + return 0; } + // 4. Is it valid XML? Inkscape::XML::Document *prefs_read = sp_repr_read_mem(prefs_xml, len, NULL); g_free(prefs_xml); if (!prefs_read) { - //_reportError(Glib::ustring::compose(_("The preferences file %1 is not a valid XML document."), - // Glib::filename_to_utf8(_prefs_filename)), not_saved); gchar *msg = g_strdup_printf(_("The preferences file %s is not a valid XML document."), - Glib::filename_to_utf8(_prefs_filename).data()); - _reportError(msg, not_saved); + Glib::filename_to_utf8(prefsFilename).c_str()); + errMsg = msg; g_free(msg); - return; + return 0; } + // 5. Basic sanity check: does the root element have a correct name? if (strcmp(prefs_read->root()->name(), "inkscape")) { - //_reportError(Glib::ustring::compose(_("The file %1 is not a valid Inkscape preferences file."), - // Glib::filename_to_utf8(_prefs_filename)), not_saved); gchar *msg = g_strdup_printf(_("The file %s is not a valid Inkscape preferences file."), - Glib::filename_to_utf8(_prefs_filename).data()); - _reportError(msg, not_saved); + Glib::filename_to_utf8(prefsFilename).c_str()); + errMsg = msg; g_free(msg); Inkscape::GC::release(prefs_read); - return; + return 0; } - - // Merge the loaded prefs with defaults. - _prefs_doc->root()->mergeFrom(prefs_read->root(), "id"); - Inkscape::GC::release(prefs_read); - _writable = true; + + return prefs_read; +} + +static void migrateDetails( Inkscape::XML::Document *from, Inkscape::XML::Document *to ) +{ + // TODO pull in additional prefs with more granularity + to->root()->mergeFrom(from->root(), "id"); } /** @@ -212,18 +259,107 @@ void Preferences::_load() */ void Preferences::save() { - if (!_writable) return; // no-op if the prefs file is not writable - - // sp_repr_save_file uses utf-8 instead of the glib filename encoding. - // I don't know why filenames are kept in utf-8 in Inkscape and then - // converted to filename encoding when necessary through special functions - // - wouldn't it be easier to keep things in the encoding they are supposed - // to be in? - Glib::ustring utf8name = Glib::filename_to_utf8(_prefs_filename); - if (utf8name.empty()) return; - sp_repr_save_file(_prefs_doc, utf8name.data()); + // no-op if the prefs file is not writable + if (_writable) { + // sp_repr_save_file uses utf-8 instead of the glib filename encoding. + // I don't know why filenames are kept in utf-8 in Inkscape and then + // converted to filename encoding when necessary through special functions + // - wouldn't it be easier to keep things in the encoding they are supposed + // to be in? + + // No, it would not. There are many reasons, one key reason being that the + // rest of GTK+ is explicitly UTF-8. From an engineering standpoint, keeping + // the filesystem encoding would change things from a one-to-many problem to + // instead be a many-to-many problem. Also filesystem encoding can change + // from one run of the program to the next, so can not be stored. + // There are many other factors, so ask if you would like to learn them. - JAC + Glib::ustring utf8name = Glib::filename_to_utf8(_prefs_filename); + if (!utf8name.empty()) { + sp_repr_save_file(_prefs_doc, utf8name.c_str()); + } + } } +bool Preferences::getLastError( Glib::ustring& primary, Glib::ustring& secondary ) +{ + bool result = _hasError; + if ( _hasError ) { + primary = _lastErrPrimary; + secondary = _lastErrSecondary; + _hasError = false; + _lastErrPrimary.clear(); + _lastErrSecondary.clear(); + } else { + primary.clear(); + secondary.clear(); + } + return result; +} + +void Preferences::migrate( std::string const& legacyDir, std::string const& prefdir ) +{ + int mode = S_IRWXU; +#ifdef S_IRGRP + mode |= S_IRGRP; +#endif +#ifdef S_IXGRP + mode |= S_IXGRP; +#endif +#ifdef S_IXOTH + mode |= S_IXOTH; +#endif + if ( g_mkdir_with_parents(prefdir.c_str(), mode) == -1 ) { + } else { + } + + gchar * oldPrefFile = g_build_filename(legacyDir.c_str(), PREFERENCES_FILE_NAME, NULL); + if (oldPrefFile) { + if (g_file_test(oldPrefFile, G_FILE_TEST_EXISTS)) { + Glib::ustring errMsg; + Inkscape::XML::Document *oldPrefs = loadImpl( oldPrefFile, errMsg ); + if (oldPrefs) { + Glib::ustring docId("documents"); + Glib::ustring recentId("recent"); + Inkscape::XML::Node *node = oldPrefs->root(); + Inkscape::XML::Node *child = 0; + Inkscape::XML::Node *recentNode = 0; + if (node->attribute("version")) { + node->setAttribute("version", "1"); + } + for (child = node->firstChild(); child; child = child->next()) { + if (docId == child->attribute("id")) { + for (child = child->firstChild(); child; child = child->next()) { + if (recentId == child->attribute("id")) { + recentNode = child; + for (child = child->firstChild(); child; child = child->next()) { + gchar const* uri = child->attribute("uri"); + if (uri) { + file_add_recent(uri); + } + } + break; + } + } + break; + } + } + + if (recentNode) { + while (recentNode->firstChild()) { + recentNode->removeChild(recentNode->firstChild()); + } + } + migrateFromDoc = oldPrefs; + //Inkscape::GC::release(oldPrefs); + oldPrefs = 0; + } else { + g_warning( "%s", errMsg.c_str() ); + } + } + g_free(oldPrefFile); + oldPrefFile = 0; + } +} // Now for the meat. @@ -236,12 +372,13 @@ std::vector Preferences::getAllEntries(Glib::ustring const & { std::vector temp; Inkscape::XML::Node *node = _getNode(path, false); - if (!node) return temp; - - // argh - purge this Util::List nonsense from XML classes fast - Inkscape::Util::List alist = node->attributeList(); - for (; alist; ++alist) - temp.push_back( Entry(path + '/' + g_quark_to_string(alist->key), static_cast(alist->value.pointer())) ); + if (node) { + // argh - purge this Util::List nonsense from XML classes fast + Inkscape::Util::List alist = node->attributeList(); + for (; alist; ++alist) { + temp.push_back( Entry(path + '/' + g_quark_to_string(alist->key), static_cast(alist->value.pointer())) ); + } + } return temp; } @@ -254,10 +391,10 @@ std::vector Preferences::getAllDirs(Glib::ustring const &path) { std::vector temp; Inkscape::XML::Node *node = _getNode(path, false); - if (!node) return temp; - - for (Inkscape::XML::NodeSiblingIterator i = node->firstChild(); i; ++i) { - temp.push_back(path + '/' + i->attribute("id")); + if (node) { + for (Inkscape::XML::NodeSiblingIterator i = node->firstChild(); i; ++i) { + temp.push_back(path + '/' + i->attribute("id")); + } } return temp; } @@ -310,6 +447,13 @@ void Preferences::setDouble(Glib::ustring const &pref_path, double value) _setRawValue(pref_path, buf); } +void Preferences::setColor(Glib::ustring const &pref_path, guint32 value) +{ + gchar buf[16]; + g_snprintf(buf, 16, "#%08x", value); + _setRawValue(pref_path, buf); +} + /** * @brief Set a string attribute of a preference * @param pref_path Path of the preference to modify @@ -317,7 +461,7 @@ void Preferences::setDouble(Glib::ustring const &pref_path, double value) */ void Preferences::setString(Glib::ustring const &pref_path, Glib::ustring const &value) { - _setRawValue(pref_path, value.data()); + _setRawValue(pref_path, value.c_str()); } void Preferences::setStyle(Glib::ustring const &pref_path, SPCSSAttr *style) @@ -367,33 +511,34 @@ void Preferences::PrefNodeObserver::notifyAttributeChanged(XML::Node &node, GQua { // filter out attributes we don't watch gchar const *attr_name = g_quark_to_string(name); - if ( !_filter.empty() && _filter != attr_name ) return; - - _ObserverData *d = static_cast<_ObserverData*>(Preferences::_get_pref_observer_data(_observer)); - Glib::ustring notify_path = _observer.observed_path; - - if (!d->_is_attr) { - std::vector path_fragments; - notify_path.reserve(256); // this will make appending operations faster - - // walk the XML tree, saving each of the id attributes in a vector - // we terminate when we hit the observer's attachment node, because the path to this node - // is already stored in notify_path - for (XML::NodeParentIterator n = &node; static_cast(n) != d->_node; ++n) - path_fragments.push_back(n->attribute("id")); - // assemble the elements into a path - for (std::vector::reverse_iterator i = path_fragments.rbegin(); i != path_fragments.rend(); ++i) { + if ( _filter.empty() || (_filter == attr_name) ) { + _ObserverData *d = static_cast<_ObserverData*>(Preferences::_get_pref_observer_data(_observer)); + Glib::ustring notify_path = _observer.observed_path; + + if (!d->_is_attr) { + std::vector path_fragments; + notify_path.reserve(256); // this will make appending operations faster + + // walk the XML tree, saving each of the id attributes in a vector + // we terminate when we hit the observer's attachment node, because the path to this node + // is already stored in notify_path + for (XML::NodeParentIterator n = &node; static_cast(n) != d->_node; ++n) { + path_fragments.push_back(n->attribute("id")); + } + // assemble the elements into a path + for (std::vector::reverse_iterator i = path_fragments.rbegin(); i != path_fragments.rend(); ++i) { + notify_path.push_back('/'); + notify_path.append(*i); + } + + // append attribute name notify_path.push_back('/'); - notify_path.append(*i); + notify_path.append(attr_name); } - // append attribute name - notify_path.push_back('/'); - notify_path.append(attr_name); + Entry const val = Preferences::_create_pref_value(notify_path, static_cast(new_value.pointer())); + _observer.notify(val); } - - Entry const val = Preferences::_create_pref_value(notify_path, static_cast(new_value.pointer())); - _observer.notify(val); } /** @@ -403,7 +548,7 @@ XML::Node *Preferences::_findObserverNode(Glib::ustring const &pref_path, Glib:: { // first assume that the last path element is an entry. _keySplit(pref_path, node_key, attr_key); - + // find the node corresponding to the "directory". Inkscape::XML::Node *node = _getNode(node_key, create), *child; for (child = node->firstChild(); child; child = child->next()) { @@ -423,45 +568,47 @@ XML::Node *Preferences::_findObserverNode(Glib::ustring const &pref_path, Glib:: void Preferences::addObserver(Observer &o) { // prevent adding the same observer twice - if ( _observer_map.find(&o) != _observer_map.end() ) return; - - Glib::ustring node_key, attr_key; - Inkscape::XML::Node *node; - node = _findObserverNode(o.observed_path, node_key, attr_key, false); - if (!node) return; - - // set additional data - _ObserverData *priv_data = new _ObserverData; - priv_data->_node = node; - priv_data->_is_attr = !attr_key.empty(); - o._data = static_cast(priv_data); - - _observer_map[&o] = new PrefNodeObserver(o, attr_key); - - // if we watch a single pref, we want to receive notifications only for a single node - if (priv_data->_is_attr) { - node->addObserver( *(_observer_map[&o]) ); - } else { - node->addSubtreeObserver( *(_observer_map[&o]) ); + if ( _observer_map.find(&o) == _observer_map.end() ) { + Glib::ustring node_key, attr_key; + Inkscape::XML::Node *node; + node = _findObserverNode(o.observed_path, node_key, attr_key, false); + if (node) { + // set additional data + _ObserverData *priv_data = new _ObserverData; + priv_data->_node = node; + priv_data->_is_attr = !attr_key.empty(); + o._data = static_cast(priv_data); + + _observer_map[&o] = new PrefNodeObserver(o, attr_key); + + // if we watch a single pref, we want to receive notifications only for a single node + if (priv_data->_is_attr) { + node->addObserver( *(_observer_map[&o]) ); + } else { + node->addSubtreeObserver( *(_observer_map[&o]) ); + } + } } } void Preferences::removeObserver(Observer &o) { // prevent removing an observer which was not added - if ( _observer_map.find(&o) == _observer_map.end() ) return; - Inkscape::XML::Node *node = static_cast<_ObserverData*>(o._data)->_node; - _ObserverData *priv_data = static_cast<_ObserverData*>(o._data); - o._data = NULL; - - if (priv_data->_is_attr) - node->removeObserver( *(_observer_map[&o]) ); - else - node->removeSubtreeObserver( *(_observer_map[&o]) ); + if ( _observer_map.find(&o) != _observer_map.end() ) { + Inkscape::XML::Node *node = static_cast<_ObserverData*>(o._data)->_node; + _ObserverData *priv_data = static_cast<_ObserverData*>(o._data); + o._data = NULL; + + if (priv_data->_is_attr) { + node->removeObserver( *(_observer_map[&o]) ); + } else { + node->removeSubtreeObserver( *(_observer_map[&o]) ); + } - delete priv_data; - delete _observer_map[&o]; - _observer_map.erase(&o); + delete priv_data; + delete _observer_map[&o]; + _observer_map.erase(&o); + } } @@ -482,41 +629,47 @@ Inkscape::XML::Node *Preferences::_getNode(Glib::ustring const &pref_key, bool c // No longer necessary, can cause problems with input devices which have a dot in the name // g_assert( pref_key.find('.') == Glib::ustring::npos ); - Inkscape::XML::Node *node = _prefs_doc->root(), *child = NULL; - gchar **splits = g_strsplit(pref_key.data(), "/", 0); - - if ( splits == NULL ) return node; - - for (int part_i = 0; splits[part_i]; ++part_i) { - // skip empty path segments - if (!splits[part_i][0]) continue; - - for (child = node->firstChild(); child; child = child->next()) - if (!strcmp(splits[part_i], child->attribute("id"))) break; - - // If the previous loop found a matching key, child now contains the node - // matching the processed key part. If no node was found then it is NULL. - if (!child) { - if (create) { - // create the rest of the key - while(splits[part_i]) { - child = node->document()->createElement("group"); - child->setAttribute("id", splits[part_i]); - node->appendChild(child); - - ++part_i; - node = child; + Inkscape::XML::Node *node = _prefs_doc->root(); + Inkscape::XML::Node *child = NULL; + gchar **splits = g_strsplit(pref_key.c_str(), "/", 0); + + if ( splits ) { + for (int part_i = 0; splits[part_i]; ++part_i) { + // skip empty path segments + if (!splits[part_i][0]) { + continue; + } + + for (child = node->firstChild(); child; child = child->next()) { + if (!strcmp(splits[part_i], child->attribute("id"))) { + break; } - g_strfreev(splits); - return node; - } else { - return NULL; } - } - node = child; + // If the previous loop found a matching key, child now contains the node + // matching the processed key part. If no node was found then it is NULL. + if (!child) { + if (create) { + // create the rest of the key + while(splits[part_i]) { + child = node->document()->createElement("group"); + child->setAttribute("id", splits[part_i]); + node->appendChild(child); + + ++part_i; + node = child; + } + g_strfreev(splits); + return node; + } else { + return NULL; + } + } + + node = child; + } + g_strfreev(splits); } - g_strfreev(splits); return node; } @@ -525,13 +678,13 @@ void Preferences::_getRawValue(Glib::ustring const &path, gchar const *&result) // create node and attribute keys Glib::ustring node_key, attr_key; _keySplit(path, node_key, attr_key); - + // retrieve the attribute Inkscape::XML::Node *node = _getNode(node_key, false); if ( node == NULL ) { result = NULL; } else { - gchar const *attr = node->attribute(attr_key.data()); + gchar const *attr = node->attribute(attr_key.c_str()); if ( attr == NULL ) { result = NULL; } else { @@ -545,10 +698,10 @@ void Preferences::_setRawValue(Glib::ustring const &path, gchar const *value) // create node and attribute keys Glib::ustring node_key, attr_key; _keySplit(path, node_key, attr_key); - + // set the attribute Inkscape::XML::Node *node = _getNode(node_key, true); - node->setAttribute(attr_key.data(), value); + node->setAttribute(attr_key.c_str(), value); } // The _extract* methods are where the actual wrok is done - they define how preferences are stored @@ -557,16 +710,23 @@ void Preferences::_setRawValue(Glib::ustring const &path, gchar const *value) bool Preferences::_extractBool(Entry const &v) { gchar const *s = static_cast(v._value); - if ( !s[0] || !strcmp(s, "0") || !strcmp(s, "false") ) return false; - return true; + if ( !s[0] || !strcmp(s, "0") || !strcmp(s, "false") ) { + return false; + } else { + return true; + } } int Preferences::_extractInt(Entry const &v) { gchar const *s = static_cast(v._value); - if ( !strcmp(s, "true") ) return true; - if ( !strcmp(s, "false") ) return false; - return atoi(s); + if ( !strcmp(s, "true") ) { + return true; + } else if ( !strcmp(s, "false") ) { + return false; + } else { + return atoi(s); + } } double Preferences::_extractDouble(Entry const &v) @@ -580,6 +740,20 @@ Glib::ustring Preferences::_extractString(Entry const &v) return Glib::ustring(static_cast(v._value)); } +guint32 Preferences::_extractColor(Entry const &v) +{ + gchar const *s = static_cast(v._value); + std::istringstream hr(s); + guint32 color; + if (s[0] == '#') { + hr.ignore(1); + hr >> std::hex >> color; + } else { + hr >> color; + } + return color; +} + SPCSSAttr *Preferences::_extractStyle(Entry const &v) { SPCSSAttr *style = sp_repr_css_attr_new(); @@ -594,9 +768,9 @@ SPCSSAttr *Preferences::_extractInheritedStyle(Entry const &v) // we'll have to walk up the tree and call sp_repr_css_attr_add_from_string Glib::ustring node_key, attr_key; _keySplit(v._pref_path, node_key, attr_key); - + Inkscape::XML::Node *node = _getNode(node_key, false); - return sp_repr_css_attr_inherited(node, attr_key.data()); + return sp_repr_css_attr_inherited(node, attr_key.c_str()); } // XML backend helper: Split the path into a node key and an attribute key. @@ -610,6 +784,9 @@ void Preferences::_keySplit(Glib::ustring const &pref_path, Glib::ustring &node_ void Preferences::_reportError(Glib::ustring const &msg, Glib::ustring const &secondary) { + _hasError = true; + _lastErrPrimary = msg; + _lastErrSecondary = secondary; if (_errorHandler) { _errorHandler->handleError(msg, secondary); } @@ -627,9 +804,11 @@ void Preferences::setErrorHandler(ErrorReporter* handler) void Preferences::unload(bool save) { - if(_instance) + if (_instance) { - if (save) _instance->save(); + if (save) { + _instance->save(); + } delete _instance; _instance = NULL; } @@ -639,7 +818,7 @@ Preferences *Preferences::_instance = NULL; } // namespace Inkscape - + /* Local Variables: mode:c++ @@ -649,4 +828,4 @@ Preferences *Preferences::_instance = NULL; fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :