@seeSwDoc::GetXmlIdRegistry @seeSwDocShell::GetXmlIdRegistry
*/ class XmlIdRegistry : public sfx2::IXmlIdRegistry
{
public:
XmlIdRegistry();
/** get the ODF element with the given metadata reference. */ virtual css::uno::Reference< css::rdf::XMetadatable >
GetElementByMetadataReference( const css::beans::StringPair & i_rReference) const
override;
/** register an ODF element at a newly generated, unique metadata reference.
/** register i_rCopy as a copy of i_rSource,
with precedence iff i_bCopyPrecedesSource is true */ void RegisterCopy(Metadatable const& i_rSource, Metadatable & i_rCopy, constbool i_bCopyPrecedesSource);
/** create a Undo Metadatable for i_rObject. */ static std::shared_ptr<MetadatableUndo> CreateUndo(
Metadatable const& i_rObject);
/** merge i_rMerged and i_rOther into i_rMerged. */ void JoinMetadatables(Metadatable & i_rMerged, Metadatable const& i_rOther);
/** the horrible Undo Metadatable: is inserted into lists to track position */ class MetadatableUndo : public Metadatable
{ /// as determined by the stream of the source in original document constbool m_isInContent; public: explicit MetadatableUndo(constbool i_isInContent)
: m_isInContent(i_isInContent) { } virtual ::sfx2::XmlIdRegistry& GetRegistry() override
{ // N.B. for Undo, m_pReg is initialized by registering this as copy in // CreateUndo; it is never cleared
OSL_ENSURE(m_pReg, "no m_pReg in MetadatableUndo ?"); return *m_pReg;
} virtualbool IsInClipboard() const override { returnfalse; } virtualbool IsInUndo() const override { returntrue; } virtualbool IsInContent() const override { return m_isInContent; } virtual css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override
{ OSL_FAIL("MetadatableUndo::MakeUnoObject"); throw; }
};
/** the horrible Clipboard Metadatable: inserted into lists to track position */ class MetadatableClipboard : public Metadatable
{ /// as determined by the stream of the source in original document constbool m_isInContent; public: explicit MetadatableClipboard(constbool i_isInContent)
: m_isInContent(i_isInContent) { } virtual ::sfx2::XmlIdRegistry& GetRegistry() override
{ // N.B. for Clipboard, m_pReg is initialized by registering this as copy in // RegisterAsCopyOf; it is only cleared by OriginNoLongerInBusinessAnymore
assert(m_pReg && "no m_pReg in MetadatableClipboard ?"); return *m_pReg;
} virtualbool IsInClipboard() const override { returntrue; } virtualbool IsInUndo() const override { returnfalse; } virtualbool IsInContent() const override { return m_isInContent; } virtual css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override
{ OSL_FAIL("MetadatableClipboard::MakeUnoObject"); throw; } void OriginNoLongerInBusinessAnymore() { m_pReg = nullptr; }
};
XmlIdVector_t * pList( LookupElementVector(i_rStreamName, i_rIdref) ); if (pList)
{ if (pList->empty())
{
pList->push_back( &i_rObject ); returntrue;
} else
{ // this is only called from TryRegister now, so check // if all elements in the list are deleted (in undo) or // placeholders, then "steal" the id from them if ( std::none_of(pList->begin(), pList->end(),
[](Metadatable* item)->bool { return !(item->IsInUndo() || item->IsInClipboard());
} ) )
{
pList->insert(pList->begin(), &i_rObject ); returntrue;
} else
{ returnfalse;
}
}
} else
{
m_XmlIdMap.insert(::std::make_pair(i_rIdref, bContent
? ::std::make_pair( XmlIdVector_t( 1, &i_rObject ), XmlIdVector_t() )
: ::std::make_pair( XmlIdVector_t(), XmlIdVector_t( 1, &i_rObject ) ))); returntrue;
}
}
// Document XML ID Registry
XmlIdRegistryDocument::XmlIdRegistryDocument()
: m_pImpl( new XmlIdRegistry_Impl )
{
}
staticvoid
removeLink(Metadatable* i_pObject)
{
OSL_ENSURE(i_pObject, "null in list ???"); if (!i_pObject) return; if (i_pObject->IsInClipboard())
{
MetadatableClipboard* pLink( dynamic_cast<MetadatableClipboard*>( i_pObject ) );
OSL_ENSURE(pLink, "IsInClipboard, but no MetadatableClipboard ?"); if (pLink)
{
pLink->OriginNoLongerInBusinessAnymore();
}
}
}
XmlIdRegistryDocument::~XmlIdRegistryDocument()
{ // notify all list elements that are actually in the clipboard for (constauto& aXmlId : m_pImpl->m_XmlIdMap) { for (auto aLink : aXmlId.second.first)
removeLink(aLink); for (auto aLink : aXmlId.second.second)
removeLink(aLink);
}
}
OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), "TryRegisterMetadatable called for MetadatableUndo?");
OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), "TryRegisterMetadatable called for MetadatableClipboard?");
OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), "RegisterMetadatableAndCreateID called for MetadatableUndo?");
OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), "RegisterMetadatableAndCreateID called for MetadatableClipboard?");
constbool isInContent( i_rObject.IsInContent() ); const OUString stream(
isInContent ? s_content : s_styles ); // check if we have a latent xmlid, and if yes, remove it
OUString old_path;
OUString old_idref;
m_pImpl->LookupXmlId(i_rObject, old_path, old_idref);
XmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() ); if (!old_idref.isEmpty())
{
old_id = m_pImpl->m_XmlIdMap.find(old_idref);
OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found"); if (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject)
{ return;
} else
{ // remove latent xmlid
rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject);
}
}
// create id const OUString id( create_id(m_pImpl->m_XmlIdMap) );
OSL_ENSURE(m_pImpl->m_XmlIdMap.find(id) == m_pImpl->m_XmlIdMap.end(), "created id is in use");
m_pImpl->m_XmlIdMap.insert(::std::make_pair(id, isInContent
? ::std::make_pair( XmlIdVector_t( 1, &i_rObject ), XmlIdVector_t() )
: ::std::make_pair( XmlIdVector_t(), XmlIdVector_t( 1, &i_rObject ) )));
m_pImpl->m_XmlIdReverseMap[&i_rObject] = ::std::make_pair(stream, id);
}
// potential sources: clipboard, undo array, splitNode // assumption: stream change can only happen via clipboard, and is handled // by Metadatable::RegisterAsCopyOf
OSL_ENSURE(i_rSource.IsInUndo() || i_rCopy.IsInUndo() ||
(i_rSource.IsInContent() == i_rCopy.IsInContent()), "RegisterCopy: not in same stream?");
OUString path;
OUString idref; if (!m_pImpl->LookupXmlId( i_rSource, path, idref ))
{
OSL_FAIL("no xml id?"); return;
}
XmlIdVector_t * pList ( m_pImpl->LookupElementVector(path, idref) );
OSL_ENSURE( ::std::find( pList->begin(), pList->end(), &i_rCopy )
== pList->end(), "copy already registered???");
XmlIdVector_t::iterator srcpos(
::std::find( pList->begin(), pList->end(), &i_rSource ) );
OSL_ENSURE(srcpos != pList->end(), "source not in list???"); if (srcpos == pList->end())
{ return;
} if (i_bCopyPrecedesSource)
{
pList->insert( srcpos, &i_rCopy );
} else
{ // for undo push_back does not work! must insert right after source
pList->insert( ++srcpos, &i_rCopy );
}
m_pImpl->m_XmlIdReverseMap.insert(::std::make_pair(&i_rCopy,
::std::make_pair(path, idref)));
}
bool mergedOwnsRef;
OUString path;
OUString idref; if (m_pImpl->LookupXmlId(i_rMerged, path, idref))
{
mergedOwnsRef = (m_pImpl->LookupElement(path, idref) == &i_rMerged);
} else
{
OSL_FAIL("JoinMetadatables: no xmlid?"); return;
} if (!mergedOwnsRef)
{
i_rMerged.RemoveMetadataReference();
i_rMerged.RegisterAsCopyOf(i_rOther, true); return;
} // other cases: merged has actual ref and is nonempty, // other has latent/actual ref and is nonempty: other loses => nothing to do
}
// Clipboard XML ID Registry (_Impl)
namespace {
struct RMapEntry
{
RMapEntry() {}
RMapEntry(OUString i_aStream,
OUString i_aXmlId,
std::shared_ptr<MetadatableClipboard> i_pLink
= std::shared_ptr<MetadatableClipboard>())
: m_Stream(std::move(i_aStream)), m_XmlId(std::move(i_aXmlId)), m_xLink(std::move(i_pLink))
{}
OUString m_Stream;
OUString m_XmlId; // this would have been an auto_ptr, if only that would have compiled...
std::shared_ptr<MetadatableClipboard> m_xLink;
};
OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), "TryRegisterMetadatable called for MetadatableUndo?");
OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), "TryRegisterMetadatable called for MetadatableClipboard?");
OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), "RegisterMetadatableAndCreateID called for MetadatableUndo?");
OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), "RegisterMetadatableAndCreateID called for MetadatableClipboard?");
// create id const OUString id( create_id(m_pImpl->m_XmlIdMap) );
OSL_ENSURE(m_pImpl->m_XmlIdMap.find(id) == m_pImpl->m_XmlIdMap.end(), "created id is in use");
m_pImpl->m_XmlIdMap.insert(::std::make_pair(id, isInContent
? ::std::make_pair( &i_rObject, static_cast<Metadatable*>(nullptr) )
: ::std::make_pair( static_cast<Metadatable*>(nullptr), &i_rObject ))); // N.B.: if i_rObject had a latent XmlId, then we implicitly delete the // MetadatableClipboard and thus the latent XmlId here
m_pImpl->m_XmlIdReverseMap[&i_rObject] = RMapEntry(stream, id);
}
// N.B.: when copying to the clipboard, the selection is always inserted // into the body, even if the source is a header/footer! // so we do not check whether the stream is right in this function
if (!isValidXmlId(i_rReference.First, i_rReference.Second))
{ throw lang::IllegalArgumentException(u"illegal XmlId"_ustr, nullptr, 0);
}
if (!i_isLatent)
{ // this should succeed assuming clipboard has a single source document constbool success( m_pImpl->TryInsertMetadatable(i_rCopy,
i_rReference.First, i_rReference.Second) );
OSL_ENSURE(success, "RegisterCopyClipboard: TryInsert failed?");
} const std::shared_ptr<MetadatableClipboard> xLink(
CreateClipboard( isContentFile(i_rReference.First)) );
m_pImpl->m_XmlIdReverseMap.insert(::std::make_pair(&i_rCopy,
RMapEntry(i_rReference.First, i_rReference.Second, xLink))); return *xLink;
}
void
Metadatable::RegisterAsCopyOf(Metadatable const & i_rSource, constbool i_bCopyPrecedesSource)
{
OSL_ENSURE(typeid(*this) == typeid(i_rSource)
|| typeid(i_rSource) == typeid(MetadatableUndo)
|| typeid(*this) == typeid(MetadatableUndo)
|| typeid(i_rSource) == typeid(MetadatableClipboard)
|| typeid(*this) == typeid(MetadatableClipboard), "RegisterAsCopyOf element with different class?");
OSL_ENSURE(!m_pReg, "RegisterAsCopyOf called on element with XmlId?");
if (m_pReg)
{
RemoveMetadataReference();
}
try
{ if (i_rSource.m_pReg)
{
XmlIdRegistry & rReg( dynamic_cast<XmlIdRegistry&>( GetRegistry() ) ); if (i_rSource.m_pReg == &rReg)
{
OSL_ENSURE(!IsInClipboard(), "RegisterAsCopy: both in clipboard?"); if (!IsInClipboard())
{
XmlIdRegistryDocument & rRegDoc( dynamic_cast<XmlIdRegistryDocument&>( rReg ) );
rRegDoc.RegisterCopy(i_rSource, *this,
i_bCopyPrecedesSource);
m_pReg = &rRegDoc;
} return;
} // source is in different document
XmlIdRegistryDocument * pRegDoc( dynamic_cast<XmlIdRegistryDocument *>(&rReg) );
XmlIdRegistryClipboard * pRegClp( dynamic_cast<XmlIdRegistryClipboard*>(&rReg) );
if (pRegClp)
{
beans::StringPair SourceRef(
i_rSource.m_pReg->GetXmlIdForElement(i_rSource) ); bool isLatent( SourceRef.Second.isEmpty() );
XmlIdRegistryDocument * pSourceRegDoc( dynamic_cast<XmlIdRegistryDocument*>(i_rSource.m_pReg) );
OSL_ENSURE(pSourceRegDoc, "RegisterAsCopyOf: 2 clipboards?"); if (!pSourceRegDoc) return; // this is a copy _to_ the clipboard if (isLatent)
{
pSourceRegDoc->LookupXmlId(i_rSource,
SourceRef.First, SourceRef.Second);
}
Metadatable & rLink(
pRegClp->RegisterCopyClipboard(*this, SourceRef, isLatent));
m_pReg = pRegClp; // register as copy in the non-clipboard registry
pSourceRegDoc->RegisterCopy(i_rSource, rLink, false); // i_bCopyPrecedesSource);
rLink.m_pReg = pSourceRegDoc;
} elseif (pRegDoc)
{
XmlIdRegistryClipboard * pSourceRegClp( dynamic_cast<XmlIdRegistryClipboard*>(i_rSource.m_pReg) );
OSL_ENSURE(pSourceRegClp, "RegisterAsCopyOf: 2 non-clipboards?"); if (!pSourceRegClp) return; const MetadatableClipboard * pLink(
pSourceRegClp->SourceLink(i_rSource) ); // may happen if src got its id via UNO call if (!pLink) return; // only register copy if clipboard content is from this SwDoc! if (&GetRegistryConst(*pLink) == pRegDoc)
{ // this is a copy _from_ the clipboard; check if the // element is still in the same stream // N.B.: we check the stream of pLink, not of i_rSource! bool srcInContent( pLink->IsInContent() ); bool tgtInContent( IsInContent() ); if (srcInContent == tgtInContent)
{
pRegDoc->RegisterCopy(*pLink, *this, true); // i_bCopyPrecedesSource);
m_pReg = pRegDoc;
} // otherwise: stream change! do not register!
}
} else
{
OSL_FAIL("neither RegDoc nor RegClp cannot happen");
}
}
} catch (const uno::Exception &)
{
TOOLS_WARN_EXCEPTION( "sfx.doc", "Metadatable::RegisterAsCopyOf");
}
}
std::shared_ptr<MetadatableUndo> Metadatable::CreateUndo() const
{
OSL_ENSURE(!IsInUndo(), "CreateUndo called for object in undo?");
OSL_ENSURE(!IsInClipboard(), "CreateUndo called for object in clipboard?"); try
{ if (!IsInClipboard() && !IsInUndo() && m_pReg)
{
XmlIdRegistryDocument * pRegDoc( dynamic_cast<XmlIdRegistryDocument*>( m_pReg ) );
assert(pRegDoc);
std::shared_ptr<MetadatableUndo> xUndo(
sfx2::XmlIdRegistryDocument::CreateUndo(*this) );
pRegDoc->RegisterCopy(*this, *xUndo, false);
xUndo->m_pReg = pRegDoc; return xUndo;
}
} catch (const uno::Exception &)
{
TOOLS_WARN_EXCEPTION( "sfx.doc", "Metadatable::CreateUndo");
} return std::shared_ptr<MetadatableUndo>();
}
void Metadatable::RestoreMetadata(
std::shared_ptr<MetadatableUndo> const& i_pUndo)
{
OSL_ENSURE(!IsInUndo(), "RestoreMetadata called for object in undo?");
OSL_ENSURE(!IsInClipboard(), "RestoreMetadata called for object in clipboard?"); if (IsInClipboard() || IsInUndo()) return;
RemoveMetadataReference(); if (i_pUndo)
{
RegisterAsCopyOf(*i_pUndo, true);
}
}
void
Metadatable::JoinMetadatable(Metadatable const & i_rOther, constbool i_isMergedEmpty, constbool i_isOtherEmpty)
{
OSL_ENSURE(!IsInUndo(), "JoinMetadatables called for object in undo?");
OSL_ENSURE(!IsInClipboard(), "JoinMetadatables called for object in clipboard?"); if (IsInClipboard() || IsInUndo()) return;
if (i_isOtherEmpty && !i_isMergedEmpty)
{ // other is empty, thus loses => nothing to do return;
} if (i_isMergedEmpty && !i_isOtherEmpty)
{
RemoveMetadataReference();
RegisterAsCopyOf(i_rOther, true); return;
}
if (!i_rOther.m_pReg)
{ // other doesn't have xmlid, thus loses => nothing to do return;
} if (!m_pReg)
{
RegisterAsCopyOf(i_rOther, true); // assumption: i_rOther will be deleted, so don't unregister it here return;
} try
{
XmlIdRegistryDocument * pRegDoc( dynamic_cast<XmlIdRegistryDocument*>( m_pReg ) );
OSL_ENSURE(pRegDoc, "JoinMetadatable: no pRegDoc?"); if (pRegDoc)
{
pRegDoc->JoinMetadatables(*this, i_rOther);
}
} catch (const uno::Exception &)
{
TOOLS_WARN_EXCEPTION( "sfx.doc", "Metadatable::JoinMetadatable");
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.