From a4d0a358424440128cd4c4fb2915ccc4b86f4587 Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Thu, 5 May 2011 23:21:51 -0700 Subject: Adding initial cut of resource manager. (bzr r10198) --- src/resource-manager.cpp | 272 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 src/resource-manager.cpp (limited to 'src/resource-manager.cpp') 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 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include +#include +#include +#include +#include +#include + +#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 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 locateLinks(Glib::ustring const & docbase, std::vector 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 ResourceManagerImpl::findBrokenLinks( SPDocument *doc ) +{ + std::vector result; + std::set uniques; + + if ( doc ) { + GSList const *images = doc->getResourceList("image"); + for (GSList const *it = images; it; it = it->next) { + Inkscape::XML::Node *ir = static_cast(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 ResourceManagerImpl::locateLinks(Glib::ustring const & docbase, std::vector const & brokenLinks) +{ + std::map result; + + // At the moment we expect this list to contain file:// references, or simple relative or absolute paths. + for ( std::vector::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 brokenHrefs = findBrokenLinks(doc); + if ( !brokenHrefs.empty() ) { + // TODO debug g_message(" FOUND SOME LINKS %d", brokenHrefs.size()); + for ( std::vector::iterator it = brokenHrefs.begin(); it != brokenHrefs.end(); ++it ) { + // TODO debug g_message(" [%s]", it->c_str()); + } + } + + std::map mapping = locateLinks(doc->getBase(), brokenHrefs); + for ( std::map::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(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 : -- cgit v1.2.3 From f365062bdb05d23dbf33073af566f98002ada583 Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Mon, 9 May 2011 23:49:35 -0700 Subject: Added simple usage of most recent file locations. (bzr r10204) --- src/resource-manager.cpp | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) (limited to 'src/resource-manager.cpp') diff --git a/src/resource-manager.cpp b/src/resource-manager.cpp index a68b2c7ae..0ccc05d49 100644 --- a/src/resource-manager.cpp +++ b/src/resource-manager.cpp @@ -8,11 +8,13 @@ #include #include +#include #include #include #include #include #include +#include #include "resource-manager.h" @@ -132,6 +134,25 @@ std::map ResourceManagerImpl::locateLinks(Glib::us { std::map result; + + // Note: we use a vector because we want them to stay in order: + std::vector priorLocations; + + Glib::RefPtr recentMgr = Gtk::RecentManager::get_default(); + std::vector< Glib::RefPtr > recentItems = recentMgr->get_items(); + for ( std::vector< Glib::RefPtr >::iterator it = recentItems.begin(); it != recentItems.end(); ++it ) { + Glib::ustring uri = (*it)->get_uri(); + std::string scheme = Glib::uri_parse_scheme(uri); + if ( scheme == "file" ) { + std::string path = Glib::filename_from_uri(uri); + path = Glib::path_get_dirname(path); + if ( std::find(priorLocations.begin(), priorLocations.end(), path) == priorLocations.end() ) { + // TODO debug g_message(" ==>[%s]", path.c_str()); + priorLocations.push_back(path); + } + } + } + // At the moment we expect this list to contain file:// references, or simple relative or absolute paths. for ( std::vector::const_iterator it = brokenLinks.begin(); it != brokenLinks.end(); ++it ) { // TODO debug g_message("========{%s}", it->c_str()); @@ -139,6 +160,7 @@ std::map ResourceManagerImpl::locateLinks(Glib::us std::string uri; if ( extractFilepath( *it, uri ) ) { // We were able to get some path. Check it + std::string origPath = uri; if ( !Glib::path_is_absolute(uri) ) { uri = Glib::build_filename(docbase, uri); @@ -165,11 +187,25 @@ std::map ResourceManagerImpl::locateLinks(Glib::us 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; + } + + if ( !exists ) { + // TODO debug g_message("Expanding the search..."); + + // Check if the MRU bases point us to it. + if ( !Glib::path_is_absolute(origPath) ) { + for ( std::vector::iterator it = priorLocations.begin(); !exists && (it != priorLocations.end()); ++it ) { + remainder = Glib::build_filename( *it, origPath ); + exists = Glib::file_test( remainder, Glib::FILE_TEST_EXISTS ); + } } } + + if ( exists ) { + bool isAbsolute = Glib::path_is_absolute( remainder ); + Glib::ustring replacement = isAbsolute ? Glib::filename_to_uri( remainder ) : Glib::filename_to_utf8( remainder ); + result[*it] = replacement; + } } } } @@ -186,7 +222,7 @@ bool ResourceManagerImpl::fixupBrokenLinks(SPDocument *doc) std::vector brokenHrefs = findBrokenLinks(doc); if ( !brokenHrefs.empty() ) { - // TODO debug g_message(" FOUND SOME LINKS %d", brokenHrefs.size()); + // TODO debug g_message(" FOUND SOME LINKS %d", static_cast(brokenHrefs.size())); for ( std::vector::iterator it = brokenHrefs.begin(); it != brokenHrefs.end(); ++it ) { // TODO debug g_message(" [%s]", it->c_str()); } -- cgit v1.2.3 From 010da2dbdf05c0fa2ea791cb9d75a558551c8413 Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Tue, 10 May 2011 00:48:37 -0700 Subject: Convert fixed paths to relative, including .. (bzr r10205) --- src/resource-manager.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'src/resource-manager.cpp') diff --git a/src/resource-manager.cpp b/src/resource-manager.cpp index 0ccc05d49..14a5ccfb8 100644 --- a/src/resource-manager.cpp +++ b/src/resource-manager.cpp @@ -25,6 +25,76 @@ namespace Inkscape { +std::vector splitPath( std::string const &path ) +{ + std::vector parts; + + std::string prior; + std::string tmp = path; + while ( !tmp.empty() && (tmp != prior) ) { + prior = tmp; + + parts.push_back( Glib::path_get_basename(tmp) ); + tmp = Glib::path_get_dirname(tmp); + } + if ( !parts.empty() ) { + std::reverse(parts.begin(), parts.end()); + } + + return parts; +} + +std::string convertPathToRelative( std::string const &path, std::string const &docbase ) +{ + std::string result = path; + + if ( !path.empty() && Glib::path_is_absolute(path) ) { + // Whack the parts into pieces + + std::vector parts = splitPath(path); + std::vector baseParts = splitPath(docbase); + + // TODO debug g_message("+++++++++++++++++++++++++"); + for ( std::vector::iterator it = parts.begin(); it != parts.end(); ++it ) { + // TODO debug g_message(" [%s]", it->c_str()); + } + // TODO debug g_message(" - - - - - - - - - - - - - - - "); + for ( std::vector::iterator it = baseParts.begin(); it != baseParts.end(); ++it ) { + // TODO debug g_message(" [%s]", it->c_str()); + } + // TODO debug g_message("+++++++++++++++++++++++++"); + + if ( !parts.empty() && !baseParts.empty() && (parts[0] == baseParts[0]) ) { + // Both paths have the same root. We can proceed. + while ( !parts.empty() && !baseParts.empty() && (parts[0] == baseParts[0]) ) { + parts.erase( parts.begin() ); + baseParts.erase( baseParts.begin() ); + } + + // TODO debug g_message("+++++++++++++++++++++++++"); + for ( std::vector::iterator it = parts.begin(); it != parts.end(); ++it ) { + // TODO debug g_message(" [%s]", it->c_str()); + } + // TODO debug g_message(" - - - - - - - - - - - - - - - "); + for ( std::vector::iterator it = baseParts.begin(); it != baseParts.end(); ++it ) { + // TODO debug g_message(" [%s]", it->c_str()); + } + // TODO debug g_message("+++++++++++++++++++++++++"); + + if ( !parts.empty() ) { + result.clear(); + + for ( size_t i = 0; i < baseParts.size(); ++i ) { + parts.insert(parts.begin(), ".."); + } + result = Glib::build_filename( parts ); + // TODO debug g_message("----> [%s]", result.c_str()); + } + } + } + + return result; +} class ResourceManagerImpl : public ResourceManager { @@ -202,6 +272,11 @@ std::map ResourceManagerImpl::locateLinks(Glib::us } if ( exists ) { + if ( Glib::path_is_absolute( remainder ) ) { + // TODO debug g_message("Need to convert to relative if possible [%s]", remainder.c_str()); + remainder = convertPathToRelative( remainder, docbase ); + } + bool isAbsolute = Glib::path_is_absolute( remainder ); Glib::ustring replacement = isAbsolute ? Glib::filename_to_uri( remainder ) : Glib::filename_to_utf8( remainder ); result[*it] = replacement; -- cgit v1.2.3 From 30b576108f09306c301c3f1ec2ea1a1a31d450e3 Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Wed, 11 May 2011 11:49:37 -0400 Subject: Fix fallback to MRU locations. (bzr r10207) --- src/resource-manager.cpp | 56 +++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 20 deletions(-) (limited to 'src/resource-manager.cpp') diff --git a/src/resource-manager.cpp b/src/resource-manager.cpp index 14a5ccfb8..b5cf67f91 100644 --- a/src/resource-manager.cpp +++ b/src/resource-manager.cpp @@ -39,6 +39,9 @@ std::vector splitPath( std::string const &path ) } if ( !parts.empty() ) { std::reverse(parts.begin(), parts.end()); + if ( (parts[0] == ".") && (path[0] != '.') ) { + parts.erase(parts.begin()); + } } return parts; @@ -124,6 +127,8 @@ public: bool extractFilepath( Glib::ustring const &href, std::string &uri ); + bool searchUpwards( std::string const &base, std::string const &subpath, std::string &dest ); + protected: }; @@ -239,25 +244,8 @@ std::map ResourceManagerImpl::locateLinks(Glib::us 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" : ""); - } + bool exists = searchUpwards( docbase, origPath, remainder ); if ( !exists ) { // TODO debug g_message("Expanding the search..."); @@ -265,8 +253,7 @@ std::map ResourceManagerImpl::locateLinks(Glib::us // Check if the MRU bases point us to it. if ( !Glib::path_is_absolute(origPath) ) { for ( std::vector::iterator it = priorLocations.begin(); !exists && (it != priorLocations.end()); ++it ) { - remainder = Glib::build_filename( *it, origPath ); - exists = Glib::file_test( remainder, Glib::FILE_TEST_EXISTS ); + exists = searchUpwards( *it, origPath, remainder ); } } } @@ -348,6 +335,35 @@ bool ResourceManagerImpl::fixupBrokenLinks(SPDocument *doc) } +bool ResourceManagerImpl::searchUpwards( std::string const &base, std::string const &subpath, std::string &dest ) +{ + bool exists = false; + // TODO debug g_message("............"); + + std::vector parts = splitPath(subpath); + std::vector baseParts = splitPath(base); + + while ( !exists && !baseParts.empty() ) { + std::vector current; + current.insert(current.begin(), parts.begin(), parts.end()); + // TODO debug g_message(" ---{%s}", Glib::build_filename( baseParts ).c_str()); + while ( !exists && !current.empty() ) { + std::vector combined; + combined.insert( combined.end(), baseParts.begin(), baseParts.end() ); + combined.insert( combined.end(), current.begin(), current.end() ); + std::string filepath = Glib::build_filename( combined ); + exists = Glib::file_test(filepath, Glib::FILE_TEST_EXISTS); + // TODO debug g_message(" ...[%s] %s", filepath.c_str(), (exists ? "XXX" : "")); + if ( exists ) { + dest = filepath; + } + current.erase( current.begin() ); + } + baseParts.pop_back(); + } + + return exists; +} static ResourceManagerImpl* theInstance = 0; -- cgit v1.2.3