/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiWord * Copyright (c) 2010 GPL. V2+ copyright to AbiSource B.V. * This file was originally written by Ben Martin in 2010. * Updates by Ben Martin in 2011. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ #include "pd_DocumentRDF.h" #include "pd_Document.h" #include "pt_PieceTable.h" #include "ut_debugmsg.h" #include "pf_Frag_Object.h" #include "pf_Frag_Strux.h" #include "ut_std_string.h" #include "ut_conversion.h" #include "xap_App.h" #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pd_RDFQuery.h" #define DEBUG_LOWLEVEL_IO 0 typedef std::map< std::string, std::string > stringmap_t; /******************************/ /******************************/ /******************************/ class PD_SemanticItemFactoryNull : public PD_SemanticItemFactory { public: virtual PD_RDFContact* createContact(PD_DocumentRDFHandle /*rdf*/, PD_ResultBindings_t::iterator /*it*/) { return 0; } virtual PD_RDFEvent* createEvent(PD_DocumentRDFHandle /*rdf*/, PD_ResultBindings_t::iterator /*it*/) { return 0; } virtual PD_RDFLocation* createLocation(PD_DocumentRDFHandle /*rdf*/, PD_ResultBindings_t::iterator /*it*/, bool isGeo84 = false ) { UT_UNUSED(isGeo84); return 0; } }; PD_SemanticItemFactory *PD_DocumentRDF::s_SemanticItemFactory; PD_SemanticItemFactory *PD_DocumentRDF::getSemanticItemFactory() { if (!s_SemanticItemFactory) s_SemanticItemFactory = new PD_SemanticItemFactoryNull; return s_SemanticItemFactory; } void PD_DocumentRDF::setSemanticItemFactory( PD_SemanticItemFactory* f ) { s_SemanticItemFactory = f; } class PD_RDFDialogsNull : public PD_RDFDialogs { public: virtual void runSemanticStylesheetsDialog(FV_View* /*pView*/) { } virtual std::pair< PT_DocPosition, PT_DocPosition > runInsertReferenceDialog(FV_View* /*pView*/) { return std::make_pair(0,0); } }; PD_RDFDialogs *PD_DocumentRDF::s_RDFDialogs; PD_RDFDialogs *PD_DocumentRDF::getRDFDialogs() { if (!s_RDFDialogs) s_RDFDialogs = new PD_RDFDialogsNull; return s_RDFDialogs; } void PD_DocumentRDF::setRDFDialogs( PD_RDFDialogs* d ) { s_RDFDialogs = d; } std::pair< PT_DocPosition, PT_DocPosition > runInsertReferenceDialog( FV_View* pView ) { return PD_DocumentRDF::getRDFDialogs()->runInsertReferenceDialog( pView ); } void runSemanticStylesheetsDialog( FV_View* pView ) { PD_DocumentRDF::getRDFDialogs()->runSemanticStylesheetsDialog( pView ); } /******************************/ /******************************/ /******************************/ PD_RDFModel::PD_RDFModel() : m_version(0) { } void PD_RDFModel::incremenetVersion() { m_version++; } /** * Grab the first URI in the list or a default constructed one for empty lists. */ PD_URI PD_RDFModel::front( const PD_URIList& l ) const { if(l.empty()) { return PD_URI(); } return l.front(); } PD_Object PD_RDFModel::front( const PD_ObjectList& l ) const { if(l.empty()) { return PD_Object(); } return l.front(); } /** * Get an object which has the given subject and predicate. If there * are more than one such object, any one of those will be returned. * So you should only use this method when the RDF only allows a * single matching triple. */ PD_Object PD_RDFModel::getObject( const PD_URI& s, const PD_URI& p ) { PD_ObjectList l = getObjects(s,p); return front(l); } /** * Similar to getSubjects but returns any one of the matches if there are * more than one. Use this method when the RDF schema only allows a single * matching triple. */ PD_URI PD_RDFModel::getSubject( const PD_URI& p, const PD_Object& o ) { PD_URIList l = getSubjects( p,o ); return front(l); } PD_ObjectList PD_RDFModel::getObjects( const PD_URI& s, const PD_URI& p ) { PD_ObjectList ret; PD_RDFModelIterator iter = begin(); PD_RDFModelIterator e = end(); for( ; iter != e; ++iter ) { const PD_RDFStatement& st = *iter; if( st.getSubject() == s && st.getPredicate() == p ) { ret.push_back( st.getObject() ); } } return ret; } PD_URIList PD_RDFModel::getSubjects( const PD_URI& p, const PD_Object& o ) { PD_URIList ret; PD_RDFModelIterator iter = begin(); PD_RDFModelIterator e = end(); for( ; iter != e; ++iter ) { const PD_RDFStatement& st = *iter; if( st.getPredicate() == p && st.getObject() == o ) { ret.push_back( st.getSubject() ); } } return ret; } POCol PD_RDFModel::getArcsOut( const PD_URI& s ) { POCol ret; PD_RDFModelIterator iter = begin(); PD_RDFModelIterator e = end(); for( ; iter != e; ++iter ) { const PD_RDFStatement& st = *iter; if( st.getSubject() == s ) { ret.insert( std::make_pair( st.getPredicate(), st.getObject() )); } } return ret; } bool PD_RDFModel::contains( const PD_RDFStatement& st ) { return contains( st.getSubject(), st.getPredicate(), st.getObject() ); } /** * Test if the given triple is in the RDF or not. */ bool PD_RDFModel::contains( const PD_URI& s, const PD_URI& p, const PD_Object& o ) { PD_RDFStatement sought( s, p, o ); bool ret = false; PD_RDFModelIterator iter = begin(); PD_RDFModelIterator e = end(); for( ; iter != e; ++iter ) { const PD_RDFStatement& st = *iter; if( st == sought ) return true; } return ret; } long PD_RDFModel::getTripleCount() { long ret = 0; PD_RDFModelIterator iter = begin(); PD_RDFModelIterator e = end(); for( ; iter != e; ++iter ) { ++ret; } return ret; } /** * Get a list of every subject in the model. * If you want to get all triples, then first get all subjects * and then use getArcsOut() to get the predicate-object combinations * for each of the subjects. */ PD_URIList PD_RDFModel::getAllSubjects() { PD_URIList ret; PD_RDFModelIterator iter = begin(); PD_RDFModelIterator e = end(); for( ; iter != e; ++iter ) { const PD_RDFStatement& st = *iter; ret.push_back( st.getSubject() ); } return ret; } /** * Test if the given subject+predicate is in the RDF or not. */ bool PD_RDFModel::contains( const PD_URI& s, const PD_URI& p ) { PD_URI u = getObject( s, p ); return u.isValid(); } void PD_RDFModel::dumpModel( const std::string& headerMsg ) { UT_DEBUG_ONLY_ARG(headerMsg); #ifdef DEBUG PD_RDFModelIterator iter = begin(); PD_RDFModelIterator e = end(); UT_DEBUGMSG(("PD_RDFModel::dumpModel() ----------------------------------\n")); UT_DEBUGMSG(("PD_RDFModel::dumpModel() %s\n", headerMsg.c_str())); UT_DEBUGMSG(("PD_RDFModel::dumpModel() triple count:%ld\n", getTripleCount())); UT_DEBUGMSG(("PD_RDFModel::dumpModel() ----------------------------------\n")); for( ; iter != e; ++iter ) { PD_RDFStatement st = *iter; UT_DEBUGMSG(("PD_RDFModel::dumpModel() st:%s\n", st.toString().c_str() )); } UT_DEBUGMSG(("PD_RDFModel::dumpModel() --- done -------------------------\n")); #endif } std::string PD_RDFModel::uriToPrefixed( const std::string& uri ) { uriToPrefix_t& m = getUriToPrefix(); for( uriToPrefix_t::iterator iter = m.begin(); iter != m.end(); ++iter ) { const std::string& p = iter->second; const std::string& ns = iter->first; if( starts_with( uri, p )) { return ns + ":" + uri.substr(p.length()); } } return uri; } std::string PD_RDFModel::prefixedToURI( const std::string& prefixedstr ) { std::string::size_type colonLocation = prefixedstr.find(":"); if( colonLocation != std::string::npos ) { std::string prefix = prefixedstr.substr( 0, colonLocation ); std::string rest = prefixedstr.substr( colonLocation+1 ); uriToPrefix_t& m = getUriToPrefix(); uriToPrefix_t::iterator mi = m.find( prefix ); if( mi != m.end() ) { std::stringstream ss; ss << mi->second << rest; return ss.str(); } } return prefixedstr; } PD_RDFModel::uriToPrefix_t& PD_RDFModel::getUriToPrefix() { static uriToPrefix_t m; if( m.empty() ) { m.insert( std::make_pair( "pkg", "http://docs.oasis-open.org/opendocument/meta/package/common#" )); m.insert( std::make_pair( "odf", "http://docs.oasis-open.org/opendocument/meta/package/odf#" )); m.insert( std::make_pair( "rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#" )); m.insert( std::make_pair( "dcterms", "http://dublincore.org/documents/dcmi-terms/#" )); m.insert( std::make_pair( "cite", "http://docs.oasis-open.org/prototype/opendocument/citation#" )); m.insert( std::make_pair( "foaf", "http://xmlns.com/foaf/0.1/" )); m.insert( std::make_pair( "example", "http://www.example.org/xmlns/ex#" )); m.insert( std::make_pair( "geo84", "http://www.w3.org/2003/01/geo/wgs84_pos#" )); m.insert( std::make_pair( "rdfs", "http://www.w3.org/2000/01/rdf-schema#" )); m.insert( std::make_pair( "dc", "http://purl.org/dc/elements/1.1/" )); m.insert( std::make_pair( "cal", "http://www.w3.org/2002/12/cal/icaltzd#" )); m.insert( std::make_pair( "abifoaf", "http://abicollab.net/rdf/foaf#" )); } return m; } /** * Read a string which is prefixed with it's length in ascii from the * given stream. * @param iss stream to read length and string from * @return string */ static std::string readLengthPrefixedString( std::istream& iss ) { char ch; int len = 0; iss >> len >> std::noskipws >> ch; #if DEBUG if( DEBUG_LOWLEVEL_IO ) { off_t loc = iss.tellg(); UT_DEBUGMSG(("PD_DocumentRDF::readLengthPrefixedString() len:%d loc:%ld\n", len, (long)loc)); } #endif char* p = new char[len+2]; memset( p, 0, len+2 ); iss.read( p, len ); std::string ret = p; delete [] p; return ret; } /** * Given a string z, create a new string which contains the length of z * as an ascii string, a space and then z itself. * @param s the string z to create a length z string from * @return a string containing the length of z, a space, then z */ static std::string createLengthPrefixedString( const std::string& s ) { std::stringstream ss; ss << s.length() << " " << s; return ss.str(); } /** * Given an predicate and object, create a serialized "packed" double of these two. * @see splitPO() */ static std::string combinePO(const PD_URI& p, const PD_Object& o ) { std::stringstream ss; p.write(ss); o.write(ss); return ss.str(); } /** * Split up a packed double that contains a predicate and object. * @see combinePO() */ static std::pair< PD_URI, PD_Object > splitPO( const std::string& po ) { std::stringstream ss; ss << po; PD_URI p; PD_Object o; p.read( ss ); o.read( ss ); return std::make_pair( p, o ); } /** * Decode a list of predicate,object pairings that was created with encodePOCol(). * * @see encodePOCol() */ static POCol decodePOCol( const std::string& data ) { // UT_DEBUGMSG(("PD_DocumentRDF::decodePOCol() data:%s\n", data.c_str() )); POCol ret; if( data.empty() ) return ret; char ch; int sz = 0; std::stringstream ss; ss << data; ss >> sz >> std::noskipws >> ch; // UT_DEBUGMSG(("PD_DocumentRDF::decodePOCol() sz:%d\n", sz )); for( int i=0; i> std::noskipws >> ch; // UT_DEBUGMSG(("PD_DocumentRDF::decodePOCol() po:%s\n", po.c_str() )); std::pair< PD_URI, PD_Object > p = splitPO( po ); ret.insert(p); } return ret; } /** * Encode a list of predicate,object pairings into a single string. * * @see decodePOCol() */ static std::string encodePOCol( const POCol& l ) { std::stringstream ss; ss << l.size() << " "; POCol::const_iterator e = l.end(); for( POCol::const_iterator iter = l.begin(); iter != e; ++iter ) { std::string po = combinePO( iter->first, iter->second ); ss << createLengthPrefixedString(po) << ' '; } return ss.str(); } /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ PD_URI::PD_URI( const std::string& v ) : m_value( v ) { } /** * get a std::string representation */ std::string PD_URI::toString() const { return m_value; } int PD_URI::length() const { return m_value.length(); } /** * Only very basic tests for validity are performed. The * main use of this method is to detect default constructed * PD_URI values */ bool PD_URI::isValid() const { return !m_value.empty(); } bool PD_URI::operator==(const PD_URI& b) const { return m_value == b.m_value; } bool PD_URI::operator==(const std::string& b) const { return m_value == b; } PD_URI PD_URI::prefixedToURI( PD_RDFModelHandle model ) const { PD_URI ret( model->prefixedToURI( toString() )); return ret; } /** * Deserialize the PD_URI from the given stream. * * I thought about using boost::serialization for this, as it * is doing a similar thing. Using b::s though would have required * a link dependancy. * * @see write() */ bool PD_URI::read( std::istream& ss ) { char ch; int version = 0; int numParts = 0; ss >> version >> std::noskipws >> ch; ss >> numParts >> std::noskipws >> ch; m_value = readLengthPrefixedString(ss); ss >> std::noskipws >> ch; return true; } /** * Write the URI to the given stream. * @see read() */ bool PD_URI::write( std::ostream& ss ) const { int version = 1; int numParts = 1; ss << version << " " << numParts << " "; ss << createLengthPrefixedString(m_value) << " "; return true; } bool operator<( PD_URI a, PD_URI b) { return a.toString() < b.toString(); } bool operator<( std::pair< PD_URI, PD_URI > a, PD_URI b) { return a.first.toString() < b.toString(); } bool operator<( PD_URI a, std::pair< PD_URI, PD_URI > b ) { return a.toString() < b.first.toString(); } /****************************************/ /****************************************/ /****************************************/ PD_Object::PD_Object( const std::string& v ) : PD_URI(v) , m_objectType( OBJECT_TYPE_URI ) { } PD_Object::PD_Object( const PD_URI& u ) : PD_URI(u.toString()) , m_objectType( OBJECT_TYPE_URI ) { } PD_Object::PD_Object( const std::string& v, int objectType, const std::string& type ) : PD_URI(v) , m_xsdType(type) , m_objectType(objectType) { } int PD_Object::getObjectType() const { return m_objectType; } bool PD_Object::isLiteral() const { return m_objectType == OBJECT_TYPE_LITERAL; } bool PD_Object::isURI() const { return m_objectType == OBJECT_TYPE_URI; } bool PD_Object::isBNode() const { return m_objectType == OBJECT_TYPE_BNODE; } std::string PD_Object::getXSDType() const { return m_xsdType; } bool PD_Object::hasXSDType() const { return !m_xsdType.empty(); } bool PD_Object::read( std::istream& ss ) { char ch; int version = 0; int numParts = 0; ss >> version >> std::noskipws >> ch; ss >> numParts >> std::noskipws >> ch; ss >> m_objectType >> std::noskipws >> ch; m_value = readLengthPrefixedString(ss); ss >> std::noskipws >> ch; m_xsdType = readLengthPrefixedString(ss); ss >> std::noskipws >> ch; m_context = readLengthPrefixedString(ss); ss >> std::noskipws >> ch; return true; } bool PD_Object::write( std::ostream& ss ) const { int version = 1; int numParts = 4; ss << version << " " << numParts << " "; ss << m_objectType << " "; ss << createLengthPrefixedString(m_value) << " "; ss << createLengthPrefixedString(m_xsdType) << " "; ss << createLengthPrefixedString(m_context) << " "; return true; } PD_Literal::PD_Literal( const std::string& v, const std::string& xsdtype ) : PD_Object( v, OBJECT_TYPE_LITERAL, xsdtype ) { } /****************************************/ /****************************************/ /****************************************/ PD_RDFStatement::PD_RDFStatement() : m_isValid( false ) { } PD_RDFStatement PD_RDFStatement::prefixedToURI( PD_RDFModelHandle model ) const { PD_RDFStatement ret( model->prefixedToURI( getSubject().toString()), model->prefixedToURI( getPredicate().toString()), PD_Object( model->prefixedToURI( getObject().toString()))); return ret; } PD_RDFStatement PD_RDFStatement::uriToPrefixed( PD_RDFModelHandle model ) const { PD_RDFStatement ret( model->uriToPrefixed( getSubject().toString()), model->uriToPrefixed( getPredicate().toString()), PD_Object( model->uriToPrefixed( getObject().toString()))); return ret; } bool PD_RDFStatement::operator==(const PD_RDFStatement& b) const { return getSubject() == b.getSubject() && getPredicate() == b.getPredicate() && getObject() == b.getObject(); } PD_RDFStatement::PD_RDFStatement( PD_RDFModelHandle model, const PD_URI& s, const PD_URI& p, const PD_Object& o ) : m_subject( s.prefixedToURI(model) ) , m_predicate( p.prefixedToURI(model) ) , m_object( o.prefixedToURI(model).toString() ) , m_isValid( true ) { } PD_RDFStatement::PD_RDFStatement( const PD_URI& s, const PD_URI& p, const PD_Object& o ) : m_subject( s ) , m_predicate( p ) , m_object( o ) , m_isValid( true ) { } PD_RDFStatement::PD_RDFStatement( const std::string& s, const std::string& p, const PD_Object& o ) : m_subject( PD_URI(s) ) , m_predicate( PD_URI(p) ) , m_object( o ) , m_isValid( true ) { } PD_RDFStatement::PD_RDFStatement( const std::string& s, const std::string& p, const PD_Literal& o ) : m_subject( PD_URI(s) ) , m_predicate( PD_URI(p) ) , m_object( o ) , m_isValid( true ) { } const PD_URI& PD_RDFStatement::getSubject() const { return m_subject; } const PD_URI& PD_RDFStatement::getPredicate() const { return m_predicate; } const PD_Object& PD_RDFStatement::getObject() const { return m_object; } bool PD_RDFStatement::isValid() const { return m_isValid; } std::string PD_RDFStatement::toString() const { std::stringstream ss; ss << " s:" << m_subject.toString() << " p:" << m_predicate.toString() << " ot:" << m_object.getObjectType() << " o:" << m_object.toString() << " "; return ss.str(); } /****************************************/ /****************************************/ /****************************************/ /****************************************/ /****************************************/ /****************************************/ class PD_RDFModelFromAP : public PD_DocumentRDF { // Can't do this... PD_RDFModelFromAP& operator=( const PD_RDFModelFromAP& other ); protected: const PP_AttrProp* m_AP; public: explicit PD_RDFModelFromAP( PD_Document* doc, const PP_AttrProp* AP ) : PD_DocumentRDF( doc ), m_AP(AP) { UT_DEBUGMSG((" PD_RDFModelFromAP() this:%p\n",this)); } virtual ~PD_RDFModelFromAP() { UT_DEBUGMSG(("~PD_RDFModelFromAP() this:%p\n",this)); delete m_AP; } virtual const PP_AttrProp* getAP(void) { return m_AP; } virtual UT_Error setAP( PP_AttrProp* newAP ) { delete m_AP; m_AP = newAP; return UT_OK; } virtual bool isStandAlone() const { return true; } virtual void maybeSetDocumentDirty() { } }; /** * The idea of this class is to be able to slice up a document's RDF. * So you can explicitly say, give me the RDF that is contained in all * the AP between two positions in the document. */ class PD_RDFModelFromStartEndPos : public PD_DocumentRDF { PT_DocPosition m_beginPos; PT_DocPosition m_endPos; public: explicit PD_RDFModelFromStartEndPos( PD_Document* doc, PT_DocPosition b, PT_DocPosition e ) : PD_DocumentRDF(doc) , m_beginPos(b) , m_endPos(e) { updateAPList(); } virtual ~PD_RDFModelFromStartEndPos() { } virtual const PP_AttrProp* getAP(void) { UT_DEBUGMSG(("ERROR: getAP() is not valid for a start-end position rdf model\n")); return 0; } virtual UT_Error setAP( PP_AttrProp* newAP ) { UT_UNUSED( newAP ); return UT_OK; } virtual bool isStandAlone() const { return true; } //////////////// // For iterating over the PP_AttrProp that are in range. typedef std::list< const PP_AttrProp* > m_APList_t; m_APList_t m_APList; void updateAPList() { m_APList.clear(); pf_Frag* frag = m_doc->getFragFromPosition( m_beginPos ); pf_Frag* endFrag = m_doc->getFragFromPosition( m_endPos ); if( !frag || !endFrag ) { UT_DEBUGMSG(("updateAPList() bpos:%d epos:%d frag:%p endFrag:%p\n", m_beginPos, m_endPos, frag, endFrag )); return; } endFrag = endFrag->getNext(); for( ; frag != endFrag; frag = frag->getNext() ) { PT_AttrPropIndex api = frag->getIndexAP(); const PP_AttrProp * pAP = 0; m_doc->getAttrProp( api, &pAP ); m_APList.push_back( pAP ); } } m_APList_t::iterator apBegin() { return m_APList.begin(); } m_APList_t::iterator apEnd() { return m_APList.end(); } //////////////// // Statement iterator methods... // PD_RDFStatement class StatementIterator : public std::iterator< std::forward_iterator_tag, PD_RDFStatement > { private: typedef std::list< const PP_AttrProp* > m_APList_t; bool m_end; m_APList_t::iterator m_apiter; m_APList_t::iterator m_apenditer; size_t m_apPropertyNumber; std::string m_subject; POCol m_pocol; POCol::iterator m_pocoliter; PD_RDFStatement m_current; public: typedef StatementIterator& self_reference; typedef StatementIterator self_type; StatementIterator() : m_end( true ) , m_apPropertyNumber( 0 ) { } StatementIterator( m_APList_t::iterator iter, m_APList_t::iterator enditer ) : m_end( false ) , m_apiter( iter ) , m_apenditer( enditer ) , m_apPropertyNumber( 0 ) { } void advance_apiter() { ++m_apiter; if( m_apiter == m_apenditer ) { m_end = true; return; } m_apPropertyNumber = 0; m_subject = ""; m_pocol.clear(); m_pocoliter = m_pocol.end(); } void setup_pocol() { UT_DEBUGMSG(("SI... statement iter++/setup_pocol(top)\n" )); const gchar * szName = 0; const gchar * szValue = 0; const PP_AttrProp* AP = *m_apiter; if( AP->getNthProperty( m_apPropertyNumber, szName, szValue) ) { // UT_DEBUGMSG(("statement iter++/setup_pocol szName :%s\n", szName )); // UT_DEBUGMSG(("statement iter++/setup_pocol szValue:%s\n", szValue )); m_subject = szName; m_pocol = decodePOCol( szValue ); if( m_pocol.empty() ) return; m_pocoliter = m_pocol.begin(); std::string pred = m_pocoliter->first.toString(); PD_Object obj = m_pocoliter->second; m_current = PD_RDFStatement( m_subject, pred, obj ); } } self_reference operator++() { if( m_end ) return *this; if( m_apiter == m_apenditer ) { m_end = true; return *this; } /** * We have to walk over each AP using m_apiter until we hit m_apenditer * * For each of these AP; * we have to walk over all the properties * ( each prop is a subject -> list[ pred+obj ] ) * * For each of these properties; * we have to walk over all the pairs in the pocol. */ /// FIXME: const PP_AttrProp* AP = *m_apiter; size_t count = AP->getPropertyCount(); // if( m_apPropertyNumber == count ) // { // advance_apiter(); // return operator++(); // } while( m_pocol.empty() ) { if( m_apPropertyNumber == count ) { advance_apiter(); return operator++(); } setup_pocol(); ++m_apPropertyNumber; } std::string pred = m_pocoliter->first.toString(); PD_Object obj = m_pocoliter->second; m_current = PD_RDFStatement( m_subject, pred, obj ); ++m_pocoliter; if( m_pocoliter == m_pocol.end() ) { m_pocol.clear(); } return *this; } self_type operator++(int) { self_type result( *this ); ++( *this ); return result; } bool operator==( const self_reference other ) { if( m_end && other.m_end ) return true; if( (!m_end && other.m_end) || (m_end && !other.m_end) ) { return false; } return m_apPropertyNumber == other.m_apPropertyNumber && m_pocoliter == other.m_pocoliter && m_apiter == other.m_apiter; } bool operator!=( const self_reference other ) { return !operator==(other); } reference operator*() { return m_current; } }; // StatementIterator begin() // { // return StatementIterator( apBegin(), apEnd() ); // } // StatementIterator end() // { // return StatementIterator(); // } //////////////// // PD_RDFModel methods... virtual PD_ObjectList getObjects( const PD_URI& s, const PD_URI& p ) { PD_ObjectList ret; for( m_APList_t::iterator iter = apBegin(); iter != apEnd(); ++iter ) apGetObjects( *iter, ret, s, p ); return ret; } virtual PD_Object getObject( const PD_URI& s, const PD_URI& p ) { PD_ObjectList l = getObjects(s,p); return front(l); } virtual PD_URIList getSubjects( const PD_URI& p, const PD_Object& o ) { PD_URIList ret; for( m_APList_t::iterator iter = apBegin(); iter != apEnd(); ++iter ) apGetSubjects( *iter, ret, p, o ); return ret; } virtual PD_URI getSubject( const PD_URI& p, const PD_Object& o ) { PD_URIList l = getSubjects( p,o ); return front(l); } virtual PD_URIList getAllSubjects() { PD_URIList ret; for( m_APList_t::iterator iter = apBegin(); iter != apEnd(); ++iter ) apGetAllSubjects( *iter, ret ); return ret; } virtual POCol getArcsOut( const PD_URI& s ) { POCol ret; for( m_APList_t::iterator iter = apBegin(); iter != apEnd(); ++iter ) apGetArcsOut( *iter, ret, s ); return ret; } virtual bool contains( const PD_URI& s, const PD_URI& p, const PD_Object& o ) { bool ret = false; for( m_APList_t::iterator iter = apBegin(); iter != apEnd(); ++iter ) { ret |= apContains( *iter, s, p, o ); if( ret ) break; } return ret; } virtual void dumpModel( const std::string& headerMsg = "dumpModel()" ) { UT_DEBUG_ONLY_ARG(headerMsg); #ifdef DEBUG UT_DEBUGMSG(("PD_RDFModelFromStartEndPos::dumpModel() doc:%p\n", m_doc)); for( m_APList_t::iterator iter = apBegin(); iter != apEnd(); ++iter ) apDumpModel( *iter, headerMsg ); #endif } }; /****************************************/ /****************************************/ /****************************************/ PD_RDFModelIterator::PD_RDFModelIterator() : m_AP( 0 ) , m_end( true ) , m_apPropertyNumber( 0 ) { } PD_RDFModelIterator::~PD_RDFModelIterator() { xxx_UT_DEBUGMSG(("~PD_RDFModelIterator() model: %p\n", m_model.get())); } PD_RDFModelIterator::PD_RDFModelIterator( PD_RDFModelHandle model, const PP_AttrProp* AP ) : m_model( model ) , m_AP( AP ) , m_end( false ) , m_apPropertyNumber( 0 ) { xxx_UT_DEBUGMSG(("PD_RDFModelIterator() model: %p\n", model.get())); operator++(); } void PD_RDFModelIterator::setup_pocol() { xxx_UT_DEBUGMSG(("MI statement iter++/setup_pocol(top) apn:%d\n", m_apPropertyNumber )); const gchar * szName = 0; const gchar * szValue = 0; if( m_AP->getNthProperty( m_apPropertyNumber, szName, szValue) ) { xxx_UT_DEBUGMSG(("MI statement iter++/setup_pocol szName :%s\n", szName )); xxx_UT_DEBUGMSG(("MI statement iter++/setup_pocol szValue:%s\n", szValue )); m_subject = szName; m_pocol = decodePOCol( szValue ); if( m_pocol.empty() ) return; m_pocoliter = m_pocol.begin(); std::string pred = m_pocoliter->first.toString(); PD_Object obj = m_pocoliter->second; m_current = PD_RDFStatement( m_subject, pred, obj ); } } bool PD_RDFModelIterator::moveToNextSubjectHavePOCol() { return !m_pocol.empty(); } void PD_RDFModelIterator::moveToNextSubjectReadPO() { setup_pocol(); std::string pred = m_pocoliter->first.toString(); PD_Object obj = m_pocoliter->second; m_current = PD_RDFStatement( m_subject, pred, obj ); ++m_pocoliter; if( m_pocoliter == m_pocol.end() ) { m_pocol.clear(); } } PD_RDFModelIterator::self_reference PD_RDFModelIterator::moveToNextSubject() { if( m_end ) return *this; ++m_apPropertyNumber; if( m_apPropertyNumber == m_AP->getPropertyCount() ) { m_end = true; return *this; } const gchar * szName = 0; const gchar * szValue = 0; m_AP->getNthProperty( m_apPropertyNumber, szName, szValue ); m_subject = szName; m_current = PD_RDFStatement( m_subject, PD_URI(), PD_Object() ); m_pocol.clear(); return *this; } PD_RDFModelIterator::self_reference PD_RDFModelIterator::operator++() { if( m_end ) return *this; /** * We have to walk over each AP using m_apiter until we hit m_apenditer * * For each of these AP; * we have to walk over all the properties * ( each prop is a subject -> list[ pred+obj ] ) * * For each of these properties; * we have to walk over all the pairs in the pocol. */ /// FIXME: size_t count = m_AP->getPropertyCount(); while( m_pocol.empty() ) { if( m_apPropertyNumber == count ) { m_end = true; return *this; } setup_pocol(); ++m_apPropertyNumber; } std::string pred = m_pocoliter->first.toString(); PD_Object obj = m_pocoliter->second; m_current = PD_RDFStatement( m_subject, pred, obj ); ++m_pocoliter; if( m_pocoliter == m_pocol.end() ) { m_pocol.clear(); } return *this; } bool PD_RDFModelIterator::operator==( self_constref other ) { if( m_end && other.m_end ) return true; if( (!m_end && other.m_end) || (m_end && !other.m_end) ) { return false; } return m_apPropertyNumber == other.m_apPropertyNumber && m_pocoliter == other.m_pocoliter; } PD_RDFModelIterator& PD_RDFModelIterator::operator=( const PD_RDFModelIterator& r ) { if( this != &r ) { xxx_UT_DEBUGMSG(("PD_RDFModelIterator op=() model: %p r.model: %p\n", m_model.get(), r.m_model.get())); m_model = r.m_model; m_AP = r.m_AP; m_end = r.m_end; m_apPropertyNumber = r.m_apPropertyNumber; m_subject = r.m_subject; m_pocol = r.m_pocol; m_current = r.m_current; // // m_pocoliter is an iterator into *our* m_pocol // the default op=() will just copy the iterator into // r.pocol. // { POCol::const_iterator b = r.m_pocol.begin(); POCol::const_iterator i = r.m_pocoliter; int d = std::distance( b, i ); m_pocoliter = m_pocol.begin(); advance( m_pocoliter, d ); } } return *this; } /****************************************/ /****************************************/ /****************************************/ /****************************************/ /****************************************/ /****************************************/ /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ PD_RDFSemanticItem::PD_RDFSemanticItem( PD_DocumentRDFHandle rdf, PD_ResultBindings_t::iterator& it ) : m_rdf(rdf) , m_context( PD_DocumentRDF::getManifestURI() ) { m_name = bindingAsString( it, "name" ); } PD_RDFSemanticItem::~PD_RDFSemanticItem() { } std::string PD_RDFSemanticItem::name() const { return m_name; } void PD_RDFSemanticItem::setName( const std::string& n ) { m_name = n; } std::string PD_RDFSemanticItem::getDisplayLabel() const { return "Semantic Item"; } std::list< std::pair< std::string, std::string> > PD_RDFSemanticItem::getImportTypes() const { std::list< std::pair< std::string, std::string> > ret; return ret; } std::list< std::pair< std::string, std::string> > PD_RDFSemanticItem::getExportTypes() const { std::list< std::pair< std::string, std::string> > ret; return ret; } std::string PD_RDFSemanticItem::getDefaultExtension() const { return ".unknown"; } PD_DocumentRDFHandle PD_RDFSemanticItem::getRDF() const { return m_rdf; } PD_DocumentRDFMutationHandle PD_RDFSemanticItem::createMutation() { return m_rdf->createMutation(); } std::string PD_RDFSemanticItem::requestExportFileNameByDialog() { std::string ret = getExportToFileName( "", getDefaultExtension(), getExportTypes() ); return ret; } PD_URI PD_RDFSemanticItem::linkingSubject() const { return m_linkingSubject; } PD_URI PD_RDFSemanticItem::context() const { return m_context; } std::set< std::string > PD_RDFSemanticItem::getXMLIDs() const { std::set< std::string > ret; PD_URI linksubj = linkingSubject(); PD_ObjectList ol = m_rdf->getObjects( linksubj, PD_URI("http://docs.oasis-open.org/opendocument/meta/package/common#idref")); for( PD_ObjectList::iterator it = ol.begin(); it != ol.end(); ++it ) { std::string xmlid = it->toString(); ret.insert(xmlid); } return ret; } void PD_RDFSemanticItem::updateFromEditorData() { PD_DocumentRDFMutationHandle m = m_rdf->createMutation(); updateFromEditorData( m ); m->commit(); } #include "xap_Frame.h" #include "fv_View.h" std::pair< PT_DocPosition, PT_DocPosition > PD_RDFSemanticItem::insertTextWithXMLID( const std::string& textconst, const std::string& xmlid ) { PT_DocPosition startpos = 0, endpos = 0; XAP_Frame* lff = XAP_App::getApp()->getLastFocussedFrame(); if(lff) { FV_View * pView = static_cast( lff->getCurrentView() ); std::string text = " " + textconst + " "; startpos = pView->getPoint(); m_rdf->getDocument()->insertSpan( startpos, text ); endpos = pView->getPoint(); startpos++; endpos--; pView->selectRange( startpos, endpos ); pView->cmdInsertXMLID( xmlid ); } return std::make_pair( startpos, endpos ); } std::string PD_RDFSemanticItem::bindingAsString( PD_ResultBindings_t::iterator& it, const std::string k ) { return (*it)[k]; } std::string PD_RDFSemanticItem::optionalBindingAsString( PD_ResultBindings_t::iterator& it, const std::string k ) { std::map< std::string, std::string >& m = *it; if( m.end() == m.find(k) || m[k] == "NULL" ) return ""; return m[k]; } PD_URI& PD_RDFSemanticItem::handleSubjectDefaultArgument( PD_URI& subj ) { if( subj.toString().empty() ) { subj = linkingSubject(); } return subj; } void PD_RDFSemanticItem::setRDFType(PD_DocumentRDFMutationHandle m, const std::string& type, PD_URI subj ) { handleSubjectDefaultArgument( subj ); std::string t = type; updateTriple( m, t, type, PD_URI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type") ); // PD_URI pred("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); // m->add( subj, pred, PD_Object(type), context() ); } void PD_RDFSemanticItem::setRDFType(const std::string& type, PD_URI subj ) { PD_DocumentRDFMutationHandle m = createMutation(); setRDFType( m, type, subj ); m->commit(); } void PD_RDFSemanticItem::updateTriple( PD_DocumentRDFMutationHandle m, std::string& toModify, const std::string& newValue, const PD_URI& predString ) { m->remove( linkingSubject(), PD_URI( predString ) ); updateTriple_remove( m, toModify, predString, linkingSubject() ); toModify = newValue; updateTriple_add( m, toModify, predString, linkingSubject() ); } void PD_RDFSemanticItem::updateTriple( PD_DocumentRDFMutationHandle m, time_t& toModify, time_t newValue, const PD_URI& predString ) { m->remove( linkingSubject(), PD_URI( predString ) ); updateTriple_remove( m, PD_URI(tostr(toModify)), predString, linkingSubject() ); toModify = newValue; updateTriple_add( m, PD_URI(toTimeString(toModify)), predString, linkingSubject() ); } void PD_RDFSemanticItem::updateTriple( PD_DocumentRDFMutationHandle m, double& toModify, double newValue, const PD_URI& predString ) { m->remove( linkingSubject(), PD_URI( predString ) ); // // I abstracted the below code to an ::remove() method in mutation // { // PD_URI pred( predString ); // PD_ObjectList objects = m_rdf->getObjects( linkingSubject(), pred ); // std::list< PD_RDFStatement > removeList; // for( PD_ObjectList::iterator it = objects.begin(); it != objects.end(); ++it ) // { // PD_Object obj = *it; // PD_RDFStatement s( linkingSubject(), pred, obj ); // removeList.push_back( s ); // } // m->remove( removeList ); // } updateTriple_remove( m, PD_URI(tostr(toModify)), predString, linkingSubject() ); toModify = newValue; updateTriple_add( m, PD_URI(tostr(toModify)), predString, linkingSubject() ); } void PD_RDFSemanticItem::updateTriple( PD_DocumentRDFMutationHandle m, double& toModify, double newValue, const PD_URI& predString, PD_URI linkingSubj ) { updateTriple_remove( m, PD_URI(tostr(toModify)), predString, linkingSubj ); toModify = newValue; updateTriple_add( m, PD_URI(tostr(toModify)), predString, linkingSubj ); } void PD_RDFSemanticItem::updateTriple( std::string& toModify, const std::string& newValue, const PD_URI& predString ) { PD_DocumentRDFMutationHandle m = createMutation(); updateTriple( m, toModify, newValue, predString ); m->commit(); } void PD_RDFSemanticItem::updateTriple( time_t& toModify, time_t newValue, const PD_URI& predString ) { PD_DocumentRDFMutationHandle m = createMutation(); updateTriple( m, toModify, newValue, predString ); m->commit(); } void PD_RDFSemanticItem::updateTriple( double& toModify, double newValue, const PD_URI& predString ) { PD_DocumentRDFMutationHandle m = createMutation(); updateTriple( m, toModify, newValue, predString ); m->commit(); } void PD_RDFSemanticItem::updateTriple_remove( PD_DocumentRDFMutationHandle m, const PD_URI& toModify, const PD_URI& predString, const PD_URI& explicitLinkingSubject ) { PD_URI pred( predString ); m->remove( explicitLinkingSubject, pred, PD_Literal(toModify.toString()) ); // // Typeless remove, I found that if a object literal did not // stipulate its type in the input RDF, just using // remove() above might not pick it up. So the below code // looks through all statements with subj+pred and checks typeless // string identity of the object() and removes it if strings match. // PD_ObjectList objects = m_rdf->getObjects( explicitLinkingSubject, pred ); std::list< PD_RDFStatement > removeList; for( PD_ObjectList::iterator it = objects.begin(); it != objects.end(); ++it ) { PD_Object obj = *it; PD_RDFStatement s( explicitLinkingSubject, pred, obj ); if( obj.toString() == toModify.toString()) { removeList.push_back( s ); } // // // // Sometimes the object value is serialized as 51.47026 or // // 5.1470260000e+01. There are also slight rounding errors // // which are introduced that complicate comparisons. // // // if (toModify.isDouble()) // { // removeList.push_back( s ); // } } m->remove( removeList ); } void PD_RDFSemanticItem::updateTriple_add( PD_DocumentRDFMutationHandle m, const PD_URI& toModify, const PD_URI& predString, const PD_URI& explicitLinkingSubject ) { if( toModify.empty() ) return; PD_URI pred( predString ); m->add( explicitLinkingSubject, pred, PD_Literal(toModify.toString()), context() ); } PD_URI PD_RDFSemanticItem::createUUIDNode() { std::string uuid = XAP_App::getApp()->createUUIDString(); return PD_URI( uuid ); } void PD_RDFSemanticItem::importFromFile( const std::string& filename_const ) { std::string filename = getImportFromFileName( filename_const, getImportTypes() ); std::ifstream iss( filename.c_str() ); importFromData( iss, m_rdf ); } PD_RDFSemanticItemHandle PD_RDFSemanticItem::createSemanticItem( PD_DocumentRDFHandle rdf, const std::string& semanticClass ) { PD_ResultBindings_t b; b.push_back( std::map< std::string, std::string >() ); PD_ResultBindings_t::iterator it = b.begin(); return createSemanticItem( rdf, it, semanticClass ); } PD_RDFSemanticItemHandle PD_RDFSemanticItem::createSemanticItem( PD_DocumentRDFHandle rdf, PD_ResultBindings_t::iterator it, const std::string& semanticClass ) { if (semanticClass == "Contact") { return PD_RDFSemanticItemHandle( PD_DocumentRDF::getSemanticItemFactory()->createContact( rdf, it ) ); } if (semanticClass == "Event") { return PD_RDFSemanticItemHandle( PD_DocumentRDF::getSemanticItemFactory()->createEvent( rdf, it )); } #ifdef WITH_CHAMPLAIN if (semanticClass == "Location") { return PD_RDFSemanticItemHandle( PD_DocumentRDF::getSemanticItemFactory()->createLocation( rdf, it )); } #endif return PD_RDFSemanticItemHandle(); } void PD_RDFSemanticItem::showEditorWindow( const PD_RDFSemanticItems& cl ) { UT_DEBUG_ONLY_ARG(cl); UT_DEBUGMSG(("showEditorWindow(base) list... sz:%lu\n", (long unsigned)cl.size() )); } void PD_RDFSemanticItem::showEditorWindow( const PD_RDFSemanticItemHandle& c ) { UT_DEBUG_ONLY_ARG(c); UT_DEBUGMSG(("showEditorWindow(base) name:%s linksubj:%s\n", c->name().c_str(), c->linkingSubject().toString().c_str() )); } void PD_RDFSemanticItem::importFromDataComplete( std::istream& /*iss*/, PD_DocumentRDFHandle /*rdf*/, PD_DocumentRDFMutationHandle /*m*/, PD_DocumentRange* /*pDocRange*/ ) { UT_DEBUGMSG(("importFromDataComplete(base)\n")); } std::string PD_RDFSemanticItem::getImportFromFileName( const std::string& /*filename_const*/, std::list< std::pair< std::string, std::string> > /*types*/ ) const { return ""; } std::string PD_RDFSemanticItem::getExportToFileName( const std::string& /*filename_const*/, std::string /*defaultExtension*/, std::list< std::pair< std::string, std::string> > /*types*/ ) const { return ""; } /***********/ /***********/ /***********/ PD_RDFContact::PD_RDFContact( PD_DocumentRDFHandle rdf, PD_ResultBindings_t::iterator& it ) : PD_RDFSemanticItem( rdf, it ) { m_linkingSubject = PD_URI( bindingAsString( it, "person") ); m_nick = optionalBindingAsString( it, "nick"); m_email = optionalBindingAsString( it, "email"); m_homePage = optionalBindingAsString( it, "homepage"); m_imageUrl = optionalBindingAsString( it, "img"); m_phone = optionalBindingAsString( it, "phone"); m_jabberID = optionalBindingAsString( it, "jabberid"); } PD_RDFContact::~PD_RDFContact() { } std::string PD_RDFContact::getDisplayLabel() const { return "Contact"; } void PD_RDFContact::setupStylesheetReplacementMapping( std::map< std::string, std::string >& m ) { m["%NICK%"] = m_nick; m["%HOMEPAGE%"] = m_homePage; m["%PHONE%"] = m_phone; m["%EMAIL%"] = m_email; } PD_RDFSemanticStylesheets PD_RDFContact::stylesheets() const { PD_RDFSemanticStylesheets ret; ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("143c1ba3-d7bb-440b-8528-7f07d2eff5f2", RDF_SEMANTIC_STYLESHEET_CONTACT_NAME, "%NAME%"))); ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("2fad34d1-42a0-4b10-b17e-a87db5208f6d", RDF_SEMANTIC_STYLESHEET_CONTACT_NICK, "%NICK%"))); ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("0dd5878d-95c5-47e5-a777-63ec36da3b9a", RDF_SEMANTIC_STYLESHEET_CONTACT_NAME_PHONE, "%NAME%, %PHONE%"))); ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("9cbeb4a6-34c5-49b2-b3ef-b94277db0c59", RDF_SEMANTIC_STYLESHEET_CONTACT_NICK_PHONE, "%NICK%, %PHONE%"))); ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("47025a4a-5da5-4a32-8d89-14c03658631d", RDF_SEMANTIC_STYLESHEET_CONTACT_NAME_HOMEPAGE_PHONE, "%NAME%, (%HOMEPAGE%), %PHONE%"))); return ret; } std::string PD_RDFContact::className() const { return "Contact"; } #ifdef WITH_EVOLUTION_DATA_SERVER extern "C" { #include }; static std::string get( EVCard* c, const char* v ) { EVCardAttribute* a = e_vcard_get_attribute( c, v ); UT_DEBUGMSG((" cvard.group:%s v:%s\n", e_vcard_attribute_get_group( a ), v )); if( a && e_vcard_attribute_is_single_valued(a) ) { return e_vcard_attribute_get_value(a); } return ""; } static void set( EVCard* c, const char* k, const std::string& v ) { EVCardAttribute* a = e_vcard_get_attribute( c, k ); if( !a ) { a = e_vcard_attribute_new( 0, k ); e_vcard_append_attribute( c, a ); } if( a ) { e_vcard_attribute_add_value( a, v.c_str() ); } } #endif std::list< std::pair< std::string, std::string> > PD_RDFContact::getImportTypes() const { std::list< std::pair< std::string, std::string> > types; types.push_back( std::make_pair( "VCard File", "vcf" )); return types; } void PD_RDFContact::importFromData( std::istream& iss, PD_DocumentRDFHandle rdf, PD_DocumentRange * pDocRange ) { #ifdef WITH_EVOLUTION_DATA_SERVER std::string vcard = StreamToString( iss ); UT_DEBUGMSG(("trying to get card for data:%s\n", vcard.c_str() )); if( EVCard* c = e_vcard_new_from_string( vcard.c_str() ) ) { std::string textrep = ""; typedef std::list< const char* > charplist_t; charplist_t textreplist; textreplist.push_back( EVC_EMAIL ); textreplist.push_back( EVC_FN ); textreplist.push_back( EVC_NICKNAME ); textreplist.push_back( EVC_UID ); for( charplist_t::iterator iter = textreplist.begin(); iter != textreplist.end(); ++iter ) { textrep = get( c, *iter ); if( !textrep.empty() ) break; } UT_DEBUGMSG(("have card!\n")); std::string fn = get( c, EVC_FN ); std::string uid = get( c, EVC_UID ); std::string xmlid = rdf->makeLegalXMLID( fn + "_" + uid ); std::string email = get( c, EVC_EMAIL ); UT_DEBUGMSG(("uid:%s xmlid:%s\n", uid.c_str(), xmlid.c_str() )); m_name = fn; m_nick = get( c, EVC_NICKNAME ); m_email = email; m_phone = get( c, EVC_TEL ); m_jabberID = get( c, EVC_X_JABBER ); // std::pair< PT_DocPosition, PT_DocPosition > se = insertTextWithXMLID( textrep, xmlid ); // PT_DocPosition startpos = se.first; // PT_DocPosition endpos = se.second; std::string uuid = "http://abicollab.net/rdf/foaf#" + uid; m_linkingSubject = PD_URI( uuid ); XAP_Frame* lff = XAP_App::getApp()->getLastFocussedFrame(); if(lff) { // FV_View * pView = static_cast( lff->getCurrentView() ); // std::pair< PT_DocPosition, PT_DocPosition > se = insert( pView ); // PT_DocPosition startpos = se.first; // PT_DocPosition endpos = se.second; } // PD_DocumentRDFMutationHandle m = rdf->createMutation(); // m->add( PD_URI(uuid), // PD_URI("http://docs.oasis-open.org/opendocument/meta/package/common#idref"), // PD_Literal( xmlid ) ); // // m->add( PD_URI(uuid), // // PD_URI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), // // PD_Object("http://xmlns.com/foaf/0.1/Person") ); // // addFoafProp( m, c, EVC_TEL, uuidnode, "phone" ); // // addFoafProp( m, c, EVC_NICKNAME, uuidnode, "nick" ); // // addFoafProp( m, c, EVC_FN, uuidnode, "name" ); // // addFoafProp( m, c, EVC_N, uuidnode, "givenName" ); // // addFoafProp( m, c, EVC_X_JABBER, uuidnode, "jabberID" ); PD_DocumentRDFMutationHandle m = rdf->createMutation(); importFromDataComplete( iss, rdf, m, pDocRange ); m->commit(); } #else UT_UNUSED(iss); UT_UNUSED(rdf); UT_UNUSED(pDocRange); #endif } std::list< std::pair< std::string, std::string> > PD_RDFContact::getExportTypes() const { std::list< std::pair< std::string, std::string> > ret; ret.push_back( std::make_pair( "VCard File", "vcf" )); return ret; } std::string PD_RDFContact::getDefaultExtension() const { return ".vcf"; } void PD_RDFContact::exportToFile( const std::string& filename_const ) const { std::string filename = getExportToFileName( filename_const, ".vcf", getExportTypes() ); UT_DEBUGMSG(( "saving vcard to file:%s\n", filename.c_str() )); #ifdef WITH_EVOLUTION_DATA_SERVER if( EVCard* c = e_vcard_new() ) { set( c, EVC_FN, m_name ); set( c, EVC_UID, m_linkingSubject.toString() ); set( c, EVC_EMAIL, m_email ); set( c, EVC_NICKNAME, m_nick ); set( c, EVC_TEL, m_phone ); set( c, EVC_X_JABBER, m_jabberID ); gchar* data = e_vcard_to_string( c, EVC_FORMAT_VCARD_30 ); UT_DEBUGMSG(( "saving vcard to file:%s vcard.len:%ld\n", filename.c_str(), strlen(data) )); std::ofstream oss( filename.c_str() ); oss.write( data, strlen(data) ); oss.flush(); oss.close(); g_free(data); } #endif } /******************************/ /******************************/ /******************************/ #ifdef WITH_LIBICAL extern "C" { #include }; #if 0 // static std::string tostr( time_t v ) // { // std::stringstream ss; // ss << v; // return ss.str(); // } static void addCalProp( PD_DocumentRDFMutationHandle m, const PD_URI& uuidnode, const std::string& predend, const std::string& value ) { std::string predBase = "http://www.w3.org/2002/12/cal/icaltzd#"; m->add( uuidnode, PD_URI(predBase + predend), PD_Literal( value ) ); } static void addCalPropSZ( PD_DocumentRDFMutationHandle m, const PD_URI& uuidnode, const std::string& predend, const char* value ) { std::string predBase = "http://www.w3.org/2002/12/cal/icaltzd#"; if( value ) { addCalProp( m, uuidnode, predend, (std::string)value ); } } #endif #endif PD_RDFEvent::PD_RDFEvent( PD_DocumentRDFHandle rdf, PD_ResultBindings_t::iterator& it ) : PD_RDFSemanticItem( rdf, it ) { m_linkingSubject = PD_URI( bindingAsString( it, "ev") ); m_summary = optionalBindingAsString( it, "summary"); m_location = optionalBindingAsString( it, "location"); m_uid = optionalBindingAsString( it, "uid"); m_desc = optionalBindingAsString( it, "description"); m_dtstart = parseTimeString(optionalBindingAsString( it, "dtstart")); m_dtend = parseTimeString(optionalBindingAsString( it, "dtend")); if( m_name.empty() ) m_name = m_uid; } PD_RDFEvent::~PD_RDFEvent() { } void PD_RDFEvent::setupStylesheetReplacementMapping( std::map< std::string, std::string >& m ) { m["%UID%"] = m_uid; m["%DESCRIPTION%"] = m_desc; m["%DESC%"] = m_desc; m["%SUMMARY%"] = m_summary; m["%LOCATION%"] = m_location; m["%START%"] = toTimeString(m_dtstart); m["%END%"] = toTimeString(m_dtend); } PD_RDFSemanticStylesheets PD_RDFEvent::stylesheets() const { PD_RDFSemanticStylesheets ret; ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("92f5d6c5-2c3a-4988-9646-2f29f3731f89", RDF_SEMANTIC_STYLESHEET_EVENT_NAME, "%NAME%"))); ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("b4817ce4-d2c3-4ed3-bc5a-601010b33363", RDF_SEMANTIC_STYLESHEET_EVENT_SUMMARY, "%SUMMARY%"))); ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("853242eb-031c-4a36-abb2-7ef1881c777e", RDF_SEMANTIC_STYLESHEET_EVENT_SUMMARY_LOCATION, "%SUMMARY%, %LOCATION%"))); ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("2d6b87a8-23be-4b61-a881-876177812ad4", RDF_SEMANTIC_STYLESHEET_EVENT_SUMMARY_LOCATION_TIMES, "%SUMMARY%, %LOCATION%, %START%"))); ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("115e3ceb-6bc8-445c-a932-baee09686895", RDF_SEMANTIC_STYLESHEET_EVENT_SUMMARY_TIMES, "%SUMMARY%, %START%"))); return ret; } std::string PD_RDFEvent::className() const { return "Event"; } std::list< std::pair< std::string, std::string> > PD_RDFEvent::getImportTypes() const { std::list< std::pair< std::string, std::string> > types; types.push_back( std::make_pair( "ICalendar files", "ics" )); return types; } std::list< std::pair< std::string, std::string> > PD_RDFEvent::getExportTypes() const { std::list< std::pair< std::string, std::string> > types; types.push_back( std::make_pair( "ICalendar files", "ics" )); return types; } std::string PD_RDFEvent::getDisplayLabel() const { return "Event"; } #ifdef WITH_LIBICAL static void setFromString( std::string& s, const char* input ) { if( input ) s = input; else s = ""; } #endif void PD_RDFEvent::importFromData( std::istream& iss, PD_DocumentRDFHandle rdf, PD_DocumentRange * pDocRange ) { #ifdef WITH_LIBICAL std::string data = StreamToString(iss); UT_DEBUGMSG(("trying to get calendar for data:%s\n", data.c_str() )); if( icalcomponent* c = icalcomponent_new_from_string( data.c_str() ) ) { const char* zdesc = icalcomponent_get_description( c ); const char* zloc = icalcomponent_get_location( c ); const char* zsummary = icalcomponent_get_summary( c ); const char* zuid = icalcomponent_get_uid( c ); struct icaltimetype zdtstart = icalcomponent_get_dtstart( c ); struct icaltimetype zdtend = icalcomponent_get_dtend( c ); std::string xmlid; if( zsummary ) xmlid += (std::string)"" + zsummary + "_"; if( zuid ) xmlid += zuid; xmlid = rdf->makeLegalXMLID( xmlid ); setFromString( m_desc, zdesc ); setFromString( m_location, zloc ); setFromString( m_summary, zsummary ); setFromString( m_uid, zuid ); m_name = m_uid; m_dtstart = icaltime_as_timet( zdtstart ); m_dtend = icaltime_as_timet( zdtend ); std::string uuid = "http://abicollab.net/rdf/cal#" + xmlid; m_linkingSubject = PD_URI( uuid ); XAP_Frame* lff = XAP_App::getApp()->getLastFocussedFrame(); if(lff) { // FV_View * pView = static_cast( lff->getCurrentView() ); // std::pair< PT_DocPosition, PT_DocPosition > se = insert( pView ); // PT_DocPosition startpos = se.first; // PT_DocPosition endpos = se.second; } PD_DocumentRDFMutationHandle m = rdf->createMutation(); importFromDataComplete( iss, rdf, m, pDocRange ); m->commit(); } #else UT_UNUSED(iss); UT_UNUSED(rdf); UT_UNUSED(pDocRange); #endif } std::string PD_RDFEvent::getDefaultExtension() const { return ".ical"; } void PD_RDFEvent::exportToFile( const std::string& filename_const ) const { std::string filename = getExportToFileName( filename_const, ".ical", getExportTypes() ); UT_DEBUGMSG(( "saving ical to file:%s\n", filename.c_str() )); #ifdef WITH_LIBICAL if( icalcomponent* c = icalcomponent_new( ICAL_VEVENT_COMPONENT ) ) { icalcomponent_set_uid( c, m_uid.c_str() ); icalcomponent_set_location( c, m_location.c_str() ); icalcomponent_set_description( c, m_desc.c_str() ); icalcomponent_set_dtstart( c, icaltime_from_timet( m_dtstart, 0 ) ); icalcomponent_set_dtend( c, icaltime_from_timet( m_dtend, 0 ) ); char* data = icalcomponent_as_ical_string( c ); std::ofstream oss( filename.c_str() ); oss.write( data, strlen(data) ); oss.flush(); oss.close(); } #endif } /******************************/ /******************************/ /******************************/ std::list< std::pair< std::string, std::string> > PD_RDFLocation::getImportTypes() const { std::list< std::pair< std::string, std::string> > types; types.push_back( std::make_pair( "KML files", "kml" )); return types; } std::list< std::pair< std::string, std::string> > PD_RDFLocation::getExportTypes() const { std::list< std::pair< std::string, std::string> > types; types.push_back( std::make_pair( "KML files", "kml" )); return types; } PD_RDFLocation::PD_RDFLocation( PD_DocumentRDFHandle rdf, PD_ResultBindings_t::iterator& it, bool isGeo84 ) : PD_RDFSemanticItem( rdf, it ) , m_isGeo84( isGeo84 ) { m_linkingSubject = PD_URI( bindingAsString( it, "geo") ); m_name = optionalBindingAsString( it, "name"); m_uid = optionalBindingAsString( it, "uid"); m_desc = optionalBindingAsString( it, "desc"); m_dlat = toType(optionalBindingAsString( it, "lat")); m_dlong = toType(optionalBindingAsString( it, "long")); m_joiner = PD_Object(optionalBindingAsString( it, "joiner")); if( m_name.empty() ) m_name = m_uid; if( m_name.empty() ) { m_name = tostr(m_dlat) + "_" + tostr(m_dlong); if( m_uid.empty() ) m_uid = m_name; } UT_DEBUGMSG(("PD_RDFLocation() name:%s long:%f lat:%f geo84:%d\n", m_name.c_str(), m_dlat, m_dlong, isGeo84 )); } PD_RDFLocation::~PD_RDFLocation() { } void PD_RDFLocation::setupStylesheetReplacementMapping( std::map< std::string, std::string >& m ) { m["%UID%"] = m_uid; m["%DESCRIPTION%"] = m_desc; m["%DESC%"] = m_desc; m["%LAT%"] = tostr(m_dlat); m["%LONG%"] = tostr(m_dlong); m["%DLAT%"] = tostr(m_dlat); m["%DLONG%"] = tostr(m_dlong); } PD_RDFSemanticStylesheets PD_RDFLocation::stylesheets() const { PD_RDFSemanticStylesheets ret; ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("33314909-7439-4aa1-9a55-116bb67365f0", RDF_SEMANTIC_STYLESHEET_LOCATION_NAME, "%NAME%"))); ret.push_back( PD_RDFSemanticStylesheetHandle( new PD_RDFSemanticStylesheet("34584133-52b0-449f-8b7b-7f1ef5097b9a", RDF_SEMANTIC_STYLESHEET_LOCATION_NAME_LATLONG, "%NAME%, %DLAT%, %DLONG%"))); return ret; } std::string PD_RDFLocation::className() const { return "Location"; } std::string PD_RDFLocation::getDisplayLabel() const { return "Location"; } void PD_RDFLocation::importFromData( std::istream& /*iss*/, PD_DocumentRDFHandle /*rdf*/, PD_DocumentRange * /*pDocRange*/ ) { UT_DEBUGMSG(( "FIXME: importFromData()\n" )); } std::string PD_RDFLocation::getDefaultExtension() const { return ".kml"; } void PD_RDFLocation::exportToFile( const std::string& filename_const ) const { std::string filename = getExportToFileName( filename_const, ".kml", getExportTypes() ); UT_DEBUGMSG(( "Saving KML to file:%s\n", filename.c_str() )); std::ofstream xmlss( filename.c_str() ); xmlss << " \n" << " \n" << " \n" << " \n" << " " << name() << " \n" << " \n" << " " << m_dlong << " \n" << " " << m_dlat << " \n" << " \n" << " \n" << "\n"; xmlss.flush(); xmlss.close(); } std::set< std::string > PD_RDFLocation::getXMLIDs() const { std::set< std::string > ret; std::stringstream ss; ss << "prefix rdf: " << std::endl << "prefix foaf: " << std::endl << "prefix pkg: " << std::endl << "prefix geo84: " << std::endl << "" << std::endl << "select distinct ?s ?p ?o ?xmlid" << std::endl << "where { " << std::endl << " ?s pkg:idref ?xmlid ." << std::endl << " ?s ?p ?o " << std::endl << " . filter( str(?o) = \"" << m_linkingSubject.toString() << "\" )" << std::endl << "}" << std::endl; std::set uniqfilter; PD_RDFQuery q( getRDF(), getRDF() ); PD_ResultBindings_t bindings = q.executeQuery( ss.str() ); for( PD_ResultBindings_t::iterator iter = bindings.begin(); iter != bindings.end(); ++iter ) { std::map< std::string, std::string > d = *iter; std::string xmlid = d["xmlid"]; if (uniqfilter.count(xmlid)) continue; uniqfilter.insert(xmlid); if( !xmlid.empty() ) ret.insert( xmlid ); UT_DEBUGMSG(("PD_RDFLocation::getXMLIDs() xmlid:%s\n", xmlid.c_str() )); } return ret; } /************************************************************/ /************************************************************/ /************************************************************/ /************************************************************/ /************************************************************/ /************************************************************/ std::pair< PT_DocPosition, PT_DocPosition > PD_RDFSemanticItem::insert( PD_DocumentRDFMutationHandle m, FV_View* /*pView*/ ) { std::string xmlid = m_rdf->makeLegalXMLID( name() ); std::pair< PT_DocPosition, PT_DocPosition > se = insertTextWithXMLID( name(), xmlid ); if (m_linkingSubject.toString().empty()) { std::string uuid = XAP_App::getApp()->createUUIDString(); m_linkingSubject = uuid; } m->add( m_linkingSubject, PD_URI("http://docs.oasis-open.org/opendocument/meta/package/common#idref"), PD_Literal( xmlid ) ); return se; } std::pair< PT_DocPosition, PT_DocPosition > PD_RDFSemanticItem::insert( FV_View* pView ) { PD_DocumentRDFMutationHandle m = m_rdf->createMutation(); std::pair< PT_DocPosition, PT_DocPosition > ret = insert( m, pView ); m->commit(); return ret; } std::list< std::string > PD_RDFSemanticItem::getClassNames() { std::list< std::string > ret; ret.push_back( "Contact" ); ret.push_back( "Event" ); ret.push_back( "Location" ); return ret; } void PD_RDFSemanticItem::setupStylesheetReplacementMapping( std::map< std::string, std::string >& /*m*/ ) { } PD_RDFSemanticStylesheetHandle PD_RDFSemanticItem::findStylesheetByUuid(const std::string &uuid) const { PD_RDFSemanticStylesheetHandle ret; if( uuid.empty() ) return ret; PD_RDFSemanticStylesheets ssl = stylesheets(); for( PD_RDFSemanticStylesheets::iterator iter = ssl.begin(); iter != ssl.end(); ++iter ) { PD_RDFSemanticStylesheetHandle ss = *iter; if ( ss->uuid() == uuid ) { return ss; } } return ret; } PD_RDFSemanticStylesheetHandle PD_RDFSemanticItem::findStylesheetByName(const std::string & /*sheetType*/, const std::string &n) const { return findStylesheetByName( stylesheets(), n ); } PD_RDFSemanticStylesheetHandle PD_RDFSemanticItem::findStylesheetByName(const PD_RDFSemanticStylesheets& ssl, const std::string &n) const { PD_RDFSemanticStylesheetHandle ret; if( n.empty() ) return ret; for( PD_RDFSemanticStylesheets::const_iterator iter = ssl.begin(); iter != ssl.end(); ++iter ) { PD_RDFSemanticStylesheetHandle ss = *iter; if ( ss->name() == n ) { return ss; } } return ret; } std::string PD_RDFSemanticItem::getProperty( std::string subj, std::string pred, std::string defVal ) const { PD_Object o = m_rdf->getObject( subj, pred ); if( o.empty() ) return defVal; return o.toString(); } PD_RDFSemanticStylesheetHandle PD_RDFSemanticItem::defaultStylesheet() const { std::string semanticClass = className(); std::string name_ = getProperty( "http://calligra-suite.org/rdf/document/" + semanticClass, "http://calligra-suite.org/rdf/stylesheet", RDF_SEMANTIC_STYLESHEET_NAME ); std::string type = getProperty( "http://calligra-suite.org/rdf/document/" + semanticClass, "http://calligra-suite.org/rdf/stylesheet-type", PD_RDFSemanticStylesheet::stylesheetTypeSystem() ); std::string uuid = getProperty( "http://calligra-suite.org/rdf/document/" + semanticClass, "http://calligra-suite.org/rdf/stylesheet-uuid", "" ); PD_RDFSemanticStylesheetHandle ret = findStylesheetByUuid( uuid ); if (!ret) { ret = findStylesheetByName( type, name_ ); } if (!ret) { // The "name" stylesheet should always exist ret = findStylesheetByName( PD_RDFSemanticStylesheet::stylesheetTypeSystem(), RDF_SEMANTIC_STYLESHEET_NAME ); } return ret; } void PD_RDFSemanticItem::relationAdd( PD_RDFSemanticItemHandle dst, RelationType rt ) { std::string predBase("http://xmlns.com/foaf/0.1/" ); PD_URI pred( predBase + "knows"); PD_DocumentRDFMutationHandle m = m_rdf->createMutation(); switch( rt ) { case RELATION_FOAF_KNOWS: // symetric relation m->add( linkingSubject(), pred, PD_Object(dst->linkingSubject()) ); m->add( dst->linkingSubject(), pred, PD_Object(linkingSubject()) ); break; } m->commit(); } PD_RDFSemanticItems PD_RDFSemanticItem::relationFind( RelationType rt ) { std::string predBase("http://xmlns.com/foaf/0.1/" ); PD_URI pred( predBase + "knows"); switch( rt ) { case RELATION_FOAF_KNOWS: pred = PD_URI( predBase + "knows"); break; } UT_DEBUGMSG(("relationFind() this->linkingSubj:%s\n", linkingSubject().c_str() )); std::set< std::string > xmlids; PD_ObjectList ol = m_rdf->getObjects( linkingSubject(), pred ); for( PD_ObjectList::iterator iter = ol.begin(); iter != ol.end(); ++iter ) { PD_URI linkingSubj = *iter; UT_DEBUGMSG(("relationFind() linkingSubj:%s\n", linkingSubj.c_str() )); std::set< std::string > t = getXMLIDsForLinkingSubject( m_rdf, linkingSubj.toString() ); UT_DEBUGMSG(("relationFind() t.sz:%ld\n", (long)t.size() )); xmlids.insert( t.begin(), t.end() ); } UT_DEBUGMSG(("relationFind() xmlids.sz:%ld\n", (long)xmlids.size() )); PD_RDFSemanticItems ret = m_rdf->getSemanticObjects( xmlids ); return ret; } std::set< std::string > PD_RDFSemanticItem::getXMLIDsForLinkingSubject( PD_DocumentRDFHandle rdf, const std::string& linkingSubj ) { std::set< std::string > ret; std::stringstream ss; ss << "prefix rdf: " << std::endl << "prefix foaf: " << std::endl << "prefix pkg: " << std::endl << "prefix geo84: " << std::endl << "" << std::endl << "select distinct ?s ?xmlid" << std::endl << "where { " << std::endl << " ?s pkg:idref ?xmlid " << std::endl << " . filter( str(?s) = \"" << linkingSubj << "\" )" << std::endl << "}" << std::endl; std::set uniqfilter; PD_RDFQuery q( rdf, rdf ); UT_DEBUGMSG(("getXMLIDsForLinkingSubject() sparql:%s\n", ss.str().c_str() )); PD_ResultBindings_t bindings = q.executeQuery( ss.str() ); for( PD_ResultBindings_t::iterator iter = bindings.begin(); iter != bindings.end(); ++iter ) { std::map< std::string, std::string > d = *iter; std::string xmlid = d["xmlid"]; if (uniqfilter.count(xmlid)) continue; uniqfilter.insert(xmlid); if( !xmlid.empty() ) ret.insert( xmlid ); } return ret; } /************************************************************/ /************************************************************/ /************************************************************/ PD_RDFSemanticStylesheet::PD_RDFSemanticStylesheet( const std::string &_uuid, const std::string &_name, const std::string &_templateString, const std::string &_type, bool _isMutable ) : m_uuid(_uuid) , m_name(_name) , m_templateString(_templateString) , m_type(_type) , m_isMutable(_isMutable) { } void PD_RDFSemanticStylesheet::format( PD_RDFSemanticItemHandle obj, FV_View* pView, const std::string& xmlid_const ) { PD_Document* pDoc = pView->getDocument(); PD_DocumentRDFHandle rdf = obj->getRDF(); std::string xmlid = xmlid_const; if( xmlid.empty() ) { std::set< std::string > tmp; rdf->addRelevantIDsForPosition( tmp, pView->getPoint() ); if( tmp.empty() ) { UT_DEBUGMSG(("ss:format(no xmlid!) obj->name:%s\n", obj->name().c_str() )); return; } xmlid = *(tmp.begin()); } UT_DEBUGMSG(("ss:format() obj->name:%s\n", obj->name().c_str() )); UT_DEBUGMSG(("xmlid:%s pView:%p sheetname:%s\n", xmlid.c_str(), pView, name().c_str() )); std::pair< PT_DocPosition, PT_DocPosition > p = rdf->getIDRange( xmlid ); PT_DocPosition startpos = p.first + 1; PT_DocPosition endpos = p.second; if (!endpos) { UT_DEBUGMSG(("ss:format(invalid range!) obj->name:%s\n", obj->name().c_str() )); return; } UT_DEBUGMSG(("formating start:%d end:%d\n", startpos, endpos )); // Grab the text that was there and remove it. pView->selectRange( startpos, endpos ); pView->cmdCut(); pView->setPoint( startpos ); std::string data = templateString(); std::map< std::string, std::string > m; m["%NAME%"] = obj->name(); obj->setupStylesheetReplacementMapping( m ); for( std::map< std::string, std::string >::iterator mi = m.begin(); mi != m.end(); ++mi) { std::string k = mi->first; std::string v = mi->second; data = replace_all( data, k, v ); } // make sure there is something in the replacement other than commas and spaces std::string tmpstring = data; tmpstring = replace_all( tmpstring, " ", "" ); tmpstring = replace_all( tmpstring, ",", "" ); if (tmpstring.empty()) { UT_DEBUGMSG(("stylesheet results in empty data, using name() instead\n")); data = name(); } UT_DEBUGMSG(("Updating with new formatting:%s\n", data.c_str() )); pDoc->insertSpan( startpos, data ); pView->setPoint( startpos ); } PD_RDFSemanticStylesheet::~PD_RDFSemanticStylesheet() { } std::string PD_RDFSemanticStylesheet::stylesheetTypeSystem() { return "System"; } std::string PD_RDFSemanticStylesheet::stylesheetTypeUser() { return "User"; } std::string PD_RDFSemanticStylesheet::uuid() const { return m_uuid; } std::string PD_RDFSemanticStylesheet::name() const { return m_name; } std::string PD_RDFSemanticStylesheet::templateString() const { return m_templateString; } std::string PD_RDFSemanticStylesheet::type() const { return m_type; } bool PD_RDFSemanticStylesheet::isMutable() const { return m_isMutable; } /************************************************************/ /************************************************************/ /************************************************************/ PD_RDFSemanticItemViewSite::PD_RDFSemanticItemViewSite( PD_RDFSemanticItemHandle _si, const std::string& _xmlid ) : m_xmlid(_xmlid) , m_semItem(_si) { } PD_RDFSemanticItemViewSite::PD_RDFSemanticItemViewSite( PD_RDFSemanticItemHandle _si, PT_DocPosition pos ) : m_semItem(_si) { std::set< std::string > posxml; m_semItem->getRDF()->addRelevantIDsForPosition( posxml, pos ); std::set< std::string > sixml = m_semItem->getXMLIDs(); std::set< std::string > tmp; std::set_intersection( posxml.begin(), posxml.end(), sixml.begin(), sixml.end(), inserter( tmp, tmp.end() )); if( tmp.empty() ) { // error } else { m_xmlid = *(tmp.begin()); } } PD_RDFSemanticItemViewSite::~PD_RDFSemanticItemViewSite() { } PD_RDFSemanticStylesheetHandle PD_RDFSemanticItemViewSite::stylesheet() const { std::string name = getProperty("stylesheet", RDF_SEMANTIC_STYLESHEET_NAME); std::string type = getProperty("stylesheet-type", PD_RDFSemanticStylesheet::stylesheetTypeSystem()); std::string uuid = getProperty("stylesheet-uuid", ""); UT_DEBUGMSG(("stylesheet at site, format(), xmlid:%s\n", m_xmlid.c_str() )); UT_DEBUGMSG((" sheet:%s type:%s\n", name.c_str(), type.c_str() )); PD_RDFSemanticStylesheetHandle ret; if (!uuid.empty()) { ret = m_semItem->findStylesheetByUuid( uuid ); } if (!ret) { ret = m_semItem->findStylesheetByName( type, name ); } if (!ret) { // safety first, there will always be a default stylesheet ret = m_semItem->defaultStylesheet(); } return ret; } void PD_RDFSemanticItemViewSite::disassociateStylesheet() { UT_DEBUGMSG(("stylesheet at site. xmlid:%s\n", m_xmlid.c_str() )); setProperty("stylesheet", ""); setProperty("stylesheet-type", ""); setProperty("stylesheet-uuid", ""); } void PD_RDFSemanticItemViewSite::applyStylesheet( FV_View* pView, PD_RDFSemanticStylesheetHandle ss ) { if( !ss ) { UT_DEBUGMSG(("apply stylesheet at site. format(), xmlid:%s NO SHEET\n", m_xmlid.c_str())); return; } UT_DEBUGMSG(("apply stylesheet at site. format(), xmlid:%s sheet:%s\n", m_xmlid.c_str(), ss->name().c_str() )); setStylesheetWithoutReflow( ss ); reflowUsingCurrentStylesheet( pView ); } void PD_RDFSemanticItemViewSite::setStylesheetWithoutReflow( PD_RDFSemanticStylesheetHandle ss ) { // Save the stylesheet property UT_DEBUGMSG(("apply stylesheet at site. format(), xmlid:%s sheet:%s\n", m_xmlid.c_str(), ss->name().c_str() )); setProperty("stylesheet", ss->name()); setProperty("stylesheet-type", ss->type()); setProperty("stylesheet-uuid", ss->uuid()); } void PD_RDFSemanticItemViewSite::reflowUsingCurrentStylesheet( FV_View* pView ) { PD_RDFSemanticStylesheetHandle ss = stylesheet(); ss->format( m_semItem, pView, m_xmlid ); } void PD_RDFSemanticItemViewSite::select( FV_View* pView ) { std::set< std::string > xmlids; xmlids.insert( m_xmlid ); m_semItem->getRDF()->selectXMLIDs( xmlids, pView ); } PD_URI PD_RDFSemanticItemViewSite::linkingSubject() const { PD_DocumentRDFHandle rdf = m_semItem->getRDF(); PD_URI pred("http://calligra-suite.org/rdf/site/package/common#idref"); PD_Literal obj(m_xmlid); // try to find it if it already exists PD_URIList ul = rdf->getSubjects( pred, obj ); for( PD_URIList::iterator iter = ul.begin(); iter != ul.end(); ++iter ) { return *iter; } PD_DocumentRDFMutationHandle m = rdf->createMutation(); PD_URI ret = m->createBNode(); m->add( ret, pred, obj ); m->commit(); return ret; } std::string PD_RDFSemanticItemViewSite::getProperty(const std::string &prop, const std::string &defval) const { PD_DocumentRDFHandle rdf = m_semItem->getRDF(); PD_URI ls = linkingSubject(); std::string fqprop = "http://calligra-suite.org/rdf/site#" + prop; PD_ObjectList ol = rdf->getObjects( ls, PD_URI(fqprop) ); for( PD_ObjectList::iterator iter = ol.begin(); iter != ol.end(); ++iter ) { return iter->toString(); } return defval; } void PD_RDFSemanticItemViewSite::setProperty(const std::string &prop, const std::string &v) { PD_DocumentRDFHandle rdf = m_semItem->getRDF(); std::string fqprop = "http://calligra-suite.org/rdf/site#" + prop; PD_URI ls = linkingSubject(); PD_URI pred(fqprop); PD_DocumentRDFMutationHandle m = rdf->createMutation(); m->remove( ls, pred ); if( !v.empty() ) m->add( ls, pred, PD_Literal(v) ); m->commit(); } void PD_RDFSemanticItemViewSite::selectRange( FV_View* pView, std::pair< PT_DocPosition, PT_DocPosition > range ) { pView->selectRange( range ); } /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ PD_DocumentRDF::PD_DocumentRDF( PD_Document* doc ) : m_doc( doc ), m_indexAP( 0 ), m_haveSemItems( false ) { UT_DEBUGMSG(("PD_DocumentRDF() this:%p doc:%p\n",this,doc)); } PD_DocumentRDF::~PD_DocumentRDF() { UT_DEBUGMSG(("~PD_DocumentRDF() this:%p\n", this)); } std::string PD_DocumentRDF::makeLegalXMLID( const std::string& s ) { std::string ret; for( std::string::const_iterator iter = s.begin(); iter != s.end(); ++iter ) { char ch = *iter; if( ch >= 'a' && ch <= 'z' ) ret += ch; else if( ch >= 'A' && ch <= 'Z' ) ret += ch; else if( ch >= '0' && ch <= '9' ) ret += ch; else ret += '_'; } return ret; } void PD_DocumentRDF::relinkRDFToNewXMLID( const std::string& oldxmlid, const std::string& newxmlid, bool deepCopyRDF ) { if( deepCopyRDF ) { // FIXME: todo UT_DEBUGMSG(("relinkRDFToNewXMLID DEEP COPY FIXME oldid:%s newid:%s\n", oldxmlid.c_str(), newxmlid.c_str() )); } UT_DEBUGMSG(("relinkRDFToNewXMLID oldid:%s newid:%s\n", oldxmlid.c_str(), newxmlid.c_str() )); PD_DocumentRDFMutationHandle m = createMutation(); PD_URI idref("http://docs.oasis-open.org/opendocument/meta/package/common#idref"); std::set< std::string > oldlist; oldlist.insert( oldxmlid ); std::string sparql = getSPARQL_LimitedToXMLIDList( oldlist ); UT_DEBUGMSG(("relinkRDFToNewXMLID sparql:%s\n", sparql.c_str() )); PD_DocumentRDFHandle rdf = getDocument()->getDocumentRDF(); PD_RDFQuery q( rdf, rdf ); PD_ResultBindings_t bindings = q.executeQuery( sparql ); for( PD_ResultBindings_t::iterator iter = bindings.begin(); iter != bindings.end(); ++iter ) { std::map< std::string, std::string > d = *iter; PD_URI s( d["s"] ); PD_URI p( d["p"] ); PD_Object o( d["o"] ); UT_DEBUGMSG(("relinkRDFToNewXMLID oldid:%s newid:%s subj:%s\n", oldxmlid.c_str(), newxmlid.c_str(), s.toString().c_str() )); m->add( s, idref, PD_Literal( newxmlid )); } m->commit(); } std::string PD_DocumentRDF::getSPARQL_LimitedToXMLIDList( const std::set< std::string >& xmlids, const std::string& extraPreds ) { if( xmlids.empty() ) return ""; std::stringstream ss; ss << "prefix rdf: \n" << "prefix foaf: \n" << "prefix pkg: \n" << "prefix geo84: \n" << "\n" << "select ?s ?p ?o ?rdflink \n" << "where { \n" << " ?s ?p ?o . \n" << " ?s pkg:idref ?rdflink . \n" << " filter( "; std::string joiner = ""; for( std::set< std::string >::const_iterator iter = xmlids.begin(); iter != xmlids.end(); ++iter ) { ss << joiner << " str(?rdflink) = \"" << *iter << "\" "; joiner = " || "; } ss << " ) \n"; if( !extraPreds.empty() ) { ss << " . " << extraPreds << "\n"; } ss << "}\n"; std::string ret = ss.str(); return ret; } /** * If the document changes its m_pPieceTable it needs to call here * too. * * In various places like PD_Document::_importFile the document * creates a new piecetable and thus must notify the DocumentRDF of * this change so we can update our AttrProp indexes and the like. */ UT_Error PD_DocumentRDF::setupWithPieceTable() { PP_AttrProp* newAP = new PP_AttrProp(); PT_AttrPropIndex newAPI = 0; pt_PieceTable* pt = getPieceTable(); pt_VarSet& m_varset = pt->getVarSet(); bool success = m_varset.addIfUniqueAP( newAP, &newAPI ); if( !success ) { UT_DEBUGMSG(("PD_DocumentRDF::setupWithPieceTable() -- could not create raw RDF AttrProperties\n")); // MIQ 2010 July: addIfUniqueAP() method states false == memory error of some kind. return UT_OUTOFMEM; } m_indexAP = newAPI; UT_DEBUGMSG(("PD_DocumentRDF::setupWithPieceTable() m_indexAP:%d\n",m_indexAP)); return UT_OK; } /** * Change the AttrProp Index that we are using to store all the RDF. * This is used by PD_DocumentRDFMutation to commit it's changes. */ void PD_DocumentRDF::setIndexAP( PT_AttrPropIndex idx ) { m_indexAP = idx; } /** * Get the AttrProp index where we are storing all the RDF */ PT_AttrPropIndex PD_DocumentRDF::getIndexAP(void) const { return m_indexAP; } /** * Get the AttrProp with all the RDF in it */ const PP_AttrProp* PD_DocumentRDF::getAP(void) { PT_AttrPropIndex indexAP = getIndexAP(); pt_PieceTable* pt = getPieceTable(); pt_VarSet& m_varset = pt->getVarSet(); const PP_AttrProp* ret = m_varset.getAP(indexAP); return ret; } UT_Error PD_DocumentRDF::setAP( PP_AttrProp* newAP ) { newAP->prune(); newAP->markReadOnly(); pt_PieceTable* pt = getPieceTable(); pt_VarSet& m_varset = pt->getVarSet(); PT_AttrPropIndex newAPI = 0; bool success = m_varset.addIfUniqueAP( newAP, &newAPI ); // addIfUniqueAP() eats it newAP = 0; if(!success) { return UT_OUTOFMEM; } setIndexAP( newAPI ); return UT_OK; } bool PD_DocumentRDF::isStandAlone() const { return false; } PD_Document* PD_DocumentRDF::getDocument(void) const { return m_doc; } /** * Get a list of all the objects which have the given subject and predicate. * * For example: * emu has legs * emu has eyes * would give { legs, eyes } */ PD_ObjectList PD_DocumentRDF::getObjects( const PD_URI& s, const PD_URI& p ) { PD_ObjectList ret; apGetObjects( getAP(), ret, s, p ); return ret; } /** * Get a list of all the subjects which have the given predicate and object. * * For example: * emu has legs * emu has eyes * human has legs * when called with ( has, legs ) would give { emu, human } */ PD_URIList PD_DocumentRDF::getSubjects( const PD_URI& p, const PD_Object& o ) { PD_URIList ret; apGetSubjects( getAP(), ret, p, o ); return ret; } PD_URIList PD_DocumentRDF::getAllSubjects() { PD_URIList ret; apGetAllSubjects( getAP(), ret ); return ret; } /** * Internal method: Using the supplied AP, insert into ret a list of * every subject in the model. If you want to get all triples, then * first get all subjects and then use getArcsOut() to get the * predicate-object combinations for each of the subjects. */ PD_URIList& PD_DocumentRDF::apGetAllSubjects( const PP_AttrProp* AP, PD_URIList& ret ) { size_t count = AP->getPropertyCount(); for( size_t i = 0; igetNthProperty( i, szName, szValue) ) { std::string subj = szName; ret.push_back(subj); } } return ret; } /** * Get the predicate and objects which have the given subject. * This can be thought of as all the arcs from the node at 's' in the RDF * graph. */ POCol PD_DocumentRDF::getArcsOut( const PD_URI& s ) { POCol ret; apGetArcsOut( getAP(), ret, s ); return ret; } /** * Get the predicate and objects which have the given subject. * This can be thought of as all the arcs from the node at 's' in the RDF * graph. */ POCol& PD_DocumentRDF::apGetArcsOut( const PP_AttrProp* AP, POCol& ret, const PD_URI& s ) { const gchar* szValue = 0; if( AP->getProperty( s.toString().c_str(), szValue) ) { ret = decodePOCol(szValue); } return ret; } /** * Internal method: Using the supplied AP, insert into ret a list of * all the objects which have the given subject and predicate. * * For example: * emu has legs * emu has eyes * would give { legs, eyes } */ PD_ObjectList& PD_DocumentRDF::apGetObjects( const PP_AttrProp* AP, PD_ObjectList& ret, const PD_URI& s, const PD_URI& p ) { const gchar* szValue = 0; if( AP->getProperty( s.toString().c_str(), szValue) ) { POCol l = decodePOCol(szValue); std::pair< POCol::iterator, POCol::iterator > range = std::equal_range( l.begin(), l.end(), p ); for( POCol::iterator iter = range.first; iter != range.second; ++iter ) { ret.push_back( iter->second ); } } return ret; } /** * Internal method: Using the supplied AP, insert into ret a list of * all the subjects which have the given predicate and object. * * For example: * emu has legs * emu has eyes * human has legs * when called with ( has, legs ) would give { emu, human } */ PD_URIList& PD_DocumentRDF::apGetSubjects( const PP_AttrProp* AP, PD_URIList& ret, const PD_URI& p, const PD_Object& o ) { size_t count = AP->getPropertyCount(); for( size_t i = 0; igetNthProperty( i, szName, szValue) ) { POCol l = decodePOCol( szValue ); std::string subj = szName; for( POCol::iterator iter = l.begin(); iter!=l.end(); ++iter ) { if( iter->first == p && iter->second == o ) ret.push_back(subj); } } } return ret; } /** * Internal method: tests if the AP has the triple or not. */ bool PD_DocumentRDF::apContains( const PP_AttrProp* AP, const PD_URI& s, const PD_URI& p, const PD_Object& o ) { const gchar* szValue = 0; if( AP->getProperty( s.toString().c_str(), szValue) ) { POCol l = decodePOCol(szValue); std::pair< POCol::iterator, POCol::iterator > range = std::equal_range( l.begin(), l.end(), p ); for( POCol::iterator iter = range.first; iter != range.second; ++iter ) { if( iter->second == o ) return true; } } return false; } /** * Test if the given triple is in the RDF or not. */ bool PD_DocumentRDF::contains( const PD_URI& s, const PD_URI& p, const PD_Object& o ) { return apContains( getAP(), s, p, o ); } bool PD_DocumentRDF::contains( const PD_RDFStatement& st ) { return contains( st.getSubject(), st.getPredicate(), st.getObject() ); } /** * Get the total number of triples in the model. This can be * relatively expensive to calculate. So definately don't keep * on doing it in a loop. */ long PD_DocumentRDF::getTripleCount() { long ret = 0; PD_URIList subjects = getAllSubjects(); PD_URIList::iterator subjend = subjects.end(); for( PD_URIList::iterator subjiter = subjects.begin(); subjiter != subjend; ++subjiter ) { PD_URI subject = *subjiter; POCol polist = getArcsOut( subject ); POCol::iterator poend = polist.end(); for( POCol::iterator poiter = polist.begin(); poiter != poend; ++poiter ) { PD_URI predicate = poiter->first; PD_Object object = poiter->second; ++ret; } } return ret; } PD_RDFModelIterator PD_DocumentRDF::begin() { // UT_DEBUGMSG(("docrdf::begin() ap:%p\n", getAP() )); PD_RDFModelHandle model = getDocument()->getDocumentRDF(); PD_RDFModelIterator iter( model, getAP() ); return iter; } PD_RDFModelIterator PD_DocumentRDF::end() { return PD_RDFModelIterator(); } /** * The single way that you can update the document RDF is through * an PD_DocumentRDFMutation. This is where you get one of those. * * @see PD_DocumentRDFMutation */ PD_DocumentRDFMutationHandle PD_DocumentRDF::createMutation() { PD_DocumentRDFMutationHandle h(new PD_DocumentRDFMutation(this)); return h; } /** * Internal method: used by AbiCollab to update the RDF */ void PD_DocumentRDF::handleCollabEvent( gchar** szAtts, gchar** szProps ) { PD_DocumentRDFMutationHandle h = createMutation(); h->handleCollabEvent( szAtts, szProps ); h->commit(); } pt_PieceTable * PD_DocumentRDF::getPieceTable(void) const { return m_doc->getPieceTable(); } ////////////////////////////////// ////////////////////////////////// ////////////////////////////////// void RDFAnchor::setup( const PP_AttrProp* pAP ) { const gchar * v = 0; // if(pAP->getAttribute("this-is-an-rdf-anchor", v) && v) // UT_DEBUGMSG(("RDFAnchor() is-rdf-a:%s\n",v)); // if(pAP->getAttribute(PT_RDF_END, v) && v) // UT_DEBUGMSG(("RDFAnchor() PT_RDF_END:%s\n",v)); if( pAP->getAttribute(PT_RDF_END, v) && v) { m_isEnd = !strcmp(v,"yes"); } if( pAP->getAttribute(PT_XMLID, v) && v) { m_xmlid = v; } } RDFAnchor::RDFAnchor( PD_Document* pDoc, PT_AttrPropIndex api ) : m_isEnd( false ) { const PP_AttrProp * pAP = NULL; pDoc->getAttrProp( api, &pAP ); setup( pAP ); } RDFAnchor::RDFAnchor( PD_Document* doc, pf_Frag* pf ) : m_isEnd( false ) { PT_AttrPropIndex api = pf->getIndexAP(); const PP_AttrProp * pAP = NULL; doc->getAttrProp( api, &pAP ); setup( pAP ); } RDFAnchor::RDFAnchor( const PP_AttrProp* pAP ) : m_isEnd( false ) { setup( pAP ); } bool RDFAnchor::isEnd() { return m_isEnd; } std::string RDFAnchor::getID() { return m_xmlid; } ////////////////////////////////// ////////////////////////////////// ////////////////////////////////// std::set< std::string >& PD_DocumentRDF::getAllIDs( std::set< std::string >& ret ) { PD_Document* doc = getDocument(); pf_Frag * iter = doc->getFragFromPosition(0); // pf_Frag* last = doc->getLastFrag(); UT_DEBUGMSG(( "getAllIDs() iter starting at:%p\n", iter )); for( ; iter; iter = iter->getNext() ) { pf_Frag* pf = iter; std::string xmlid = pf->getXMLID(); if( !xmlid.empty() ) ret.insert( xmlid ); } return ret; } std::pair< PT_DocPosition, PT_DocPosition > PD_DocumentRDF::getIDRange( const std::string& xmlid ) const { std::pair< PT_DocPosition, PT_DocPosition > ret( 0, 0 ); PD_Document* doc = getDocument(); pf_Frag * iter = doc->getFragFromPosition(0); // UT_DEBUGMSG(( "getIDRange() iter starting at:%p\n", iter )); for( ; iter; iter = iter->getNext() ) { pf_Frag* pf = iter; std::string x = pf->getXMLID(); if( xmlid == x ) { PT_DocPosition epos = pf->getPos() + pf->getLength(); pf_Frag* e = pf->getNext(); for( ; e; e = e->getNext() ) { if( e->getType() == pf_Frag::PFT_Strux ) { const pf_Frag_Strux* pfs = static_cast(e); PTStruxType st = pfs->getStruxType(); if( st == PTX_Block || st == PTX_SectionCell ) { epos = e->getPos() - 1; break; } } if( e->getType() == pf_Frag::PFT_Object ) { const pf_Frag_Object* pfo = static_cast(e); if( pfo->getObjectType() == PTO_RDFAnchor ) { RDFAnchor a( doc, e ); if( a.getID() == xmlid ) { epos = e->getPos(); break; } } } } return std::make_pair( pf->getPos(), epos ); } } return ret; } std::set< std::string >& PD_DocumentRDF::addRelevantIDsForRange( std::set< std::string >& ret, PD_DocumentRange* range ) { addRelevantIDsForRange( ret, std::make_pair( range->m_pos1, range->m_pos2 )); return ret; } std::list< pf_Frag_Object* > PD_DocumentRDF::getObjectsInScopeOfTypesForRange( std::set< PTObjectType > objectTypes, std::pair< PT_DocPosition, PT_DocPosition > range ) { std::list< pf_Frag_Object* > ret; // PD_Document* doc = getDocument(); pt_PieceTable* pt = getPieceTable(); PT_DocPosition start = range.first; PT_DocPosition curr = range.second; PT_DocPosition searchBackThisFar = 0; if( !curr ) curr = start; // // Allow recursion of text:meta where an outside tag might encase the point but // another text:meta might completely be before point. Consider: // // .... // ... boo // ... POINT ... // // // In this case, we want to ignore the xml:id == nested anchors but find the // xml:id == outside one // std::set< std::string > m_ignoreIDSet; // // FIXME: Some form of index would be nice, rather than walking back the entire // document to find the RDF Anchors. // for( ; curr > searchBackThisFar; ) { pf_Frag* pf = 0; PT_BlockOffset boffset; if( pt->getFragFromPosition( curr, &pf, &boffset ) ) { xxx_UT_DEBUGMSG(("PD_DocumentRDF::getObjectsInScope() current:%d frag type:%d len:%d \n", curr, pf->getType(), pf->getLength() )); // skip backwards fast if possible. if(pf->getType() != pf_Frag::PFT_Object) { xxx_UT_DEBUGMSG(("PD_DocumentRDF::getObjectsInScope() SKIPPING BACK!\n" )); curr = pf->getPos() - 1; continue; } // otherwise keep moving backwards slowly anyway --curr; // check what RDF is attached to this object. if(pf->getType() == pf_Frag::PFT_Object) { pf_Frag_Object* pOb = static_cast(pf); const PP_AttrProp * pAP = NULL; xxx_UT_DEBUGMSG(("PD_DocumentRDF::getObjectsInScope() po type:%d\n", pOb->getObjectType() )); if( pOb->getObjectType() == PTO_Bookmark && objectTypes.count(pOb->getObjectType())) { pOb->getPieceTable()->getAttrProp(pOb->getIndexAP(),&pAP); const char* v = 0; if( pAP->getAttribute(PT_XMLID, v) && v) { std::string xmlid = v; bool isEnd = pAP->getAttribute("type", v) && v && !strcmp(v,"end"); xxx_UT_DEBUGMSG(("PD_DocumentRDF::getObjectsInScope() isEnd:%d id:%s\n", isEnd, xmlid.c_str() )); if( isEnd && curr < start ) { m_ignoreIDSet.insert( xmlid ); } else { if( !m_ignoreIDSet.count( xmlid )) ret.push_back( pOb ); } } } if( pOb->getObjectType() == PTO_RDFAnchor && objectTypes.count(pOb->getObjectType())) { pOb->getPieceTable()->getAttrProp(pOb->getIndexAP(),&pAP); RDFAnchor a(pAP); xxx_UT_DEBUGMSG(("PD_DocumentRDF::getObjectsInScope() isEnd:%d id:%s\n", a.isEnd(), a.getID().c_str() )); if( a.isEnd() && curr < start ) { m_ignoreIDSet.insert( a.getID() ); } else { if( !m_ignoreIDSet.count( a.getID() )) ret.push_back( pOb ); } } } } } return ret; } std::set< std::string >& PD_DocumentRDF::addXMLIDsForObjects( std::set< std::string >& ret, std::list< pf_Frag_Object* > objectList ) { const PP_AttrProp * pAP = NULL; for( std::list< pf_Frag_Object* >::iterator iter = objectList.begin(); iter != objectList.end(); ++iter ) { pf_Frag_Object* pOb = *iter; if( pOb->getObjectType() == PTO_Bookmark ) { pOb->getPieceTable()->getAttrProp(pOb->getIndexAP(),&pAP); const char* v = 0; if( pAP->getAttribute(PT_XMLID, v) && v) { std::string xmlid = v; ret.insert( xmlid ); } } if( pOb->getObjectType() == PTO_RDFAnchor ) { pOb->getPieceTable()->getAttrProp(pOb->getIndexAP(),&pAP); RDFAnchor a(pAP); ret.insert( a.getID() ); xxx_UT_DEBUGMSG(("addXMLIDsForObjects() xmlid:%s\n", a.getID().c_str() )); } } return ret; } PT_DocPosition PD_DocumentRDF::addXMLIDsForBlockAndTableCellForPosition( std::set< std::string >& col, PT_DocPosition pos ) { PT_DocPosition ret = pos; PD_Document* doc = getDocument(); pt_PieceTable* pt = getPieceTable(); pf_Frag* frag = doc->getFragFromPosition( pos ); ret = frag->getPos() - 1; // // xml:id attached to containing paragraph/header // / // pf_Frag_Strux* psdh; if( pt->getStruxOfTypeFromPosition( pos, PTX_Block, &psdh ) && psdh ) { xxx_UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() block pos:%d\n", pos )); PT_AttrPropIndex api = doc->getAPIFromSDH( psdh ); const PP_AttrProp * AP = NULL; doc->getAttrProp(api,&AP); if( AP ) { const char * v = NULL; if(AP->getAttribute("xml:id", v)) { xxx_UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() xmlid:%s \n",v)); col.insert(v); } } } // // xml:id attached to containing table:table-cell // if( pt->getStruxOfTypeFromPosition( pos, PTX_SectionCell, &psdh ) && psdh ) { xxx_UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() cell pos:%d\n", pos )); PT_AttrPropIndex api = doc->getAPIFromSDH( psdh ); const PP_AttrProp * AP = NULL; doc->getAttrProp(api,&AP); if( AP ) { const char * v = NULL; if(AP->getAttribute("xml:id", v)) { xxx_UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() xmlid:%s \n",v)); col.insert(v); #if 0 if(AP->getAttribute("props", v)) { xxx_UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() props:%s \n",v)); } #endif } } } return ret; } std::set< std::string >& PD_DocumentRDF::addRelevantIDsForRange( std::set< std::string >& ret, std::pair< PT_DocPosition, PT_DocPosition > range ) { // // A sneaky optimization, for the first position we might have to // search backward to the start of the document to see opening // blocks and text:meta elements which might have RDF attached. // However, for startpos+1 to the end position we only have to // consider the range itself because we have already added any IDs // which might have opened before the range with the first // backward search. // PT_DocPosition pos = range.first; xxx_UT_DEBUGMSG(("PD_DocumentRDF::addRelevantIDsForRange() xxxyyy begin:%d end:%d\n", range.first, range.second )); xxx_UT_DEBUGMSG(("PD_DocumentRDF::addRelevantIDsForRange() xxxyyy looking back to find bookmark and rdf anchor openings...\n" )); std::set< PTObjectType > objectTypes; objectTypes.insert( PTO_Bookmark ); objectTypes.insert( PTO_RDFAnchor ); std::list< pf_Frag_Object* > objectList = getObjectsInScopeOfTypesForRange( objectTypes, range ); addXMLIDsForObjects( ret, objectList ); xxx_UT_DEBUGMSG(("PD_DocumentRDF::addRelevantIDsForRange() xxxyyy objectList.sz:%ld\n", objectList.size() )); addXMLIDsForBlockAndTableCellForPosition( ret, pos ); xxx_UT_DEBUGMSG(("PD_DocumentRDF::addRelevantIDsForRange() xxxyyy inspecting range...\n" )); // PT_DocPosition searchBackThisFar = pos; ++pos; PT_DocPosition endPos = range.second; if( !endPos ) { endPos = range.first+1; } for( PT_DocPosition curr = endPos; curr >= range.first; ) { xxx_UT_DEBUGMSG(("PD_DocumentRDF::addRelevantIDsForRange() xxxyyy looping curr:%d\n", curr )); curr = addXMLIDsForBlockAndTableCellForPosition( ret, curr ); } // priv_addRelevantIDsForPosition( ret, endPos, searchBackThisFar ); // for( ; pos <= range.second; ++pos ) // { // priv_addRelevantIDsForPosition( ret, pos, searchBackThisFar ); // } xxx_UT_DEBUGMSG(("PD_DocumentRDF::addRelevantIDsForRange() ret begin:%d end:%d\n", range.first, range.second )); return ret; } std::set< std::string >& PD_DocumentRDF::addRelevantIDsForPosition( std::set< std::string >& ret, PT_DocPosition pos ) { addRelevantIDsForRange( ret, std::make_pair( pos, (PT_DocPosition)0 ) ); return ret; } std::set< std::string >& PD_DocumentRDF::priv_addRelevantIDsForPosition( std::set< std::string >& ret, PT_DocPosition pos, PT_DocPosition searchBackThisFar ) { PD_Document* doc = getDocument(); pt_PieceTable* pt = getPieceTable(); PT_DocPosition curr = pos; UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() current:%d searchBackLimit:%d\n", curr, searchBackThisFar )); // // Allow recursion of text:meta where an outside tag might encase the point but // another text:meta might completely be before point. Consider: // // .... // ... boo // ... POINT ... // // // In this case, we want to ignore the xml:id == nested anchors but find the // xml:id == outside one // std::set< std::string > m_ignoreIDSet; // // FIXME: Some form of index would be nice, rather than walking back the entire // document to find the RDF Anchors. // for( ; curr > searchBackThisFar; ) { pf_Frag* pf = 0; PT_BlockOffset boffset; if( pt->getFragFromPosition( curr, &pf, &boffset ) ) { UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() current:%d frag type:%d len:%d \n", curr, pf->getType(), pf->getLength() )); // skip backwards fast if possible. if(pf->getType() != pf_Frag::PFT_Object) { curr = pf->getPos() - 1; continue; } // otherwise keep moving backwards slowly anyway --curr; // check what RDF is attached to this object. if(pf->getType() == pf_Frag::PFT_Object) { pf_Frag_Object* pOb = static_cast(pf); const PP_AttrProp * pAP = NULL; UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() po type:%d\n", pOb->getObjectType() )); if(pOb->getObjectType() == PTO_Bookmark) { pOb->getPieceTable()->getAttrProp(pOb->getIndexAP(),&pAP); const char* v = 0; if( pAP->getAttribute(PT_XMLID, v) && v) { std::string xmlid = v; bool isEnd = pAP->getAttribute("type", v) && v && !strcmp(v,"end"); UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() isEnd:%d id:%s\n", isEnd, xmlid.c_str() )); if( isEnd ) { m_ignoreIDSet.insert( xmlid ); } else { if( !m_ignoreIDSet.count( xmlid )) ret.insert( xmlid ); } } } if(pOb->getObjectType() == PTO_RDFAnchor) { pOb->getPieceTable()->getAttrProp(pOb->getIndexAP(),&pAP); RDFAnchor a(pAP); UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() isEnd:%d id:%s\n", a.isEnd(), a.getID().c_str() )); if( a.isEnd() ) { m_ignoreIDSet.insert( a.getID() ); } else { if( !m_ignoreIDSet.count( a.getID() )) ret.insert( a.getID() ); } } } } } // // xml:id attached to containing paragraph/header // / // pf_Frag_Strux* psdh; if( pt->getStruxOfTypeFromPosition( pos, PTX_Block, &psdh ) && psdh ) { UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() block pos:%d\n", pos )); PT_AttrPropIndex api = doc->getAPIFromSDH( psdh ); const PP_AttrProp * AP = NULL; doc->getAttrProp(api,&AP); if( AP ) { const char * v = NULL; if(AP->getAttribute("xml:id", v)) { UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() xmlid:%s \n",v)); ret.insert(v); } } } // // xml:id attached to containing table:table-cell // if( pt->getStruxOfTypeFromPosition( pos, PTX_SectionCell, &psdh ) && psdh ) { UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() cell pos:%d\n", pos )); PT_AttrPropIndex api = doc->getAPIFromSDH( psdh ); const PP_AttrProp * AP = NULL; doc->getAttrProp(api,&AP); if( AP ) { const char * v = NULL; if(AP->getAttribute("xml:id", v)) { UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() xmlid:%s \n",v)); ret.insert(v); if(AP->getAttribute("props", v)) { UT_DEBUGMSG(("PD_DocumentRDF::priv_addRelevantIDsForPosition() props:%s \n",v)); } } } } return ret; } PD_RDFModelHandle PD_DocumentRDF::createScratchModel() { PD_Document* doc = getDocument(); PP_AttrProp* AP = new PP_AttrProp(); PD_RDFModelFromAP* retModel = new PD_RDFModelFromAP( doc, AP ); PD_RDFModelHandle ret( retModel ); return ret; } PD_URI PD_DocumentRDF::getManifestURI() { return PD_URI("http://abiword.org/manifest.rdf"); } PD_RDFModelHandle PD_DocumentRDF::getRDFAtPosition( PT_DocPosition pos ) { UT_DEBUG_ONLY_ARG(pos); PD_Document* doc = getDocument(); #ifdef DEBUG std::set< std::string > IDList; addRelevantIDsForPosition( IDList, pos ); PP_AttrProp* AP = new PP_AttrProp(); PD_RDFModelFromAP* retModel = new PD_RDFModelFromAP( doc, AP ); PD_RDFModelHandle ret( retModel ); if( !IDList.empty() ) { PD_DocumentRDFMutationHandle m = retModel->createMutation(); for( std::set< std::string >::iterator iter = IDList.begin(); iter != IDList.end(); ++iter ) { std::string xmlid = *iter; addRDFForID( xmlid, m ); } m->commit(); } // retModel->dumpModel("RDF result for xmlid"); return ret; // if( pt->getStruxOfTypeFromPosition( pos, PTX_Block, &psdh ) && psdh ) // { // UT_DEBUGMSG(("PD_DocumentRDF::getRDFAtPosition() pos:%d\n", pos )); // PT_AttrPropIndex api = doc->getAPIFromSDH( psdh ); // const PP_AttrProp * AP = NULL; // doc->getAttrProp(api,&AP); // if( AP ) // { // const char * v = NULL; // if(AP->getAttribute("xml:id", v)) // { // UT_DEBUGMSG(("PD_DocumentRDF::getRDFAtPosition() xmlid:%s \n",v)); // PD_RDFModelHandle ret = getRDFForID( v ); // return ret; // } // } // } #else { // return an empty model PD_RDFModelHandle x( new PD_RDFModelFromAP( doc, new PP_AttrProp() )); return x; } #endif } void PD_DocumentRDF::addRDFForID( const std::string& xmlid, PD_DocumentRDFMutationHandle& m ) { // Execute query to find all triples related to xmlid // and add them all to the mutation m // // prefix rdf: // prefix pkg: // select ?s ?p ?o // where { // ?s pkg:idref ?xmlid . // ?s ?p ?o . // filter( str(?xmlid) = \"" << xmlid << "\" ) // }; PD_URI pkg_idref("http://docs.oasis-open.org/opendocument/meta/package/common#idref"); PD_Object xmlidNode( xmlid ); PD_URIList subjects = getAllSubjects(); PD_URIList::iterator subjend = subjects.end(); for( PD_URIList::iterator subjiter = subjects.begin(); subjiter != subjend; ++subjiter ) { bool addSubject = false; PD_URI subject = *subjiter; { POCol polist = getArcsOut( subject ); POCol::iterator poend = polist.end(); for( POCol::iterator poiter = polist.begin(); poiter != poend; ++poiter ) { PD_URI predicate = poiter->first; PD_Object object = poiter->second; if( predicate == pkg_idref && object == xmlidNode ) { addSubject = true; break; } } } if( addSubject ) { POCol polist = getArcsOut( subject ); POCol::iterator poend = polist.end(); for( POCol::iterator poiter = polist.begin(); poiter != poend; ++poiter ) { PD_URI predicate = poiter->first; PD_Object object = poiter->second; UT_DEBUGMSG(("PD_DocumentRDF::adding s:%s p:%s o:%s\n", subject.toString().c_str(), predicate.toString().c_str(), object.toString().c_str() )); m->add( subject, predicate, object ); } } } } PD_RDFModelHandle PD_DocumentRDF::getRDFForID( const std::string& xmlid ) { PP_AttrProp* AP = new PP_AttrProp(); PD_RDFModelFromAP* retModel = new PD_RDFModelFromAP( m_doc, AP ); PD_RDFModelHandle ret( retModel ); PD_DocumentRDFMutationHandle m = retModel->createMutation(); addRDFForID( xmlid, m ); m->commit(); // retModel->dumpModel("RDF result for xmlid"); return ret; } void PD_DocumentRDF::runMilestone2Test() { #ifdef DEBUG UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test() doc:%p\n", m_doc)); { PD_DocumentRDFMutationHandle m = createMutation(); m->add( PD_URI("http://www.example.com/foo"), PD_URI("http://www.example.com/bar"), PD_Literal("AABBCC") ); m->add( PD_URI("http://www.example.com/koala"), PD_URI("http://www.example.com/is-a"), PD_Literal("dangeroo", "http://www.w3.org/2001/XMLSchema#boolean" )); } dumpModel(); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test() -------------------------------\n")); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test() adding some more triples\n")); { PD_DocumentRDFMutationHandle m = createMutation(); m->add( PD_URI("http://www.example.com/foo"), PD_URI("http://www.example.com/bar2"), PD_Literal("extra data") ); m->add( PD_URI("http://www.example.com/foo"), PD_URI("http://www.example.com/magic"), PD_Literal("card trick", "http://www.w3.org/2001/XMLSchema#string" )); m->add( PD_URI("http://www.example.com/emu"), PD_URI("http://www.example.com/lives-in"), PD_Object("http://www.example.com/australia")); m->add( PD_URI("http://www.example.com/water dragon"), PD_URI("http://www.example.com/lives-in"), PD_Object("http://www.example.com/australia")); } dumpModel(); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test() -------------------------------\n")); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test() removing some triples\n")); { // This test removes something from foo, which has multiple // values in it's PO list. Also the koala is removed, so the // whole s->po mapping should disappear from the AP after // commit(); PD_DocumentRDFMutationHandle m = createMutation(); m->remove( PD_URI("http://www.example.com/koala"), PD_URI("http://www.example.com/is-a"), PD_Object("http://www.example.com/dangeroo")); m->remove( PD_URI("http://www.example.com/foo"), PD_URI("http://www.example.com/bar"), PD_Literal("AABBCC") ); } dumpModel(); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test() -------------------------------\n")); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test() rollback test\n")); { PD_DocumentRDFMutationHandle m = createMutation(); m->add( PD_URI("http://www.example.com/et"), PD_URI("http://www.example.com/is-a"), PD_Object("http://www.example.com/alien")); m->rollback(); } dumpModel(); runMilestone2Test2(); #endif } #ifdef DEBUG static void dump( const std::string& msg, PD_RDFModelIterator iter, PD_RDFModelIterator e ) { int count = 0; UT_DEBUGMSG(("dump(top) msg::%s\n", msg.c_str() )); for( ; iter != e; ++iter ) { const PD_RDFStatement& st(*iter); UT_DEBUGMSG((" st:%s\n", st.toString().c_str() )); ++count; } UT_DEBUGMSG(("dump(end) count:%d msg::%s\n", count, msg.c_str() )); } #endif void PD_DocumentRDF::updateHaveSemItemsCache() { PD_RDFSemanticItems items = getAllSemanticObjects(); m_haveSemItems = !items.empty(); } bool PD_DocumentRDF::haveSemItems() const { return m_haveSemItems; } void PD_DocumentRDF::runPlay() { #ifdef DEBUG UT_DEBUGMSG(("================================================================================\n" )); UT_DEBUGMSG(("PD_DocumentRDF::runPlay() o:%s\n", "foo" )); PD_RDFContacts cl = getContacts(); UT_DEBUGMSG(("PD_DocumentRDF::runPlay() contacts.sz:%lu\n", (long unsigned)cl.size() )); for( PD_RDFContacts::iterator ci = cl.begin(); ci != cl.end(); ++ci ) { PD_RDFContactHandle c = *ci; UT_DEBUGMSG((" subj:%s\n", c->linkingSubject().toString().c_str() )); UT_DEBUGMSG((" name:%s\n", c->name().c_str() )); std::set< std::string > xmlids = c->getXMLIDs(); for( std::set< std::string >::iterator iter = xmlids.begin(); iter != xmlids.end(); ++iter ) { std::string xmlid = *iter; UT_DEBUGMSG((" x2mlid:%s ", xmlid.c_str() )); std::pair< PT_DocPosition, PT_DocPosition > range = getIDRange( xmlid ); UT_DEBUGMSG((" start:%d end:%d ", range.first, range.second )); UT_DEBUGMSG((" \n" )); } // if( c->name() == "James Smith" ) // { // c->showEditorWindow( c ); // } } PD_RDFEvents el = getEvents(); UT_DEBUGMSG((" events.sz:%lu\n", (long unsigned)el.size() )); for( PD_RDFEvents::iterator ei = el.begin(); ei != el.end(); ++ei ) { PD_RDFEventHandle e = *ei; UT_DEBUGMSG((" events.name:%s\n", e->name().c_str() )); if( e->name() == "uri:campingtime" ) { e->showEditorWindow( e ); } } return; UT_DebugOnly count = 0; typedef PD_RDFModelIterator iterator; dump( "whole model", begin(), end() ); UT_DEBUGMSG(("runPlay() triple count:%d\n", (int)count )); UT_DEBUGMSG(("runPlay()\n\n")); PD_RDFModelHandle m = getRDFForID( "wingb" ); dump( "wingb", m->begin(), m->end() ); #endif } void PD_DocumentRDF::runMilestone2Test2() { #ifdef DEBUG PD_URI s; PD_URI o = getObject( PD_URI("http://www.example.com/emu"), PD_URI("http://www.example.com/lives-in")); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test2() o:%s\n", o.toString().c_str())); o = getObject( PD_URI("http://www.example.com/et"), PD_URI("http://www.example.com/is-a")); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test2() (should be nothing) o:%s\n", o.toString().c_str())); POCol col = getArcsOut( PD_URI("http://www.example.com/foo") ); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test2() subject foo has arcs... count:%d\n", (int)col.size())); for( POCol::iterator iter = col .begin(); iter != col.end(); ++iter ) { UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test2() p:%s\n", iter->first.toString().c_str())); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test2() o:%s\n", iter->second.toString().c_str())); } s = getSubject( PD_URI("http://www.example.com/lives-in"), PD_Object("http://www.example.com/australia")); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test2() one creature living in aus:%s\n", s.toString().c_str())); PD_URIList ul = getSubjects( PD_URI("http://www.example.com/lives-in"), PD_Object("http://www.example.com/australia")); UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test2() all of the creatures living in aus, count:%d\n", (int)ul.size())); for( PD_URIList::iterator iter = ul.begin(); iter != ul.end(); ++iter ) { UT_DEBUGMSG(("PD_DocumentRDF::runMilestone2Test2() creature:%s\n", iter->toString().c_str())); } #endif } void PD_DocumentRDF::dumpObjectMarkersFromDocument() { #ifdef DEBUG UT_DEBUGMSG(("PD_DocumentRDF::dumpObjectMarkersFromDocument() doc:%p\n", m_doc)); m_doc->dumpDoc("dumpObjectMarkersFromDocument", 0, 0); PD_Document* doc = getDocument(); pt_PieceTable* pt = getPieceTable(); PT_DocPosition curr = 0; PT_DocPosition eod = 0; pt->getBounds( true, eod ); UT_DEBUGMSG(("PD_DocumentRDF::dumpObjectMarkersFromDocument() current:%d end:%d\n", curr, eod )); for( ; curr < eod; ++curr ) { pf_Frag* pf = 0; PT_BlockOffset boffset; pf_Frag_Strux* psdh; if( pt->getStruxOfTypeFromPosition( curr, PTX_Block, &psdh ) && psdh ) { UT_DEBUGMSG(("PD_DocumentRDF::dumpObjectMarkersFromDocument() current:%d end:%d have PTX_BLOCK \n", curr, eod )); PT_AttrPropIndex api = doc->getAPIFromSDH( psdh ); const PP_AttrProp * AP = NULL; doc->getAttrProp(api,&AP); if( AP ) { const char * v = NULL; if(AP->getAttribute("xml:id",v)) { UT_DEBUGMSG(("PD_DocumentRDF::dumpObjectMarkersFromDocument() xmlid:%s \n",v)); } } } if( pt->getFragFromPosition( curr, &pf, &boffset ) ) { UT_DEBUGMSG(("PD_DocumentRDF::dumpObjectMarkersFromDocument() current:%d end:%d frag type:%d len:%d \n", curr, eod, pf->getType(), pf->getLength() )); if(pf->getType() == pf_Frag::PFT_Object) { pf_Frag_Object* pOb = static_cast(pf); UT_DEBUGMSG(("PD_DocumentRDF::dumpObjectMarkersFromDocument() po type:%d\n", pOb->getObjectType() )); if(pOb->getObjectType() == PTO_RDFAnchor) { const PP_AttrProp * pAP = NULL; pOb->getPieceTable()->getAttrProp(pOb->getIndexAP(),&pAP); const gchar * v = 0; if(!pAP->getAttribute(PT_XMLID, v) || !v) { } else { UT_DEBUGMSG(("PD_DocumentRDF::dumpObjectMarkersFromDocument() xml:id:%s\n",v)); } if(pAP->getAttribute("this-is-an-rdf-anchor", v) && v) { UT_DEBUGMSG(("PD_DocumentRDF::dumpObjectMarkersFromDocument() is-rdf-a:%s\n",v)); } } } } } ////////////// // curr = 420; // PD_RDFModelHandle h = getRDFAtPosition( curr ); #endif } /** * Dump the model as debug messages */ void PD_DocumentRDF::dumpModel( const std::string& headerMsg ) { UT_DEBUG_ONLY_ARG(headerMsg); #ifdef DEBUG UT_DEBUGMSG(("PD_DocumentRDF::dumpModel() doc:%p\n", m_doc)); apDumpModel( getAP(), headerMsg ); #endif } void PD_DocumentRDF::maybeSetDocumentDirty() { if( m_doc ) m_doc->forceDirty(); incremenetVersion(); } /** * Dump the model contained in the given AP as debug messages */ void PD_DocumentRDF::apDumpModel( const PP_AttrProp* AP, const std::string& headerMsg ) { UT_DEBUG_ONLY_ARG(AP); UT_DEBUG_ONLY_ARG(headerMsg); #ifdef DEBUG UT_DEBUGMSG(("PD_DocumentRDF::apDumpModel() ----------------------------------\n")); UT_DEBUGMSG(("PD_DocumentRDF::apDumpModel() %s\n", headerMsg.c_str())); UT_DEBUGMSG(("PD_DocumentRDF::apDumpModel() triple count:%ld\n", getTripleCount())); UT_DEBUGMSG(("PD_DocumentRDF::apDumpModel() ----------------------------------\n")); size_t count = AP->getPropertyCount(); UT_DEBUGMSG(("PD_DocumentRDF::DUMPMODEL() API:%d COUNT:%ld\n", m_indexAP, (long)count)); for( size_t i = 0; i < count; ++i ) { const gchar * szName = 0; const gchar * szValue = 0; if( AP->getNthProperty( i, szName, szValue) ) { // UT_DEBUGMSG(("PD_DocumentRDF::dumpModel() szName :%s\n", szName )); // UT_DEBUGMSG(("PD_DocumentRDF::dumpModel() szValue:%s\n", szValue )); POCol l = decodePOCol( szValue ); // UT_DEBUGMSG(("PD_DocumentRDF::dumpModel() po list size:%d\n", (int)l.size() )); std::string subj = szName; for( POCol::iterator iter = l.begin(); iter!=l.end(); ++iter ) { std::string pred = iter->first.toString(); std::string obj = iter->second.toString(); UT_DEBUGMSG(("PD_DocumentRDF::dumpModel() s:%s\n", subj.c_str())); UT_DEBUGMSG(("PD_DocumentRDF::dumpModel() p:%s\n", pred.c_str())); UT_DEBUGMSG(("PD_DocumentRDF::dumpModel() ot:%d o:%s\n", iter->second.getObjectType(), obj.c_str())); if( iter->second.hasXSDType() ) { UT_DEBUGMSG(("PD_DocumentRDF::dumpModel() type:%s\n", iter->second.getXSDType().c_str())); } } } } #endif } /****************************************/ /****************************************/ /****************************************/ /****************************************/ /****************************************/ /****************************************/ /** * A view on the given delegate model, restricted to showing only the * triples which match a given SPARQL query. For dynamicaly created * queries, a subclass might overload getSparql() and make the query * string at runtime. * * Subclasses might decide to override createMutation() to adjust * things when changes are desired. */ class RDFModel_SPARQLLimited : public PD_RDFModelFromAP { protected: PD_DocumentRDFHandle m_rdf; PD_RDFModelHandle m_delegate; std::string m_sparql; protected: virtual void update(); public: RDFModel_SPARQLLimited( PD_DocumentRDFHandle rdf, PD_RDFModelHandle delegate ) : PD_RDFModelFromAP( rdf->getDocument(), new PP_AttrProp() ) , m_rdf( rdf ) , m_delegate( delegate ) { } virtual ~RDFModel_SPARQLLimited() { } virtual PD_DocumentRDFMutationHandle createMutation(); virtual std::string getSparql() { return m_sparql; } void setSparql( const std::string& s ) { m_sparql = s; } virtual const PP_AttrProp* getAP(void) { update(); return m_AP; } }; PD_DocumentRDFMutationHandle RDFModel_SPARQLLimited::createMutation() { PD_DocumentRDFMutationHandle ret; return ret; } void RDFModel_SPARQLLimited::update() { UT_DEBUGMSG(("RDFModel_SPARQLLimited::update() TOP\n" )); UT_DEBUGMSG(("RDFModel_SPARQLLimited::update() our version:%ld\n", getVersion() )); UT_DEBUGMSG(("RDFModel_SPARQLLimited::update() their version:%ld\n", m_delegate->getVersion() )); if( getVersion() >= m_delegate->getVersion() ) { UT_DEBUGMSG(("RDFModel_SPARQLLimited::update() nothing to be done...\n" )); return; } PP_AttrProp* AP = new PP_AttrProp(); UT_DEBUGMSG(("RDFModel_SPARQLLimited::update() 1\n" )); UT_DEBUGMSG(("RDFModel_SPARQLLimited::update() sparql:%s\n", getSparql().c_str() )); PD_RDFQuery q( m_rdf, m_delegate ); PD_ResultBindings_t bindings = q.executeQuery( getSparql() ); UT_DEBUGMSG(("RDFModel_SPARQLLimited::update() 2\n" )); for( PD_ResultBindings_t::iterator iter = bindings.begin(); iter != bindings.end(); ++iter ) { std::map< std::string, std::string > d = *iter; PD_URI s( d["s"] ); PD_URI p( d["p"] ); int objectType = PD_Object::OBJECT_TYPE_URI; PD_Object dobj = m_delegate->getObject( s, p ); UT_DEBUGMSG(("RDFModel_SPARQLLimited::update() dobj.valid:%d dobj.type:%d dobj.str:%s \n", dobj.isValid(), dobj.getObjectType(), dobj.toString().c_str() )); if( dobj.isValid() ) objectType = dobj.getObjectType(); PD_Object o( d["o"], objectType ); POCol l; const gchar* szName = s.toString().c_str(); const gchar* szValue = 0; if( AP->getProperty( szName, szValue) ) { l = decodePOCol(szValue); } l.insert( std::make_pair( p, o )); std::string po = encodePOCol(l); AP->setProperty( szName, po.c_str() ); PD_RDFStatement st( s, p, o ); UT_DEBUGMSG(("RDFModel_SPARQLLimited::update() adding st:%s \n", st.toString().c_str() )); } delete m_AP; m_AP = AP; m_version = m_delegate->getVersion(); // dumpModel("after sparql query..."); } /****************************************/ /****************************************/ /****************************************/ class RDFModel_XMLIDLimited : public RDFModel_SPARQLLimited { std::string m_writeID; std::set< std::string > m_readIDList; protected: virtual void update(); public: RDFModel_XMLIDLimited( PD_DocumentRDFHandle rdf, PD_RDFModelHandle delegate, const std::string& writeID, const std::set< std::string >& readIDList ) : RDFModel_SPARQLLimited( rdf, delegate ) , m_writeID( writeID ) , m_readIDList( readIDList ) { } virtual ~RDFModel_XMLIDLimited() { UT_DEBUGMSG(("~RDFModel_XMLIDLimited()\n")); } virtual std::string getSparql(); virtual PD_DocumentRDFMutationHandle createMutation(); }; void RDFModel_XMLIDLimited::update() { if( getVersion() >= m_delegate->getVersion() ) { UT_DEBUGMSG(("RDFModel_XMLIDLimited::update() nothing to be done...\n" )); return; } std::set< std::string > xmlids; xmlids.insert( m_writeID ); copy( m_readIDList.begin(), m_readIDList.end(), inserter( xmlids, xmlids.end() ) ); if( xmlids.size() == 1 ) { std::string xmlid = *(xmlids.begin()); PP_AttrProp* AP = new PP_AttrProp(); PD_URI idref( "http://docs.oasis-open.org/opendocument/meta/package/common#pkg:idref" ); PD_Literal rdflink( xmlid ); PD_URI s = m_delegate->getSubject( idref, rdflink ); POCol polist = m_delegate->getArcsOut( s ); const gchar* szName = s.toString().c_str(); std::string po = encodePOCol( polist ); AP->setProperty( szName, po.c_str() ); return; } RDFModel_SPARQLLimited::update(); } std::string RDFModel_XMLIDLimited::getSparql() { UT_DEBUGMSG(("RDFModel_XMLIDLimited::getSparql()\n")); std::set< std::string > xmlids; xmlids.insert( m_writeID ); copy( m_readIDList.begin(), m_readIDList.end(), inserter( xmlids, xmlids.end() ) ); std::string sparql = PD_DocumentRDF::getSPARQL_LimitedToXMLIDList( xmlids ); return sparql; } class ABI_EXPORT PD_RDFMutation_XMLIDLimited : public PD_DocumentRDFMutation { PD_DocumentRDFMutationHandle m_delegate; std::string m_writeID; typedef std::set< std::string > m_cleanupSubjects_t; m_cleanupSubjects_t m_cleanupSubjects; public: PD_RDFMutation_XMLIDLimited( PD_DocumentRDF* rdf, PD_DocumentRDFMutationHandle delegate, const std::string& xmlid ) : PD_DocumentRDFMutation( rdf ) , m_delegate( delegate ) , m_writeID( xmlid ) { } virtual bool add( const PD_URI& s, const PD_URI& p, const PD_Object& o ) { UT_DEBUGMSG(("XMLIDLimited::add() s:%s\n", s.toString().c_str() )); UT_DEBUGMSG(("XMLIDLimited::add() p:%s\n", p.toString().c_str() )); UT_DEBUGMSG(("XMLIDLimited::add() o:%s\n", o.toString().c_str() )); UT_DEBUGMSG(("XMLIDLimited::add() s:%s linking to xmlid:%s\n", s.toString().c_str(), m_writeID.c_str() )); bool rc = true; rc &= m_delegate->add( s, p, o ); if( !rc ) return rc; PD_RDFStatement rdflink( s, PD_URI("http://docs.oasis-open.org/opendocument/meta/package/common#idref"), PD_Literal(m_writeID) ); UT_DEBUGMSG(("XMLIDLimited::add() testing document for existing rdflink\n" )); if( !m_rdf->contains( rdflink )) { UT_DEBUGMSG(("XMLIDLimited::add() document does not contain the rdflink\n" )); rc &= m_delegate->add( rdflink ); } UT_DEBUGMSG(("XMLIDLimited::add() s:%s linking to xmlid:%s rc:%d\n", s.toString().c_str(), m_writeID.c_str(), rc )); return rc; } virtual void remove( const PD_URI& s, const PD_URI& p, const PD_Object& o ) { POCol po = m_rdf->getArcsOut( s ); UT_DEBUGMSG(("XMLIDLimited::remove() subject count:%d\n", (int)po.size() )); m_delegate->remove( s, p, o ); m_cleanupSubjects.insert( s.toString() ); } virtual UT_Error commit() { UT_DEBUGMSG(("XMLIDLimited::commit()\n" )); UT_Error ret = m_delegate->commit(); // // Check the subjects that were deleted to see if they are now only // involved in triples like // s pkg:idref ?xmlid // for( m_cleanupSubjects_t::iterator iter = m_cleanupSubjects.begin(); iter != m_cleanupSubjects.end(); ++iter ) { std::string subj = *iter; std::stringstream sparql; sparql << "prefix rdf: \n" << "prefix foaf: \n" << "prefix pkg: \n" << "prefix geo84: \n" << " \n" << "select ?s ?p ?o ?rdflink \n" << "where { \n" << " ?s ?p ?o . \n" << " ?s pkg:idref ?rdflink . \n" << " filter( str(?s) = \"" << subj << "\" ) . \n" << " filter( str(?p) != \"http://docs.oasis-open.org/opendocument/meta/package/common#idref\" ) \n" << "} \n"; // std::list< std::string > xmlids; // xmlids.push_back( xmlid ); // std::string sparql = PD_DocumentRDF::getSPARQL_LimitedToXMLIDList( // xmlids, // "filter( str(?p) != \"http://docs.oasis-open.org/opendocument/meta/package/common#idref\" ) " ); PD_DocumentRDFHandle rdf = m_rdf->getDocument()->getDocumentRDF(); PD_RDFQuery q( rdf, rdf ); PD_ResultBindings_t bindings = q.executeQuery( sparql.str() ); UT_DEBUGMSG(("XMLIDLimited::commit() subj:%s bindings.count:%d\n", subj.c_str(), (int)bindings.size() )); if( bindings.empty() ) { PD_URI s(subj); PD_URI idref("http://docs.oasis-open.org/opendocument/meta/package/common#idref"); UT_DEBUGMSG(("XMLIDLimited::commit() can remove links for subj:%s\n", subj.c_str() )); PD_ObjectList ul = rdf->getObjects( subj, idref ); PD_DocumentRDFMutationHandle m = rdf->createMutation(); for( PD_ObjectList::iterator iter2 = ul.begin(); iter2 != ul.end(); ++iter2 ) { m->remove( s, idref, *iter2 ); } m->commit(); } } return ret; } virtual void rollback() { m_delegate->rollback(); } }; PD_DocumentRDFMutationHandle RDFModel_XMLIDLimited::createMutation() { UT_DEBUGMSG(("XMLIDLimited::createMutation()\n")); PD_DocumentRDFMutationHandle dmodel = m_delegate->createMutation(); PD_DocumentRDFMutationHandle ret( new PD_RDFMutation_XMLIDLimited( dmodel->m_rdf, dmodel, m_writeID )); return ret; } PD_RDFModelHandle PD_DocumentRDF::createRestrictedModelForXMLIDs( const std::string& writeID, const std::set< std::string >& xmlids ) { UT_DEBUGMSG(("createRestrictedModelForXMLIDs() writeID:%s xmlids.sz:%d\n", writeID.c_str(), (int)xmlids.size() )); PD_DocumentRDFHandle rdf = getDocument()->getDocumentRDF(); PD_RDFModelHandle model = rdf; PD_RDFModelHandle ret(new RDFModel_XMLIDLimited( rdf, model, writeID, xmlids )); return ret; } PD_RDFModelHandle PD_DocumentRDF::createRestrictedModelForXMLIDs( const std::set< std::string >& xmlids ) { std::string writeID = ""; if( !xmlids.empty() ) writeID = *(xmlids.begin()); return createRestrictedModelForXMLIDs( writeID, xmlids ); } PD_RDFSemanticItems PD_DocumentRDF::getAllSemanticObjects( const std::string& classRestriction ) { PD_RDFSemanticItems ret; if( classRestriction.empty() || classRestriction == "Contact" ) { PD_RDFContacts contacts = getContacts(); copy( contacts.begin(), contacts.end(), back_inserter(ret)); } if( classRestriction.empty() || classRestriction == "Event" ) { PD_RDFEvents events = getEvents(); copy( events.begin(), events.end(), back_inserter(ret)); } if( classRestriction.empty() || classRestriction == "Location" ) { PD_RDFLocations locations = getLocations(); copy( locations.begin(), locations.end(), back_inserter(ret)); } return ret; } PD_RDFSemanticItems PD_DocumentRDF::getSemanticObjects( const std::set< std::string >& xmlids ) { PD_RDFSemanticItems ret; PD_RDFContacts contacts = getContacts(); for( PD_RDFContacts::iterator ci = contacts.begin(); ci != contacts.end(); ++ci ) { PD_RDFContactHandle c = *ci; std::set< std::string > clist = c->getXMLIDs(); std::set< std::string > tmp; std::set_intersection( xmlids.begin(), xmlids.end(), clist.begin(), clist.end(), inserter( tmp, tmp.end() )); if( !tmp.empty() ) { ret.push_back( c ); } } PD_RDFEvents events = getEvents(); for( PD_RDFEvents::iterator ci = events.begin(); ci != events.end(); ++ci ) { PD_RDFEventHandle c = *ci; std::set< std::string > clist = c->getXMLIDs(); std::set< std::string > tmp; std::set_intersection( xmlids.begin(), xmlids.end(), clist.begin(), clist.end(), inserter( tmp, tmp.end() )); if( !tmp.empty() ) { ret.push_back( c ); } } PD_RDFLocations locations = getLocations(); for( PD_RDFLocations::iterator ci = locations.begin(); ci != locations.end(); ++ci ) { PD_RDFLocationHandle c = *ci; std::set< std::string > clist = c->getXMLIDs(); std::set< std::string > tmp; std::set_intersection( xmlids.begin(), xmlids.end(), clist.begin(), clist.end(), inserter( tmp, tmp.end() )); if( !tmp.empty() ) { ret.push_back( c ); } } return ret; } void PD_DocumentRDF::selectXMLIDs( const std::set< std::string >& xmlids, FV_View* pView ) const { XAP_Frame* lff = XAP_App::getApp()->getLastFocussedFrame(); if( !pView && lff ) pView = static_cast( lff->getCurrentView() ); if( !pView ) return; for( std::set< std::string >::const_iterator iter = xmlids.begin(); iter != xmlids.end(); ++iter ) { const std::string& xmlid = *iter; std::pair< PT_DocPosition, PT_DocPosition > range = getIDRange( xmlid ); UT_DEBUGMSG(("selectXMLIDs() id:%s begin:%d end:%d\n", xmlid.c_str(), range.first, range.second )); if( range.first && range.second > range.first ) pView->selectRange( range ); } } void PD_DocumentRDF::showEditorWindow( const PD_RDFSemanticItems & cl ) { if( !cl.empty() ) { PD_RDFSemanticItems::const_iterator ci = cl.begin(); PD_RDFSemanticItemHandle c = *ci; c->showEditorWindow( cl ); } } PD_RDFContacts PD_DocumentRDF::getContacts( PD_RDFModelHandle alternateModel ) { PD_RDFModelHandle m = alternateModel; if( !m ) m = getDocument()->getDocumentRDF(); PD_RDFContacts ret; std::stringstream sparqlQuery; sparqlQuery << "prefix rdf: \n" << "prefix foaf: \n" << "prefix pkg: \n" << "select distinct ?person ?name ?nick ?email ?homepage ?img ?phone \n" << "where { \n" << " ?person rdf:type foaf:Person . \n" << " ?person foaf:name ?name \n" << " OPTIONAL { ?person foaf:phone ?phone } \n" << " OPTIONAL { ?person foaf:mbox ?email } \n" << " OPTIONAL { ?person foaf:nick ?nick } \n" << " OPTIONAL { ?person foaf:homepage ?homepage } \n" << " OPTIONAL { ?person foaf:img ?img } \n" << "}\n"; UT_DEBUGMSG(("getContacts() sparql:\n%s\n\n", sparqlQuery.str().c_str() )); PD_DocumentRDFHandle rdf = getDocument()->getDocumentRDF(); PD_RDFQuery q( rdf, m ); PD_ResultBindings_t bindings = q.executeQuery( sparqlQuery.str() ); UT_DEBUGMSG(("getContacts() bindings.sz:%lu\n", (long unsigned)bindings.size() )); // uniqfilter is needed because redland might not honour the // DISTINCT sparql keyword std::set uniqfilter; for( PD_ResultBindings_t::iterator it = bindings.begin(); it != bindings.end(); ++it ) { std::string n = (*it)["name"]; if (uniqfilter.count(n)) continue; uniqfilter.insert(n); PD_RDFContact* newItem = PD_DocumentRDF::getSemanticItemFactory()->createContact( rdf, it ); PD_RDFContactHandle h( newItem ); ret.push_back( h ); } return ret; } PD_RDFEvents PD_DocumentRDF::getEvents( PD_RDFModelHandle alternateModel ) { PD_RDFModelHandle m = alternateModel; if( !m ) m = getDocument()->getDocumentRDF(); PD_RDFEvents ret; std::stringstream sparqlQuery; sparqlQuery << " prefix rdf: \n" << " prefix foaf: \n" << " prefix cal: \n" << " select distinct ?ev ?uid ?dtstart ?dtend ?summary ?location ?description ?geo ?long ?lat \n" << " where { \n" << " ?ev rdf:type cal:Vevent . \n" << " ?ev cal:uid ?uid . \n" << " ?ev cal:dtstart ?dtstart . \n" << " ?ev cal:dtend ?dtend \n" << " OPTIONAL { ?ev cal:summary ?summary } \n" << " OPTIONAL { ?ev cal:location ?location } \n" << " OPTIONAL { ?ev cal:description ?description } \n" << " OPTIONAL { \n" << " ?ev cal:geo ?geo . \n" << " ?geo rdf:first ?lat . \n" << " ?geo rdf:rest ?joiner . \n" << " ?joiner rdf:first ?long \n" << " } \n" << " } \n"; UT_DEBUGMSG(("getEvents() sparql:\n%s\n\n", sparqlQuery.str().c_str() )); PD_DocumentRDFHandle rdf = getDocument()->getDocumentRDF(); PD_RDFQuery q( rdf, m ); PD_ResultBindings_t bindings = q.executeQuery( sparqlQuery.str() ); UT_DEBUGMSG(("getEvents() bindings.sz:%lu\n", (long unsigned)bindings.size() )); // uniqfilter is needed because redland might not honour the // DISTINCT sparql keyword std::set uniqfilter; for( PD_ResultBindings_t::iterator it = bindings.begin(); it != bindings.end(); ++it ) { std::string n = (*it)["uid"]; if (uniqfilter.count(n)) continue; uniqfilter.insert(n); PD_RDFEvent* newItem = PD_DocumentRDF::getSemanticItemFactory()->createEvent( rdf, it ); PD_RDFEventHandle h( newItem ); ret.push_back( h ); } return ret; } PD_RDFLocations& PD_DocumentRDF::addLocations( PD_RDFLocations& ret, bool isGeo84, const std::string sparql, PD_RDFModelHandle /*alternateModel*/ ) { PD_DocumentRDFHandle rdf = getDocument()->getDocumentRDF(); PD_RDFQuery q( rdf, rdf ); PD_ResultBindings_t bindings = q.executeQuery( sparql ); UT_DEBUGMSG(("addLocations() bindings.sz:%lu sparql\n%s\n", (long unsigned)bindings.size(), sparql.c_str() )); std::set uniqfilter; for( PD_ResultBindings_t::iterator it = bindings.begin(); it != bindings.end(); ++it ) { std::string n = (*it)["lat"]; if (uniqfilter.count(n)) continue; uniqfilter.insert(n); UT_DEBUGMSG(("addLocations() n:%s\n", n.c_str() )); #ifdef WITH_CHAMPLAIN PD_RDFLocation* newItem = PD_DocumentRDF::getSemanticItemFactory()->createLocation( rdf, it, isGeo84 ); PD_RDFLocationHandle h( newItem ); ret.push_back( h ); #else UT_UNUSED( isGeo84 ); #endif } return ret; } PD_RDFLocations PD_DocumentRDF::getLocations( PD_RDFModelHandle alternateModel ) { PD_RDFLocations ret; addLocations( ret, false, " prefix rdf: \n" " prefix foaf: \n" " prefix dc: \n" " prefix cal: \n" " select distinct ?geo ?long ?lat ?joiner ?desc \n" " where { \n" " ?ev cal:geo ?geo . \n" " ?geo rdf:first ?lat . \n" " ?geo rdf:rest ?joiner . \n" " ?joiner rdf:first ?long \n" " OPTIONAL { ?geo dc:title ?desc } \n" " } \n", alternateModel ); UT_DEBUGMSG(( "getLocations(1) ret.size:%lu\n", (long unsigned)ret.size() )); addLocations( ret, true, " prefix rdf: \n" " prefix dc: \n" " prefix foaf: \n" " prefix geo84: \n" " \n" " select distinct ?geo ?long ?lat ?type ?desc \n" " where { \n" " \n" " ?geo geo84:lat ?lat . \n" " ?geo geo84:long ?long \n" " OPTIONAL { ?geo rdf:type ?type } \n" " OPTIONAL { ?geo dc:title ?desc } \n" " \n" " } \n", alternateModel ); UT_DEBUGMSG(( "getLocations(2) ret.size:%lu\n", (long unsigned)ret.size() )); return ret; } /****************************************/ /****************************************/ /****************************************/ /****************************************/ /****************************************/ /****************************************/ PD_DocumentRDFMutation::PD_DocumentRDFMutation( PD_DocumentRDF* rdf ) : m_rdf(rdf) , m_rolledback(false) , m_committed(false) , m_handlingAbiCollabNotification( false ) , m_pAP( 0 ) { m_pAP = m_rdf->getAP()->cloneWithReplacements( 0, 0, false ); m_crRemoveAP = new PP_AttrProp(); m_crAddAP = new PP_AttrProp(); UT_DEBUGMSG(("PD_DocumentRDF::ctor() this:%p rdf:%p\n", this, m_rdf)); } PD_DocumentRDFMutation::~PD_DocumentRDFMutation() { if( !m_committed ) commit(); if(m_pAP) delete m_pAP; if(m_crRemoveAP) delete m_crRemoveAP; if(m_crAddAP) delete m_crAddAP; } bool PD_DocumentRDFMutation::apAdd( PP_AttrProp* AP, const PD_URI& s, const PD_URI& p, const PD_Object& o ) { POCol l; const gchar* szName = s.toString().c_str(); const gchar* szValue = 0; if( AP->getProperty( szName, szValue) ) { l = decodePOCol(szValue); } // don't do this... it doesn't allow a (s,p) to have multiple objects at a global scale. // for( POCol::iterator iter = l.find( p ); iter != l.end(); iter = l.find( p ) ) // { // l.erase( iter ); // } l.insert( std::make_pair( p, o )); std::string po = encodePOCol(l); return AP->setProperty( szName, po.c_str() ); } void PD_DocumentRDFMutation::apRemove( PP_AttrProp*& AP, const PD_URI& s, const PD_URI& p, const PD_Object& o ) { PP_AttrProp* newAP = new PP_AttrProp(); size_t propCount = AP->getPropertyCount(); for( size_t i = 0; igetNthProperty( i, szName, szValue)) { // failed to get old prop continue; } if( s.toString() == szName ) { // drop this triple... POCol l = decodePOCol(szValue); std::pair< POCol::iterator, POCol::iterator > range = std::equal_range( l.begin(), l.end(), p ); for( POCol::iterator iter = range.first; iter != range.second; ) { if( iter->first == p && iter->second == o ) { POCol::iterator t = iter; ++iter; l.erase(t); continue; } ++iter; } std::string po = encodePOCol(l); // commit() calls prune first, so this property // will disappear from the AP if it's list is empty if(l.empty()) po = ""; if( !newAP->setProperty( szName, po.c_str() )) { // FIXME: failed to copy prop } continue; } if( !newAP->setProperty( szName, szValue )) { // FIXME: failed to copy prop } } std::swap( AP, newAP ); delete newAP; } bool PD_DocumentRDFMutation::add( const PD_URI& s, const PD_URI& p, const PD_Object& o ) { UT_DEBUGMSG(("PD_DocumentRDFMutation::add(1) s:%s o:%s ot:%d\n", s.toString().c_str(), o.toString().c_str(), o.getObjectType() )); // If it already exists and was not removed // then you can't add it again if( m_rdf->contains( s, p, o ) && !m_rdf->apContains( m_crRemoveAP, s, p, o )) return true; // If this mutation has added it but not already committed that addition // to the document then do not add it again either if( m_rdf->apContains( m_crAddAP, s, p, o ) && !m_rdf->apContains( m_crRemoveAP, s, p, o )) return true; UT_DEBUGMSG(("PD_DocumentRDFMutation::add(2) s:%s o:%s\n", s.toString().c_str(), o.toString().c_str() )); apAdd( m_pAP, s, p, o ); apAdd( m_crAddAP, s, p, o ); return true; } bool PD_DocumentRDFMutation::add( const PD_URI& s, const PD_URI& p, const PD_Object& o, const PD_URI& /*context*/ ) { return add( s, p, o ); } void PD_DocumentRDFMutation::remove( const PD_URI& s, const PD_URI& p, const PD_Object& o ) { UT_DEBUGMSG(("PD_DocumentRDFMutation::remove(1) s:%s p:%s o:%s ot:%d\n", s.toString().c_str(), p.c_str(), o.toString().c_str(), o.getObjectType() )); apRemove( m_pAP, s, p, o ); apRemove( m_crAddAP, s, p, o ); apAdd( m_crRemoveAP, s, p, o ); } void PD_DocumentRDFMutation::remove( const PD_URI& s, const PD_URI& p, const PD_URI& o ) { remove( s, p, PD_Object( o.toString() )); } bool PD_DocumentRDFMutation::add( const PD_RDFStatement& st ) { return add( st.getSubject(), st.getPredicate(), st.getObject() ); } PD_URI PD_DocumentRDFMutation::createBNode() { PD_Document* doc = m_rdf->getDocument(); std::stringstream ss; ss << "uri:bnode" << doc->getUID( UT_UniqueId::Annotation ); return PD_URI( ss.str() ); } void PD_DocumentRDFMutation::remove( const PD_RDFStatement& st ) { remove( st.getSubject(), st.getPredicate(), st.getObject() ); } void PD_DocumentRDFMutation::remove( const std::list< PD_RDFStatement >& sl ) { for( std::list< PD_RDFStatement >::const_iterator si = sl.begin(); si!=sl.end(); ++si ) { remove( *si ); } } void PD_DocumentRDFMutation::remove( const PD_URI& s, const PD_URI& p ) { PD_ObjectList objects = m_rdf->getObjects( s, p ); std::list< PD_RDFStatement > removeList; for( PD_ObjectList::iterator it = objects.begin(); it != objects.end(); ++it ) { PD_Object obj = *it; PD_RDFStatement st( s, p, obj ); removeList.push_back( st ); } remove( removeList ); } int PD_DocumentRDFMutation::add( PD_RDFModelHandle model ) { int count = 0; PD_RDFModelIterator iter = model->begin(); PD_RDFModelIterator e = model->end(); for( ; iter != e; ++iter ) { const PD_RDFStatement& st = *iter; UT_DEBUGMSG(("PD_DocumentRDFMutation::add(submodel) ot:%d o:%s\n", st.getObject().getObjectType(), st.getObject().toString().c_str() )); if( add( st ) ) ++count; } return count; } void PD_DocumentRDFMutation::handleCollabEvent( gchar** szAtts, gchar** szProps ) { UT_DEBUGMSG(("PD_DocumentRDFMutation::handleCollabEvent (remote) rdf:%p\n", m_rdf)); m_handlingAbiCollabNotification = true; PP_AttrProp* addAP = new PP_AttrProp(); PP_AttrProp* removeAP = new PP_AttrProp(); addAP->setProperties( (const gchar**)szAtts ); removeAP->setProperties( (const gchar**)szProps ); handleAddAndRemove( addAP, removeAP ); delete addAP; delete removeAP; } /** * This is where the triples in @add and @remove will actually modify * the DocumentRDF. This method is called by commit() locally and by * handleCollabEvent to handle remote change notificatioans during * collaborative sessions. * * First the current AttrProp is copied from the DocumentRDF, * filtering out the triples from the remove table as the copy is * performed. Then the new triples are added and the * piecetable/documentRDF is updated to use the new RDF APIndex. */ UT_Error PD_DocumentRDFMutation::handleAddAndRemove( PP_AttrProp* add_, PP_AttrProp* remove_ ) { // UT_DEBUGMSG(("PD_DocumentRDFMutation::handleAddAndRemove (general) rdf:%p\n", m_rdf)); // m_rdf->apDumpModel( remove_, "remove from model" ); // m_rdf->apDumpModel( add_, "add to model" ); /* * remove all the triples we don't want first * doing this set wise should great less junk AP instances. */ const PP_AttrProp* existingAP = m_rdf->getAP(); PP_AttrProp* newAP = new PP_AttrProp(); size_t propCount = existingAP->getPropertyCount(); for( size_t i = 0; igetNthProperty( i, szExistingName, szExistingValue)) { UT_DEBUGMSG(("PD_DocumentRDFMutation::handleAddAndRemove() failed to get prop:%ld\n", (long)i )); // failed to get old prop continue; } const gchar* szPropertiesToRemove = 0; if( remove_->getProperty( szExistingName, szPropertiesToRemove )) { POCol existingProps = decodePOCol(szExistingValue); POCol removeProps = decodePOCol(szPropertiesToRemove); // UT_DEBUGMSG(("PD_DocumentRDFMutation::handleAddAndRemove(1) n:%s exist.sz:%d rem.sz:%d\n", // szExistingName, existingProps.size(), removeProps.size() )); for( POCol::iterator iter = removeProps.begin(); iter != removeProps.end(); ++iter ) { // UT_DEBUGMSG(("PD_DocumentRDFMutation::handleAddAndRemove(rem) %s\n", iter->first.c_str() )); std::pair< POCol::iterator, POCol::iterator > range = std::equal_range( existingProps.begin(), existingProps.end(), iter->first ); for( POCol::iterator t = range.first; t!=range.second; ) { if( t->second == iter->second ) { POCol::iterator target = t; t++; existingProps.erase( target ); continue; } t++; } } std::string po = encodePOCol(existingProps); // commit() calls prune first, so this property // will disappear from the AP if it's list is empty if(existingProps.empty()) po = ""; // UT_DEBUGMSG(("PD_DocumentRDFMutation::handleAddAndRemove(2) n:%s exist.sz:%d rem.sz:%d\n", // szExistingName, existingProps.size(), removeProps.size() )); if( !newAP->setProperty( szExistingName, po.c_str() )) { UT_DEBUGMSG(("PD_DocumentRDFMutation::handleAddAndRemove() failed to set prop:%ld\n", (long)i )); // FIXME: failed to copy prop } } else { UT_DEBUGMSG(("PD_DocumentRDFMutation::handleAddAndRemove() copy prop:%s\n", szExistingName )); if( !newAP->setProperty( szExistingName, szExistingValue )) { // FIXME: failed to copy prop } } } // m_rdf->apDumpModel( newAP, "model after remove..." ); // add all the new triples propCount = add_->getPropertyCount(); for( size_t i = 0; igetNthProperty( i, szName, szValue)) { // FIXME: failed to get old prop continue; } PD_URI s(szName); POCol c = decodePOCol(szValue); for( POCol::iterator iter = c.begin(); iter != c.end(); ++iter ) { apAdd( newAP, s, iter->first, iter->second ); } } // m_rdf->apDumpModel( newAP, "updated RDF model..." ); UT_Error e = m_rdf->setAP( newAP ); if( e != UT_OK ) { UT_DEBUGMSG(("DocumentRDFMutation::handleAddAndRemove() failed to add new AttrPropIndex for RDF update\n")); // MIQ 2010 July: addIfUniqueAP() method states false == memory error of some kind. return e; } // m_rdf->apDumpModel( m_rdf->getAP(), "updated RDF model..." ); return UT_OK; } /** * Commit the add() and remove() changes to the main document RDF. * This method also emits a change record detailing the update. * * Implementation: Note that at this stage we have m_crRemoveAP and * m_crAddAP which are the tripes to remove and add respectively. * These are also the triples that will be sent via abicollab to other * instances to add/remove so we might as well try to use the same * code to handle the mutation in both this and other abiword * instances. * * Note that you can only commit() once per PD_DocumentRDFMutation object. * So you should throw it away after a commit to avoid the temptation of * trying to add() more to it. */ UT_Error PD_DocumentRDFMutation::commit() { bool success = false; UT_DEBUGMSG(("PD_DocumentRDF::commit(top1) this:%p rdf:%p\n", this, m_rdf)); // UT_DEBUGMSG(("PD_DocumentRDF::commit(top2) m_rolledback:%d\n", m_rolledback)); // UT_DEBUGMSG(("PD_DocumentRDF::commit(top3) rm.hasP:%d add.hasP:%d\n", // m_crRemoveAP->hasProperties(), m_crAddAP->hasProperties())); // if( m_crAddAP->hasProperties() ) // { // UT_DEBUGMSG(("PD_DocumentRDF::commit(top3) add count:%d\n", // (int)m_crAddAP->getPropertyCount())); // } // m_rdf->apDumpModel( m_crAddAP, "xx add to model" ); if(m_rolledback) return UT_OK; if( !m_crRemoveAP->hasProperties() && !m_crAddAP->hasProperties() ) return UT_OK; if( m_handlingAbiCollabNotification ) return UT_OK; if( m_committed ) return UT_OK; UT_DEBUGMSG(("PD_DocumentRDF::commit(running) rdf:%p\n", m_rdf)); m_pAP->prune(); m_pAP->markReadOnly(); PD_Document* doc = m_rdf->getDocument(); pt_PieceTable* pt = m_rdf->getPieceTable(); pt_VarSet& m_varset = pt->getVarSet(); handleAddAndRemove( m_crAddAP, m_crRemoveAP ); // UT_DEBUGMSG(("PD_DocumentRDF::commit(sending CR) rdf:%p\n", m_rdf)); if( !m_rdf->isStandAlone() ) { // // Notify others about this change... // PP_AttrProp* crAP = new PP_AttrProp(); crAP->setAttributes( m_crAddAP->getProperties() ); crAP->setProperties( m_crRemoveAP->getProperties() ); crAP->markReadOnly(); PT_AttrPropIndex crAPI = 0; success = m_varset.addIfUniqueAP( crAP, &crAPI ); // addIfUniqueAP() eats it crAP = 0; if( !success ) { UT_DEBUGMSG(("DocumentRDFMutation::commit() failed to add new AttrPropIndex for RDF update\n")); // MIQ 2010 July: addIfUniqueAP() method states false == memory error of some kind. return UT_OUTOFMEM; } PT_DocPosition pos = 0; UT_uint32 iXID = 0; PX_ChangeRecord* pcr = new PX_ChangeRecord( PX_ChangeRecord::PXT_ChangeDocRDF, pos, crAPI, iXID ); doc->notifyListeners( 0, pcr ); delete pcr; // UT_DEBUGMSG(("PD_DocumentRDF::commit(done) rdf:%p\n", m_rdf)); } m_committed = true; m_rdf->maybeSetDocumentDirty(); m_rdf->updateHaveSemItemsCache(); return UT_OK; } /** * Forget the changes and do not automatically try to commit() them * when the PD_DocumentRDFMutation goes out of scope. */ void PD_DocumentRDFMutation::rollback() { m_rolledback = true; }