summaryrefslogtreecommitdiffstats
path: root/src/resource-manager.cpp
diff options
context:
space:
mode:
authorJon A. Cruz <jon@joncruz.org>2011-05-06 06:21:51 +0000
committerJon A. Cruz <jon@joncruz.org>2011-05-06 06:21:51 +0000
commita4d0a358424440128cd4c4fb2915ccc4b86f4587 (patch)
tree818fc169950e0076d262bd8e633976afaafd7783 /src/resource-manager.cpp
parentsymbol rendering fix bug:705345 (diff)
downloadinkscape-a4d0a358424440128cd4c4fb2915ccc4b86f4587.tar.gz
inkscape-a4d0a358424440128cd4c4fb2915ccc4b86f4587.zip
Adding initial cut of resource manager.
(bzr r10198)
Diffstat (limited to 'src/resource-manager.cpp')
-rw-r--r--src/resource-manager.cpp272
1 files changed, 272 insertions, 0 deletions
diff --git a/src/resource-manager.cpp b/src/resource-manager.cpp
new file mode 100644
index 000000000..a68b2c7ae
--- /dev/null
+++ b/src/resource-manager.cpp
@@ -0,0 +1,272 @@
+/*
+ * Inkscape::ResourceManager - tracks external resources such as image and css files.
+ *
+ * Copyright 2011 Jon A. Cruz <jon@joncruz.org>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <string>
+#include <vector>
+#include <glibmm/i18n.h>
+#include <glibmm/convert.h>
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
+#include <glibmm/uriutils.h>
+
+#include "resource-manager.h"
+
+#include "document.h"
+#include "sp-object.h"
+#include "xml/node.h"
+#include "document-undo.h"
+
+namespace Inkscape {
+
+
+
+class ResourceManagerImpl : public ResourceManager {
+public:
+ ResourceManagerImpl();
+ virtual ~ResourceManagerImpl();
+
+ virtual bool fixupBrokenLinks(SPDocument *doc);
+
+
+ /**
+ * Walk all links in a document and create a listing of unique broken links.
+ *
+ * @return a list of all broken links.
+ */
+ std::vector<Glib::ustring> findBrokenLinks(SPDocument *doc);
+
+ /**
+ * Resolve broken links as a whole and return a map for those that can be found.
+ *
+ * Note: this will allow for future enhancements including relinking to new locations
+ * with the most broken files found, etc.
+ *
+ * @return a map of found links.
+ */
+ std::map<Glib::ustring, Glib::ustring> locateLinks(Glib::ustring const & docbase, std::vector<Glib::ustring> const & brokenLinks);
+
+ bool extractFilepath( Glib::ustring const &href, std::string &uri );
+
+protected:
+};
+
+
+ResourceManagerImpl::ResourceManagerImpl()
+ : ResourceManager()
+{
+}
+
+ResourceManagerImpl::~ResourceManagerImpl()
+{
+}
+
+bool ResourceManagerImpl::extractFilepath( Glib::ustring const &href, std::string &uri )
+{
+ bool isFile = false;
+
+ uri.clear();
+
+ std::string scheme = Glib::uri_parse_scheme(href);
+ if ( !scheme.empty() ) {
+ // TODO debug g_message("Scheme is now [%s]", scheme.c_str());
+ if ( scheme == "file" ) {
+ // TODO debug g_message("--- is a file URI [%s]", href.c_str());
+
+ // throws Glib::ConvertError:
+ uri = Glib::filename_from_uri(href); // TODO see if we can get this to throw
+ // TODO debug g_message(" [%s]", uri.c_str());
+ isFile = true;
+ }
+ } else {
+ // No scheme. Assuming it is a file path (absolute or relative).
+ // throws Glib::ConvertError:
+ uri = Glib::filename_from_utf8( href );
+ isFile = true;
+ }
+
+ return isFile;
+}
+
+
+std::vector<Glib::ustring> ResourceManagerImpl::findBrokenLinks( SPDocument *doc )
+{
+ std::vector<Glib::ustring> result;
+ std::set<Glib::ustring> uniques;
+
+ if ( doc ) {
+ GSList const *images = doc->getResourceList("image");
+ for (GSList const *it = images; it; it = it->next) {
+ Inkscape::XML::Node *ir = static_cast<SPObject *>(it->data)->getRepr();
+
+ gchar const *href = ir->attribute("xlink:href");
+ if ( href && ( uniques.find(href) == uniques.end() ) ) {
+ std::string uri;
+ if ( extractFilepath( href, uri ) ) {
+ if ( Glib::path_is_absolute(uri) ) {
+ if ( !Glib::file_test(uri, Glib::FILE_TEST_EXISTS) ) {
+ result.push_back(href);
+ uniques.insert(href);
+ }
+ } else {
+ std::string combined = Glib::build_filename(doc->getBase(), uri);
+ if ( !Glib::file_test(uri, Glib::FILE_TEST_EXISTS) ) {
+ result.push_back(href);
+ uniques.insert(href);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+
+std::map<Glib::ustring, Glib::ustring> ResourceManagerImpl::locateLinks(Glib::ustring const & docbase, std::vector<Glib::ustring> const & brokenLinks)
+{
+ std::map<Glib::ustring, Glib::ustring> result;
+
+ // At the moment we expect this list to contain file:// references, or simple relative or absolute paths.
+ for ( std::vector<Glib::ustring>::const_iterator it = brokenLinks.begin(); it != brokenLinks.end(); ++it ) {
+ // TODO debug g_message("========{%s}", it->c_str());
+
+ std::string uri;
+ if ( extractFilepath( *it, uri ) ) {
+ // We were able to get some path. Check it
+
+ if ( !Glib::path_is_absolute(uri) ) {
+ uri = Glib::build_filename(docbase, uri);
+ // TODO debug g_message(" not absolute. Fixing up as [%s]", uri.c_str());
+ }
+
+ if ( !Glib::file_test(uri, Glib::FILE_TEST_EXISTS) ) {
+ // TODO debug g_message(" DOES NOT EXIST.");
+ std::string tmp = uri;
+ std::string prior;
+ std::string remainder;
+ bool exists = false;
+ while ( (tmp != prior) && !exists) {
+ prior = tmp;
+ std::string basename = Glib::path_get_basename(tmp);
+ tmp = Glib::path_get_dirname(tmp);
+ if ( remainder.empty() ) {
+ remainder = basename;
+ } else {
+ remainder = Glib::build_filename(basename, remainder);
+ }
+
+ std::string rebuild = Glib::build_filename(docbase, remainder);
+ exists = Glib::file_test(rebuild, Glib::FILE_TEST_EXISTS);
+
+ // TODO debug g_message(" [%s] [%s]%s", tmp.c_str(), remainder.c_str(), exists ? " XXXX" : "");
+ if ( exists ) {
+ Glib::ustring replacement = Glib::filename_to_utf8( remainder );
+ result[*it] = replacement;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+bool ResourceManagerImpl::fixupBrokenLinks(SPDocument *doc)
+{
+ bool changed = false;
+ if ( doc ) {
+ // TODO debug g_message("FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP");
+ // TODO debug g_message(" base is [%s]", doc->getBase());
+
+ std::vector<Glib::ustring> brokenHrefs = findBrokenLinks(doc);
+ if ( !brokenHrefs.empty() ) {
+ // TODO debug g_message(" FOUND SOME LINKS %d", brokenHrefs.size());
+ for ( std::vector<Glib::ustring>::iterator it = brokenHrefs.begin(); it != brokenHrefs.end(); ++it ) {
+ // TODO debug g_message(" [%s]", it->c_str());
+ }
+ }
+
+ std::map<Glib::ustring, Glib::ustring> mapping = locateLinks(doc->getBase(), brokenHrefs);
+ for ( std::map<Glib::ustring, Glib::ustring>::iterator it = mapping.begin(); it != mapping.end(); ++it )
+ {
+ // TODO debug g_message(" [%s] ==> {%s}", it->first.c_str(), it->second.c_str());
+ }
+
+ bool savedUndoState = DocumentUndo::getUndoSensitive(doc);
+ DocumentUndo::setUndoSensitive(doc, true);
+
+ GSList const *images = doc->getResourceList("image");
+ for (GSList const *it = images; it; it = it->next) {
+ Inkscape::XML::Node *ir = static_cast<SPObject *>(it->data)->getRepr();
+
+ gchar const *href = ir->attribute("xlink:href");
+ if ( href ) {
+ // TODO debug g_message(" consider [%s]", href);
+
+ if ( mapping.find(href) != mapping.end() ) {
+ // TODO debug g_message(" Found a replacement");
+
+ ir->setAttribute( "xlink:href", mapping[href].c_str() );
+ if ( ir->attribute( "sodipodi:absref" ) ) {
+ ir->setAttribute( "sodipodi:absref", 0 ); // Remove this attribute
+ }
+
+ SPObject *updated = doc->getObjectByRepr(ir);
+ if (updated) {
+ // force immediate update of dependant attributes
+ updated->updateRepr();
+ }
+
+ changed = true;
+ }
+ }
+ }
+ if ( changed ) {
+ DocumentUndo::done( doc, SP_VERB_DIALOG_XML_EDITOR, _("Fixup broken links") );
+ }
+ DocumentUndo::setUndoSensitive(doc, savedUndoState);
+ }
+
+ return changed;
+}
+
+
+
+
+static ResourceManagerImpl* theInstance = 0;
+
+ResourceManager::ResourceManager()
+ : Glib::Object()
+{
+}
+
+ResourceManager::~ResourceManager() {
+}
+
+ResourceManager& ResourceManager::getManager() {
+ if ( !theInstance ) {
+ theInstance = new ResourceManagerImpl();
+ }
+
+ return *theInstance;
+}
+
+
+} // 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 :