diff options
| author | Jon A. Cruz <jon@joncruz.org> | 2011-05-06 06:21:51 +0000 |
|---|---|---|
| committer | Jon A. Cruz <jon@joncruz.org> | 2011-05-06 06:21:51 +0000 |
| commit | a4d0a358424440128cd4c4fb2915ccc4b86f4587 (patch) | |
| tree | 818fc169950e0076d262bd8e633976afaafd7783 /src/resource-manager.cpp | |
| parent | symbol rendering fix bug:705345 (diff) | |
| download | inkscape-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.cpp | 272 |
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 : |
