/** @file
* Singleton class to access the preferences file - implementation.
*/
/* Authors:
* Krzysztof KosiĆski <tweenk.pl@gmail.com>
* Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2008,2009 Authors
*
* Released under GNU GPL. Read the file 'COPYING' for more information.
*/
#include <cstring>
#include <sstream>
#include <glibmm/fileutils.h>
#include <glib.h>
#include "preferences.h"
#include "preferences-skeleton.h"
#include "inkscape.h"
#include "xml/node-observer.h"
#include "xml/node-iterators.h"
#include "xml/attribute-record.h"
namespace Inkscape {
static Inkscape::XML::Document *loadImpl( std::string const& prefsFilename, Glib::ustring & errMsg );
// TODO clean up. Function copied from file.cpp:
// what gets passed here is not actually an URI... it is an UTF-8 encoded filename (!)
{
if (!uri) {
g_warning("file_add_recent: uri == NULL");
} else {
if (fn) {
if (uriToAdd) {
}
}
}
}
}
// private inner class definition
/**
* XML - prefs observer bridge.
*
* This is an XML node observer that watches for changes in the XML document storing the preferences.
* It is used to implement preference observers.
*/
public:
_observer(o),
{}
virtual ~PrefNodeObserver() {}
virtual void notifyAttributeChanged(XML::Node &node, GQuark name, Util::ptr_shared<char>, Util::ptr_shared<char>);
private:
};
_prefs_dir(""),
_prefs_filename(""),
_prefs_doc(0),
_errorHandler(0),
_writable(false),
_hasError(false)
{
// profile_path essentailly returns the argument prefixed by the profile directory.
// \TODO this is kinda hackish, but the alternative (strrchr) is worse
_prefs_dir = path;
_load();
}
{
// delete all PrefNodeObservers
delete (*i++).second; // avoids reference to a deleted key
}
// unref XML document
}
/**
* Load internal defaults.
*
* In the future this will try to load the system-wide file before falling
* back to the internal defaults.
*/
{
}
/**
* Load the user's customized preferences.
*
* Tries to load the user's preferences.xml file. If there is none, creates it.
*/
{
"and new settings will not be saved. ");
// NOTE: After we upgrade to Glib 2.16, use Glib::ustring::compose
// 1. Does the file exist?
// No - we need to create one.
// Does the profile directory exist?
// No - create the profile directory
// the creation failed
//_reportError(Glib::ustring::compose(_("Cannot create profile directory %1."),
// Glib::filename_to_utf8(_prefs_dir)), not_saved);
return;
}
// create some subdirectories for user stuff
for (int i=0; user_dirs[i]; ++i) {
}
// 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);
return;
}
// The profile dir exists and is valid.
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);
return;
}
if ( migrateFromDoc ) {
}
// 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.
if ( prefs_read ) {
// Merge the loaded prefs with defaults.
_writable = true;
} else {
}
}
//_reportError(msg, not_saved);
static Inkscape::XML::Document *loadImpl( std::string const& prefsFilename, Glib::ustring & errMsg )
{
// 2. Is it a regular file?
return 0;
}
// 3. Is the file readable?
return 0;
}
// 4. Is it valid XML?
if (!prefs_read) {
return 0;
}
// 5. Basic sanity check: does the root element have a correct name?
return 0;
}
return prefs_read;
}
{
// TODO pull in additional prefs with more granularity
}
/**
* Flush all pref changes to the XML file.
*/
{
// 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
}
}
}
{
if ( _hasError ) {
_hasError = false;
} else {
}
return result;
}
{
#ifdef S_IRGRP
#endif
#ifdef S_IXGRP
#endif
#ifdef S_IXOTH
#endif
} else {
}
if (oldPrefFile) {
if (oldPrefs) {
}
recentNode = child;
if (uri) {
}
}
break;
}
}
break;
}
}
if (recentNode) {
while (recentNode->firstChild()) {
}
}
//Inkscape::GC::release(oldPrefs);
oldPrefs = 0;
} else {
}
}
oldPrefFile = 0;
}
}
// Now for the meat.
/**
* Get names of all entries in the specified path.
*
* @param path Preference path to query.
* @return A vector containing all entries in the given directory.
*/
{
if (node) {
// argh - purge this Util::List nonsense from XML classes fast
temp.push_back( Entry(path + '/' + g_quark_to_string(alist->key), static_cast<void const*>(alist->value.pointer())) );
}
}
return temp;
}
/**
* Get the paths to all subdirectories of the specified path.
*
* @param path Preference path to query.
* @return A vector containing absolute paths to all subdirectories in the given path.
*/
{
if (node) {
}
}
return temp;
}
// getter methods
{
gchar const *v;
_getRawValue(pref_path, v);
}
// setter methods
/**
* Set a boolean attribute of a preference.
*
* @param pref_path Path of the preference to modify.
* @param value The new value of the pref attribute.
*/
{
/// @todo Boolean values should be stored as "true" and "false",
/// but this is not possible due to an interaction with event contexts.
/// Investigate this in depth.
}
/**
* Set an integer attribute of a preference.
*
* @param pref_path Path of the preference to modify.
* @param value The new value of the pref attribute.
*/
{
}
/**
* Set a floating point attribute of a preference.
*
* @param pref_path Path of the preference to modify.
* @param value The new value of the pref attribute.
*/
{
}
/**
* Set a floating point attribute of a preference.
*
* @param pref_path Path of the preference to modify.
* @param value The new value of the pref attribute.
* @param unit_abbr The string of the unit (abbreviated).
*/
void Preferences::setDoubleUnit(Glib::ustring const &pref_path, double value, Glib::ustring const &unit_abbr)
{
}
{
}
/**
* Set a string attribute of a preference.
*
* @param pref_path Path of the preference to modify.
* @param value The new value of the pref attribute.
*/
{
}
{
}
{
}
/**
* Remove an entry
* Make sure observers have been removed before calling
*/
{
}
}
/**
* Class that holds additional information for registered Observers.
*/
{
public:
};
_data(0)
{
}
{
// on destruction remove observer to prevent invalid references
prefs->removeObserver(*this);
}
void Preferences::PrefNodeObserver::notifyAttributeChanged(XML::Node &node, GQuark name, Util::ptr_shared<char>, Util::ptr_shared<char> new_value)
{
// filter out attributes we don't watch
if (!d->_is_attr) {
// 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
}
// assemble the elements into a path
for (std::vector<gchar const *>::reverse_iterator i = path_fragments.rbegin(); i != path_fragments.rend(); ++i) {
notify_path.append(*i);
}
// append attribute name
}
Entry const val = Preferences::_create_pref_value(notify_path, static_cast<void const*>(new_value.pointer()));
}
}
/**
* Find the XML node to observe.
*/
XML::Node *Preferences::_findObserverNode(Glib::ustring const &pref_path, Glib::ustring &node_key, Glib::ustring &attr_key, bool create)
{
// first assume that the last path element is an entry.
// find the node corresponding to the "directory".
// If there is a node with id corresponding to the attr key,
// this means that the last part of the path is actually a key (folder).
// Change values accordingly.
attr_key = "";
break;
}
}
return node;
}
{
// prevent adding the same observer twice
if (node) {
// set additional data
if (o._data) {
delete o._data;
}
// if we watch a single pref, we want to receive notifications only for a single node
} else {
}
}
}
}
{
// prevent removing an observer which was not added
o._data = 0;
} else {
}
delete priv_data;
priv_data = 0;
delete _observer_map[&o];
_observer_map.erase(&o);
}
}
/**
* Get the XML node corresponding to the given pref key.
*
* @param pref_key Preference key (path) to get.
* @param create Whether to create the corresponding node if it doesn't exist.
* @param separator The character used to separate parts of the pref key.
* @return XML node corresponding to the specified key.
*
* Derived from former inkscape_get_repr(). Private because it assumes that the backend is
* a flat XML file, which may not be the case e.g. if we are using GConf (in future).
*/
{
// verify path
// No longer necessary, can cause problems with input devices which have a dot in the name
// g_assert( pref_key.find('.') == Glib::ustring::npos );
if (_prefs_doc == NULL){
return NULL;
}
if ( splits ) {
// skip empty path segments
continue;
}
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
++part_i;
}
splits = 0;
return node;
} else {
splits = 0;
return NULL;
}
}
}
}
return node;
}
{
// create node and attribute keys
// retrieve the attribute
} else {
} else {
}
}
}
{
// create node and attribute keys
// set the attribute
}
// The _extract* methods are where the actual wrok is done - they define how preferences are stored
// in the XML file.
{
return false;
} else {
return true;
}
}
{
if ( !strcmp(s, "true") ) {
return true;
} else if ( !strcmp(s, "false") ) {
return false;
} else {
return atoi(s);
}
}
{
return g_ascii_strtod(s, NULL);
}
{
// no unit specified, don't do conversion
return val;
}
return val * (unit_table.getUnit(unit)->factor / unit_table.getUnit(requested_unit)->factor); /// \todo rewrite using Quantity class, so the standard code handles unit conversion
}
{
}
{
gchar const *e;
g_ascii_strtod(str, (char **) &e);
if (e == str) {
return "";
}
if (e[0] == 0) {
/* Unitless */
return "";
} else {
}
}
{
if (s[0] == '#') {
} else {
}
return color;
}
{
return style;
}
{
// This is the dirtiest extraction method. Generally we ignore whatever was in v._value
// and just get the style using sp_repr_css_attr_inherited. To implement this in GConf,
// we'll have to walk up the tree and call sp_repr_css_attr_add_from_string
}
// XML backend helper: Split the path into a node key and an attribute key.
void Preferences::_keySplit(Glib::ustring const &pref_path, Glib::ustring &node_key, Glib::ustring &attr_key)
{
// everything after the last slash
// everything before the last slash
}
{
_hasError = true;
if (_errorHandler) {
}
}
Preferences::Entry const Preferences::_create_pref_value(Glib::ustring const &path, void const *ptr)
{
}
{
}
{
if (_instance)
{
if (save) {
}
delete _instance;
}
}
} // namespace Inkscape
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :