class SwModify; class SwFormatChangeHint; class SwAttrSet; class SwCellFrame; class SwTabFrame; class SwRowFrame; class SwTable; class SwFindNearestNode;
namespace sw
{ class ClientIteratorBase; class ListenerEntry; class ObjectDyingHint; enumclass IteratorMode { Exact, UnwrapMulti };
}
template<typename TElementType, typename TSource, sw::IteratorMode eMode> class SwIterator;
namespace sw
{ void ClientNotifyAttrChg(SwModify& rModify, const SwAttrSet& aSet, SwAttrSet& aOld, SwAttrSet& aNew); struct SAL_DLLPUBLIC_RTTI LegacyModifyHint final: SfxHint
{
LegacyModifyHint(const SfxPoolItem* pOld, const SfxPoolItem* pNew) : SfxHint(SfxHintId::SwLegacyModify), m_pOld(pOld), m_pNew(pNew) {};
sal_uInt16 GetWhich() const { return m_pOld ? m_pOld->Which() : m_pNew ? m_pNew->Which() : 0; }; virtual ~LegacyModifyHint() override; const SfxPoolItem* m_pOld; const SfxPoolItem* m_pNew;
}; struct ModifyChangedHint final: SfxHint
{
ModifyChangedHint(const SwModify* pNew) : SfxHint(SfxHintId::SwModifyChanged), m_pNew(pNew) {}; const SwModify* m_pNew;
}; // Observer pattern using svl implementation // use this instead of SwClient/SwModify wherever possible // In writer layout, this might not always be possible, // but for listeners outside of it (e.g. unocore) this should be used. // The only "magic" signal this class issues is a ModifyChangedHint // proclaiming its death. It does NOT however provide a new SwModify for // listeners to switch to like the old SwModify/SwClient did, as that leads // to madness. class SW_DLLPUBLIC BroadcasterMixin {
SvtBroadcaster m_aNotifier; public:
BroadcasterMixin() = default;
BroadcasterMixin(BroadcasterMixin const &) = default;
BroadcasterMixin& operator=(const BroadcasterMixin&)
{ return *this; // Listeners are never copied or moved.
}
SvtBroadcaster& GetNotifier() { return m_aNotifier; }
}; /// refactoring out the same of the more sane SwClient functionality class SAL_DLLPUBLIC_RTTI WriterListener
{ friendclass ::SwModify; friendclass ::sw::ClientIteratorBase; private:
WriterListener* m_pLeft;
WriterListener* m_pRight; ///< double-linked list of other clients
WriterListener(WriterListener const&) = delete;
WriterListener& operator=(WriterListener const&) = delete; // Helpers for SwModify virtualvoid RegisterIn(SwModify*) { assert(false); }; // should only be called with a ClientBase<> protected:
WriterListener()
: m_pLeft(nullptr), m_pRight(nullptr)
{} virtual ~WriterListener() COVERITY_NOEXCEPT_FALSE {} virtualvoid SwClientNotify( const SwModify&, const SfxHint& rHint) =0; public: bool IsLast() const { return !m_pLeft && !m_pRight; } virtualconst SwCellFrame* DynCastCellFrame() const { return nullptr; } virtualconst SwTabFrame* DynCastTabFrame() const { return nullptr; } virtualconst SwRowFrame* DynCastRowFrame() const { return nullptr; } virtualconst SwTable* DynCastTable() const { return nullptr; } // get information about attribute virtualbool GetInfo( SwFindNearestNode& ) const { returntrue; }
};
template<typename T> class SW_DLLPUBLIC ClientBase : public ::sw::WriterListener
{ // avoids making the details of the linked list and the callback method public friendclass ::SwModify; friendclass sw::ClientIteratorBase; friendclass sw::ListenerEntry; template<typename E, typename S, sw::IteratorMode> friendclass ::SwIterator;
// write access to pRegisteredIn shall be granted only to the object itself (protected access)
T* GetRegisteredInNonConst() const { return m_pRegisteredIn; }
// when overriding this, you MUST call SwClient::SwClientNotify() in the override! virtualvoid SwClientNotify(const SwModify&, const SfxHint& rHint) override;
// in case an SwModify object is destroyed that itself is registered in another SwModify, // its SwClient objects can decide to get registered to the latter instead by calling this method
std::optional<sw::ModifyChangedHint> CheckRegistration( const sw::ObjectDyingHint& rHint );
// class has a doubly linked list for dependencies class SW_DLLPUBLIC SwModify: public SwClient
{ friendclass sw::ClientIteratorBase; friendvoid sw::ClientNotifyAttrChg(SwModify&, const SwAttrSet&, SwAttrSet&, SwAttrSet&); template<typename E, typename S, sw::IteratorMode> friendclass ::SwIterator;
sw::WriterListener* m_pWriterListeners; // the start of the linked list of clients bool m_bModifyLocked; // don't broadcast changes now
SwModify(SwModify const &) = delete;
SwModify &operator =(const SwModify&) = delete; void EnsureBroadcasting(); protected: virtualvoid SwClientNotify(const SwModify&, const SfxHint& rHint) override; // SwFormat wants to die different than the rest: It wants to reparent every client to its parent // and then send a SwFormatChg hint. void PrepareFormatDeath(const SwFormatChangeHint&); public:
SwModify()
: SwClient(), m_pWriterListeners(nullptr), m_bModifyLocked(false)
{}
// this class is part of the migration: it still forwards the "old" // SwModify events and announces them both to the old SwClients still // registered and also to the new SvtListeners. // Still: in the long run the SwClient/SwModify interface should not be // used anymore, in which case a BroadcasterMixin should be enough instead // then. class SW_DLLPUBLIC SAL_LOPLUGIN_ANNOTATE("crosscast") BroadcastingModify : public SwModify, public BroadcasterMixin
{ public: virtualvoid CallSwClientNotify(const SfxHint& rHint) const override;
}; // this should be hidden but sadly SwIterator template needs it... class ListenerEntry final : public SwClient
{ private: template<typename E, typename S, sw::IteratorMode> friendclass ::SwIterator;
SwClient *m_pToTell;
class SW_DLLPUBLIC WriterMultiListener final
{
SwClient& m_rToTell;
std::vector<ListenerEntry> m_vDepends; public:
WriterMultiListener(SwClient& rToTell);
WriterMultiListener& operator=(WriterMultiListener const&) = delete; // MSVC2015 workaround
WriterMultiListener(WriterMultiListener const&) = delete; // MSVC2015 workaround
~WriterMultiListener(); void StartListening(SwModify* pDepend); void EndListening(SwModify* pDepend); bool IsListeningTo(const SwModify* const pDepend) const; void EndListeningAll();
}; class ClientIteratorBase : public sw::Ring< ::sw::ClientIteratorBase >
{ friendclass ::SwModify; protected: const SwModify& m_rRoot; // the current object in an iteration
WriterListener* m_pCurrent; // in case the current object is already removed, the next object in the list // is marked down to become the current object in the next step // this is necessary because iteration requires access to members of the current object
WriterListener* m_pPosition; static SW_DLLPUBLIC ClientIteratorBase* s_pClientIters;
ClientIteratorBase( const SwModify& rModify )
: m_rRoot(rModify)
{
MoveTo(s_pClientIters); #ifdefined __GNUC__ && !defined __clang__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdangling-pointer" #endif
s_pClientIters = this; #ifdefined __GNUC__ && !defined __clang__ #pragma GCC diagnostic pop #endif
m_pCurrent = m_pPosition = m_rRoot.m_pWriterListeners;
}
WriterListener* GetLeftOfPos() { return m_pPosition->m_pLeft; }
WriterListener* GetRightOfPos() { return m_pPosition->m_pRight; }
WriterListener* GoStart()
{
m_pPosition = m_rRoot.m_pWriterListeners; if(m_pPosition) while( m_pPosition->m_pLeft )
m_pPosition = m_pPosition->m_pLeft;
m_pCurrent = m_pPosition; return m_pCurrent;
}
~ClientIteratorBase() override
{
assert(s_pClientIters); if(s_pClientIters == this)
s_pClientIters = unique() ? nullptr : GetNextInRing();
MoveTo(nullptr);
} // return "true" if an object was removed from a client chain in iteration // adding objects to a client chain in iteration is forbidden // SwModify::Add() asserts this bool IsChanged() const { return m_pPosition != m_pCurrent; } // ensures the iterator to point at a current client
WriterListener* Sync() { m_pCurrent = m_pPosition; return m_pCurrent; }
};
}
namespace sw::detail
{ // Dynamic casting can be expensive when used a lot, so for certain type combinations, // we have faster routines. template<typename CastDest> inlineconst CastDest * internal_dyn_cast(const sw::WriterListener * pSource)
{ returndynamic_cast<const CastDest *>(pSource);
} template<> inlineconst SwTable* internal_dyn_cast(const sw::WriterListener * pSource)
{ return pSource->DynCastTable();
} template<> inlineconst SwCellFrame* internal_dyn_cast(const sw::WriterListener * pSource)
{ return pSource->DynCastCellFrame();
} template<> inlineconst SwTabFrame* internal_dyn_cast(const sw::WriterListener * pSource)
{ return pSource->DynCastTabFrame();
} template<> inlineconst SwRowFrame* internal_dyn_cast(const sw::WriterListener * pSource)
{ return pSource->DynCastRowFrame();
}
} // namespace sw::detail
template<typename TElementType, typename TSource,
sw::IteratorMode eMode = sw::IteratorMode::Exact> class SwIterator final
: private sw::ClientIteratorBase
{ //static_assert(!std::is_base_of<SwPageDesc,TSource>::value, "SwPageDesc as TSource is deprecated.");
static_assert(std::is_base_of<SwClient,TElementType>::value, "TElementType needs to be derived from SwClient.");
static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify."); public:
SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
TElementType* First()
{
GoStart(); if(!m_pPosition) return nullptr;
m_pCurrent = nullptr; return Next();
}
TElementType* Next()
{ if(!IsChanged())
m_pPosition = GetRightOfPos();
sw::WriterListener *pCurrent(m_pPosition); while (m_pPosition)
{ if (eMode == sw::IteratorMode::UnwrapMulti)
{ if (autoconst pLE = dynamic_cast<sw::ListenerEntry const*>(m_pPosition))
{
pCurrent = pLE->m_pToTell;
}
} if (sw::detail::internal_dyn_cast<TElementType>(pCurrent) == nullptr)
{
m_pPosition = GetRightOfPos();
pCurrent = m_pPosition;
} else break;
}
Sync(); returnstatic_cast<TElementType*>(pCurrent);
} using sw::ClientIteratorBase::IsChanged;
};
template< typename T, typename TSource > class SwIterator<sw::ClientBase<T>, TSource> final : private sw::ClientIteratorBase
{
static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify"); public:
SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
sw::ClientBase<T>* First()
{ auto pListener = GoStart();
assert(dynamic_cast<sw::ClientBase<T>*>(pListener)); returnstatic_cast<sw::ClientBase<T>*>(pListener);
}
sw::ClientBase<T>* Next()
{ if(!IsChanged())
m_pPosition = GetRightOfPos(); auto pNext = Sync();
assert(dynamic_cast<sw::ClientBase<T>*>(pNext)); returnstatic_cast<sw::ClientBase<T>*>(pNext);
} using sw::ClientIteratorBase::IsChanged;
};
// deregister new client in case it is already registered elsewhere if( rDepend.GetRegisteredIn() != nullptr )
rDepend.m_pRegisteredIn->Remove(rDepend);
// update ClientIterators if(sw::ClientIteratorBase::s_pClientIters)
{ for(auto& rIter : sw::ClientIteratorBase::s_pClientIters->GetRingContainer())
{ if (&rIter.m_rRoot == this &&
(rIter.m_pCurrent == &rDepend || rIter.m_pPosition == &rDepend))
{ // if object being removed is the current or next object in an // iterator, advance this iterator
rIter.m_pPosition = pR;
}
}
}
rDepend.m_pLeft = nullptr;
rDepend.m_pRight = nullptr;
rDepend.m_pRegisteredIn = nullptr;
} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.11Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
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.