a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz/*
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Inkscape::ResourceManager - tracks external resources such as image and css files.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz *
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Copyright 2011 Jon A. Cruz <jon@joncruz.org>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz *
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Released under GNU GPL, read the file 'COPYING' for more information
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <string>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <vector>
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz#include <algorithm>
5c45bb188ab729e501e48732842cb9de6a9813beAlex Valavanis#include <gtkmm/recentmanager.h>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <glibmm/i18n.h>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <glibmm/convert.h>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <glibmm/fileutils.h>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <glibmm/miscutils.h>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <glibmm/uriutils.h>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include "resource-manager.h"
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include "document.h"
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include "sp-object.h"
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include "xml/node.h"
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include "document-undo.h"
47badd0035ae8c9135c51444f3770b17ae504ddaAlex Valavanis#include "verbs.h"
47badd0035ae8c9135c51444f3770b17ae504ddaAlex Valavanis
47badd0035ae8c9135c51444f3770b17ae504ddaAlex Valavanis#include <set>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruznamespace Inkscape {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
17238dd97c572210f1036dd8a7a8657e67bfa9c3Campbell Bartonstatic std::vector<std::string> splitPath( std::string const &path )
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz{
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz std::vector<std::string> parts;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz std::string prior;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz std::string tmp = path;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz while ( !tmp.empty() && (tmp != prior) ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz prior = tmp;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz parts.push_back( Glib::path_get_basename(tmp) );
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz tmp = Glib::path_get_dirname(tmp);
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz if ( !parts.empty() ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz std::reverse(parts.begin(), parts.end());
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz if ( (parts[0] == ".") && (path[0] != '.') ) {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz parts.erase(parts.begin());
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz return parts;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz}
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
17238dd97c572210f1036dd8a7a8657e67bfa9c3Campbell Bartonstatic std::string convertPathToRelative( std::string const &path, std::string const &docbase )
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz{
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz std::string result = path;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz if ( !path.empty() && Glib::path_is_absolute(path) ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // Whack the parts into pieces
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz std::vector<std::string> parts = splitPath(path);
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz std::vector<std::string> baseParts = splitPath(docbase);
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message("+++++++++++++++++++++++++");
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz for ( std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); ++it ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message(" [%s]", it->c_str());
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message(" - - - - - - - - - - - - - - - ");
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz for ( std::vector<std::string>::iterator it = baseParts.begin(); it != baseParts.end(); ++it ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message(" [%s]", it->c_str());
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message("+++++++++++++++++++++++++");
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz if ( !parts.empty() && !baseParts.empty() && (parts[0] == baseParts[0]) ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // Both paths have the same root. We can proceed.
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz while ( !parts.empty() && !baseParts.empty() && (parts[0] == baseParts[0]) ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz parts.erase( parts.begin() );
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz baseParts.erase( baseParts.begin() );
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message("+++++++++++++++++++++++++");
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz for ( std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); ++it ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message(" [%s]", it->c_str());
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message(" - - - - - - - - - - - - - - - ");
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz for ( std::vector<std::string>::iterator it = baseParts.begin(); it != baseParts.end(); ++it ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message(" [%s]", it->c_str());
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message("+++++++++++++++++++++++++");
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz if ( !parts.empty() ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz result.clear();
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz for ( size_t i = 0; i < baseParts.size(); ++i ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz parts.insert(parts.begin(), "..");
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz result = Glib::build_filename( parts );
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message("----> [%s]", result.c_str());
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz return result;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzclass ResourceManagerImpl : public ResourceManager {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzpublic:
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ResourceManagerImpl();
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz virtual ~ResourceManagerImpl();
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz virtual bool fixupBrokenLinks(SPDocument *doc);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /**
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Walk all links in a document and create a listing of unique broken links.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz *
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * @return a list of all broken links.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::vector<Glib::ustring> findBrokenLinks(SPDocument *doc);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /**
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Resolve broken links as a whole and return a map for those that can be found.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz *
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Note: this will allow for future enhancements including relinking to new locations
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * with the most broken files found, etc.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz *
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * @return a map of found links.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::map<Glib::ustring, Glib::ustring> locateLinks(Glib::ustring const & docbase, std::vector<Glib::ustring> const & brokenLinks);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool extractFilepath( Glib::ustring const &href, std::string &uri );
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz bool searchUpwards( std::string const &base, std::string const &subpath, std::string &dest );
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzprotected:
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz};
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. CruzResourceManagerImpl::ResourceManagerImpl()
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz : ResourceManager()
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz{
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. CruzResourceManagerImpl::~ResourceManagerImpl()
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz{
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzbool ResourceManagerImpl::extractFilepath( Glib::ustring const &href, std::string &uri )
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz{
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool isFile = false;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz uri.clear();
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string scheme = Glib::uri_parse_scheme(href);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( !scheme.empty() ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message("Scheme is now [%s]", scheme.c_str());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( scheme == "file" ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message("--- is a file URI [%s]", href.c_str());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // throws Glib::ConvertError:
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz uri = Glib::filename_from_uri(href); // TODO see if we can get this to throw
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message(" [%s]", uri.c_str());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz isFile = true;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz } else {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // No scheme. Assuming it is a file path (absolute or relative).
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // throws Glib::ConvertError:
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz uri = Glib::filename_from_utf8( href );
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz isFile = true;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return isFile;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzstd::vector<Glib::ustring> ResourceManagerImpl::findBrokenLinks( SPDocument *doc )
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz{
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::vector<Glib::ustring> result;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::set<Glib::ustring> uniques;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( doc ) {
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin std::set<SPObject *> images = doc->getResourceList("image");
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin for (std::set<SPObject *>::const_iterator it = images.begin(); it != images.end(); ++it) {
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin Inkscape::XML::Node *ir = (*it)->getRepr();
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz gchar const *href = ir->attribute("xlink:href");
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( href && ( uniques.find(href) == uniques.end() ) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string uri;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( extractFilepath( href, uri ) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( Glib::path_is_absolute(uri) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( !Glib::file_test(uri, Glib::FILE_TEST_EXISTS) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz result.push_back(href);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz uniques.insert(href);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz } else {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string combined = Glib::build_filename(doc->getBase(), uri);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( !Glib::file_test(uri, Glib::FILE_TEST_EXISTS) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz result.push_back(href);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz uniques.insert(href);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return result;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzstd::map<Glib::ustring, Glib::ustring> ResourceManagerImpl::locateLinks(Glib::ustring const & docbase, std::vector<Glib::ustring> const & brokenLinks)
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz{
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::map<Glib::ustring, Glib::ustring> result;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz // Note: we use a vector because we want them to stay in order:
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz std::vector<std::string> priorLocations;
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz Glib::RefPtr<Gtk::RecentManager> recentMgr = Gtk::RecentManager::get_default();
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz std::vector< Glib::RefPtr<Gtk::RecentInfo> > recentItems = recentMgr->get_items();
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz for ( std::vector< Glib::RefPtr<Gtk::RecentInfo> >::iterator it = recentItems.begin(); it != recentItems.end(); ++it ) {
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz Glib::ustring uri = (*it)->get_uri();
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz std::string scheme = Glib::uri_parse_scheme(uri);
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz if ( scheme == "file" ) {
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini try {
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini std::string path = Glib::filename_from_uri(uri);
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini path = Glib::path_get_dirname(path);
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini if ( std::find(priorLocations.begin(), priorLocations.end(), path) == priorLocations.end() ) {
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini // TODO debug g_message(" ==>[%s]", path.c_str());
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini priorLocations.push_back(path);
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini }
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini } catch (Glib::ConvertError e) {
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini g_warning("Bad URL ignored [%s]", uri.c_str());
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz }
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz }
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz }
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // At the moment we expect this list to contain file:// references, or simple relative or absolute paths.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz for ( std::vector<Glib::ustring>::const_iterator it = brokenLinks.begin(); it != brokenLinks.end(); ++it ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message("========{%s}", it->c_str());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string uri;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( extractFilepath( *it, uri ) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // We were able to get some path. Check it
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz std::string origPath = uri;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( !Glib::path_is_absolute(uri) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz uri = Glib::build_filename(docbase, uri);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message(" not absolute. Fixing up as [%s]", uri.c_str());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( !Glib::file_test(uri, Glib::FILE_TEST_EXISTS) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message(" DOES NOT EXIST.");
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string remainder;
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz bool exists = searchUpwards( docbase, origPath, remainder );
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz if ( !exists ) {
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz // TODO debug g_message("Expanding the search...");
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz // Check if the MRU bases point us to it.
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz if ( !Glib::path_is_absolute(origPath) ) {
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz for ( std::vector<std::string>::iterator it = priorLocations.begin(); !exists && (it != priorLocations.end()); ++it ) {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz exists = searchUpwards( *it, origPath, remainder );
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz if ( exists ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz if ( Glib::path_is_absolute( remainder ) ) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz // TODO debug g_message("Need to convert to relative if possible [%s]", remainder.c_str());
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz remainder = convertPathToRelative( remainder, docbase );
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz bool isAbsolute = Glib::path_is_absolute( remainder );
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz Glib::ustring replacement = isAbsolute ? Glib::filename_to_uri( remainder ) : Glib::filename_to_utf8( remainder );
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz result[*it] = replacement;
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return result;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzbool ResourceManagerImpl::fixupBrokenLinks(SPDocument *doc)
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz{
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool changed = false;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( doc ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message("FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP");
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message(" base is [%s]", doc->getBase());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::vector<Glib::ustring> brokenHrefs = findBrokenLinks(doc);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( !brokenHrefs.empty() ) {
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz // TODO debug g_message(" FOUND SOME LINKS %d", static_cast<int>(brokenHrefs.size()));
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz for ( std::vector<Glib::ustring>::iterator it = brokenHrefs.begin(); it != brokenHrefs.end(); ++it ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message(" [%s]", it->c_str());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::map<Glib::ustring, Glib::ustring> mapping = locateLinks(doc->getBase(), brokenHrefs);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz for ( std::map<Glib::ustring, Glib::ustring>::iterator it = mapping.begin(); it != mapping.end(); ++it )
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message(" [%s] ==> {%s}", it->first.c_str(), it->second.c_str());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool savedUndoState = DocumentUndo::getUndoSensitive(doc);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz DocumentUndo::setUndoSensitive(doc, true);
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin std::set<SPObject *> images = doc->getResourceList("image");
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin for (std::set<SPObject *>::const_iterator it = images.begin(); it != images.end(); ++it) {
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin Inkscape::XML::Node *ir = (*it)->getRepr();
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz gchar const *href = ir->attribute("xlink:href");
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( href ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message(" consider [%s]", href);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( mapping.find(href) != mapping.end() ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // TODO debug g_message(" Found a replacement");
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ir->setAttribute( "xlink:href", mapping[href].c_str() );
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( ir->attribute( "sodipodi:absref" ) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ir->setAttribute( "sodipodi:absref", 0 ); // Remove this attribute
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz SPObject *updated = doc->getObjectByRepr(ir);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if (updated) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // force immediate update of dependant attributes
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz updated->updateRepr();
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz changed = true;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( changed ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz DocumentUndo::done( doc, SP_VERB_DIALOG_XML_EDITOR, _("Fixup broken links") );
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz DocumentUndo::setUndoSensitive(doc, savedUndoState);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return changed;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruzbool ResourceManagerImpl::searchUpwards( std::string const &base, std::string const &subpath, std::string &dest )
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz{
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz bool exists = false;
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz // TODO debug g_message("............");
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz std::vector<std::string> parts = splitPath(subpath);
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz std::vector<std::string> baseParts = splitPath(base);
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz while ( !exists && !baseParts.empty() ) {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz std::vector<std::string> current;
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz current.insert(current.begin(), parts.begin(), parts.end());
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz // TODO debug g_message(" ---{%s}", Glib::build_filename( baseParts ).c_str());
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz while ( !exists && !current.empty() ) {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz std::vector<std::string> combined;
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz combined.insert( combined.end(), baseParts.begin(), baseParts.end() );
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz combined.insert( combined.end(), current.begin(), current.end() );
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz std::string filepath = Glib::build_filename( combined );
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz exists = Glib::file_test(filepath, Glib::FILE_TEST_EXISTS);
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz // TODO debug g_message(" ...[%s] %s", filepath.c_str(), (exists ? "XXX" : ""));
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz if ( exists ) {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz dest = filepath;
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz }
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz current.erase( current.begin() );
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz }
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz baseParts.pop_back();
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz }
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz return exists;
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzstatic ResourceManagerImpl* theInstance = 0;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. CruzResourceManager::ResourceManager()
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz : Glib::Object()
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz{
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. CruzResourceManager::~ResourceManager() {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. CruzResourceManager& ResourceManager::getManager() {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( !theInstance ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz theInstance = new ResourceManagerImpl();
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return *theInstance;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz} // namespace Inkscape
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz/*
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz Local Variables:
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz mode:c++
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz c-file-style:"stroustrup"
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz indent-tabs-mode:nil
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz fill-column:99
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz End:
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz*/
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :