Use GetModuleHandleExW instead of GetModuleHandleW
[LibreOffice.git] / sw / inc / calbck.hxx
blob7d185d0537100c906e11866334884500ce4f9e5c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef INCLUDED_SW_INC_CALBCK_HXX
21 #define INCLUDED_SW_INC_CALBCK_HXX
23 #include <cassert>
25 #include <svl/hint.hxx>
26 #include <svl/broadcast.hxx>
27 #include <svl/poolitem.hxx>
28 #include "swdllapi.h"
29 #include "ring.hxx"
30 #include <type_traits>
31 #include <vector>
32 #include <memory>
33 #include <optional>
35 class SwModify;
36 class SwFormat;
37 class SfxPoolItem;
38 class SwAttrSet;
39 class SwCellFrame;
40 class SwTabFrame;
41 class SwRowFrame;
44 SwModify and SwClient cooperate in propagating attribute changes.
45 If an attribute changes, the change is notified to all dependent
46 formats and other interested objects, e.g. Nodes. The clients will detect
47 if the change affects them. It could be that the changed attribute is
48 overruled in the receiving object so that its change does not become
49 effective or that the receiver is not interested in the particular attribute
50 in general (though probably in other attributes of the SwModify object they
51 are registered in).
52 As SwModify objects are derived from SwClient, they can create a chain of SwClient
53 objects where changes can get propagated through.
54 Each SwClient can be registered at only one SwModify object, while each SwModify
55 object is connected to a list of SwClient objects. If an object derived from SwClient
56 wants to get notifications from more than one SwModify object, it must create additional
57 SwClient objects. The SwDepend class allows to handle their notifications in the same
58 notification callback as it forwards the Modify() calls it receives to a "master"
59 SwClient implementation.
60 The SwIterator class allows to iterate over the SwClient objects registered at an
61 SwModify. For historical reasons its ability to use TypeInfo to restrict this iteration
62 to objects of a particular type created a lot of code that misuses SwClient-SwModify
63 relationships that basically should be used only for Modify/Notify callbacks.
64 This is still subject to refactoring.
67 namespace sw
69 class ClientIteratorBase;
70 class ListenerEntry;
71 void ClientNotifyAttrChg(SwModify& rModify, const SwAttrSet& aSet, SwAttrSet& aOld, SwAttrSet& aNew);
72 struct SAL_DLLPUBLIC_RTTI LegacyModifyHint final: SfxHint
74 LegacyModifyHint(const SfxPoolItem* pOld, const SfxPoolItem* pNew) : SfxHint(SfxHintId::SwLegacyModify), m_pOld(pOld), m_pNew(pNew) {};
75 sal_uInt16 GetWhich() const { return m_pOld ? m_pOld->Which() : m_pNew ? m_pNew->Which() : 0; };
76 virtual ~LegacyModifyHint() override;
77 const SfxPoolItem* m_pOld;
78 const SfxPoolItem* m_pNew;
80 struct ModifyChangedHint final: SfxHint
82 ModifyChangedHint(const SwModify* pNew) : m_pNew(pNew) {};
83 const SwModify* m_pNew;
85 // Observer pattern using svl implementation
86 // use this instead of SwClient/SwModify wherever possible
87 // In writer layout, this might not always be possible,
88 // but for listeners outside of it (e.g. unocore) this should be used.
89 // The only "magic" signal this class issues is a ModifyChangedHint
90 // proclaiming its death. It does NOT however provide a new SwModify for
91 // listeners to switch to like the old SwModify/SwClient did, as that leads
92 // to madness.
93 class SW_DLLPUBLIC BroadcasterMixin {
94 SvtBroadcaster m_aNotifier;
95 public:
96 BroadcasterMixin() = default;
97 BroadcasterMixin(BroadcasterMixin const &) = default;
98 BroadcasterMixin& operator=(const BroadcasterMixin&)
100 return *this; // Listeners are never copied or moved.
102 SvtBroadcaster& GetNotifier() { return m_aNotifier; }
104 /// refactoring out the same of the more sane SwClient functionality
105 class SW_DLLPUBLIC WriterListener
107 friend class ::SwModify;
108 friend class ::sw::ClientIteratorBase;
109 private:
110 WriterListener* m_pLeft;
111 WriterListener* m_pRight; ///< double-linked list of other clients
113 WriterListener(WriterListener const&) = delete;
114 WriterListener& operator=(WriterListener const&) = delete;
116 protected:
117 WriterListener()
118 : m_pLeft(nullptr), m_pRight(nullptr)
120 virtual ~WriterListener() COVERITY_NOEXCEPT_FALSE {}
121 virtual void SwClientNotify( const SwModify&, const SfxHint& rHint) =0;
122 public:
123 bool IsLast() const { return !m_pLeft && !m_pRight; }
124 virtual const SwCellFrame* DynCastCellFrame() const { return nullptr; }
125 virtual const SwTabFrame* DynCastTabFrame() const { return nullptr; }
126 virtual const SwRowFrame* DynCastRowFrame() const { return nullptr; }
128 enum class IteratorMode { Exact, UnwrapMulti };
131 // SwClient
132 class SW_DLLPUBLIC SwClient : public ::sw::WriterListener
134 // avoids making the details of the linked list and the callback method public
135 friend class SwModify;
136 friend class sw::ClientIteratorBase;
137 friend class sw::ListenerEntry;
138 template<typename E, typename S, sw::IteratorMode> friend class SwIterator;
140 SwModify *m_pRegisteredIn; ///< event source
142 protected:
143 // single argument ctors shall be explicit.
144 inline explicit SwClient( SwModify* pToRegisterIn );
146 // write access to pRegisteredIn shall be granted only to the object itself (protected access)
147 SwModify* GetRegisteredInNonConst() const { return m_pRegisteredIn; }
149 // when overriding this, you MUST call SwClient::SwClientModify() in the override!
150 virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) override;
152 public:
153 SwClient() : m_pRegisteredIn(nullptr) {}
154 SwClient(SwClient&&) noexcept;
155 virtual ~SwClient() override;
158 // in case an SwModify object is destroyed that itself is registered in another SwModify,
159 // its SwClient objects can decide to get registered to the latter instead by calling this method
160 std::optional<sw::ModifyChangedHint> CheckRegistration( const SfxPoolItem* pOldValue );
161 // SwFormat wants to die different than the rest: It wants to reparent every client to its parent
162 // and then send a SwFormatChg hint.
163 void CheckRegistrationFormat(SwFormat& rOld);
165 const SwModify* GetRegisteredIn() const { return m_pRegisteredIn; }
166 SwModify* GetRegisteredIn() { return m_pRegisteredIn; }
167 void EndListeningAll();
168 void StartListeningToSameModifyAs(const SwClient&);
171 // get information about attribute
172 virtual bool GetInfo( SfxPoolItem& ) const { return true; }
176 // SwModify
178 // class has a doubly linked list for dependencies
179 class SW_DLLPUBLIC SwModify: public SwClient
181 friend class sw::ClientIteratorBase;
182 friend void sw::ClientNotifyAttrChg(SwModify&, const SwAttrSet&, SwAttrSet&, SwAttrSet&);
183 template<typename E, typename S, sw::IteratorMode> friend class SwIterator;
184 sw::WriterListener* m_pWriterListeners; // the start of the linked list of clients
185 bool m_bModifyLocked; // don't broadcast changes now
187 SwModify(SwModify const &) = delete;
188 SwModify &operator =(const SwModify&) = delete;
189 protected:
190 virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) override;
191 public:
192 SwModify()
193 : SwClient(), m_pWriterListeners(nullptr), m_bModifyLocked(false)
196 // broadcasting mechanism
197 virtual void CallSwClientNotify( const SfxHint& rHint ) const;
199 virtual ~SwModify() override;
201 void Add(SwClient *pDepend);
202 SwClient* Remove(SwClient *pDepend);
203 bool HasWriterListeners() const { return m_pWriterListeners; }
204 bool HasOnlyOneListener() const { return m_pWriterListeners && m_pWriterListeners->IsLast(); }
206 // get information about attribute
207 virtual bool GetInfo( SfxPoolItem& ) const override;
209 void LockModify() { m_bModifyLocked = true; }
210 void UnlockModify() { m_bModifyLocked = false; }
211 bool IsModifyLocked() const { return m_bModifyLocked; }
214 template<typename TElementType, typename TSource, sw::IteratorMode eMode> class SwIterator;
216 namespace sw
219 // this class is part of the migration: it still forwards the "old"
220 // SwModify events and announces them both to the old SwClients still
221 // registered and also to the new SvtListeners.
222 // Still: in the long run the SwClient/SwModify interface should not be
223 // used anymore, in which case a BroadcasterMixin should be enough instead
224 // then.
225 class SW_DLLPUBLIC BroadcastingModify : public SwModify, public BroadcasterMixin {
226 public:
227 virtual void CallSwClientNotify(const SfxHint& rHint) const override;
229 // this should be hidden but sadly SwIterator template needs it...
230 class ListenerEntry final : public SwClient
232 private:
233 template<typename E, typename S, sw::IteratorMode> friend class ::SwIterator;
234 SwClient *m_pToTell;
236 public:
237 ListenerEntry(SwClient *const pTellHim, SwModify *const pDepend)
238 : SwClient(pDepend), m_pToTell(pTellHim)
240 ListenerEntry(ListenerEntry const &) = delete;
241 ListenerEntry& operator=(ListenerEntry const&) = delete;
242 ListenerEntry(ListenerEntry&& other) noexcept
243 : SwClient(std::move(other))
244 , m_pToTell(other.m_pToTell)
246 ListenerEntry& operator=(ListenerEntry&& other) noexcept
248 m_pToTell = other.m_pToTell;
249 other.GetRegisteredIn()->Add(this);
250 other.EndListeningAll();
251 return *this;
254 /** get Client information */
255 virtual bool GetInfo( SfxPoolItem& rInfo) const override;
256 private:
257 virtual void SwClientNotify(const SwModify& rModify, const SfxHint& rHint) override;
260 class SW_DLLPUBLIC WriterMultiListener final
262 SwClient& m_rToTell;
263 std::vector<ListenerEntry> m_vDepends;
264 public:
265 WriterMultiListener(SwClient& rToTell);
266 WriterMultiListener& operator=(WriterMultiListener const&) = delete; // MSVC2015 workaround
267 WriterMultiListener(WriterMultiListener const&) = delete; // MSVC2015 workaround
268 ~WriterMultiListener();
269 void StartListening(SwModify* pDepend);
270 void EndListening(SwModify* pDepend);
271 bool IsListeningTo(const SwModify* const pDepend) const;
272 void EndListeningAll();
274 class ClientIteratorBase : public sw::Ring< ::sw::ClientIteratorBase >
276 friend SwClient* SwModify::Remove(SwClient*);
277 friend void SwModify::Add(SwClient*);
278 protected:
279 const SwModify& m_rRoot;
280 // the current object in an iteration
281 WriterListener* m_pCurrent;
282 // in case the current object is already removed, the next object in the list
283 // is marked down to become the current object in the next step
284 // this is necessary because iteration requires access to members of the current object
285 WriterListener* m_pPosition;
286 static SW_DLLPUBLIC ClientIteratorBase* s_pClientIters;
288 ClientIteratorBase( const SwModify& rModify )
289 : m_rRoot(rModify)
291 MoveTo(s_pClientIters);
292 s_pClientIters = this;
293 m_pCurrent = m_pPosition = m_rRoot.m_pWriterListeners;
295 WriterListener* GetLeftOfPos() { return m_pPosition->m_pLeft; }
296 WriterListener* GetRightOfPos() { return m_pPosition->m_pRight; }
297 WriterListener* GoStart()
299 m_pPosition = m_rRoot.m_pWriterListeners;
300 if(m_pPosition)
301 while( m_pPosition->m_pLeft )
302 m_pPosition = m_pPosition->m_pLeft;
303 m_pCurrent = m_pPosition;
304 return m_pCurrent;
306 ~ClientIteratorBase() override
308 assert(s_pClientIters);
309 if(s_pClientIters == this)
310 s_pClientIters = unique() ? nullptr : GetNextInRing();
311 MoveTo(nullptr);
313 // return "true" if an object was removed from a client chain in iteration
314 // adding objects to a client chain in iteration is forbidden
315 // SwModify::Add() asserts this
316 bool IsChanged() const { return m_pPosition != m_pCurrent; }
317 // ensures the iterator to point at a current client
318 WriterListener* Sync() { m_pCurrent = m_pPosition; return m_pCurrent; }
322 namespace sw::detail
324 // Dynamic casting can be expensive when used a lot, so for certain type combinations,
325 // we have faster routines.
326 template<typename CastDest>
327 inline const CastDest * internal_dyn_cast(const sw::WriterListener * pSource)
329 return dynamic_cast<const CastDest *>(pSource);
331 template<>
332 inline const SwCellFrame* internal_dyn_cast(const sw::WriterListener * pSource)
334 return pSource->DynCastCellFrame();
336 template<>
337 inline const SwTabFrame* internal_dyn_cast(const sw::WriterListener * pSource)
339 return pSource->DynCastTabFrame();
341 template<>
342 inline const SwRowFrame* internal_dyn_cast(const sw::WriterListener * pSource)
344 return pSource->DynCastRowFrame();
346 } // namespace sw::detail
348 template<typename TElementType, typename TSource,
349 sw::IteratorMode eMode = sw::IteratorMode::Exact> class SwIterator final
350 : private sw::ClientIteratorBase
352 //static_assert(!std::is_base_of<SwPageDesc,TSource>::value, "SwPageDesc as TSource is deprecated.");
353 static_assert(std::is_base_of<SwClient,TElementType>::value, "TElementType needs to be derived from SwClient.");
354 static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify.");
355 public:
356 SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
357 TElementType* First()
359 GoStart();
360 if(!m_pPosition)
361 return nullptr;
362 m_pCurrent = nullptr;
363 return Next();
365 TElementType* Next()
367 if(!IsChanged())
368 m_pPosition = GetRightOfPos();
369 sw::WriterListener *pCurrent(m_pPosition);
370 while (m_pPosition)
372 if (eMode == sw::IteratorMode::UnwrapMulti)
374 if (auto const pLE = dynamic_cast<sw::ListenerEntry const*>(m_pPosition))
376 pCurrent = pLE->m_pToTell;
379 if (sw::detail::internal_dyn_cast<TElementType>(pCurrent) == nullptr)
381 m_pPosition = GetRightOfPos();
382 pCurrent = m_pPosition;
384 else
385 break;
387 Sync();
388 return static_cast<TElementType*>(pCurrent);
390 using sw::ClientIteratorBase::IsChanged;
393 template< typename TSource > class SwIterator<SwClient, TSource> final : private sw::ClientIteratorBase
395 static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify");
396 public:
397 SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
398 SwClient* First()
399 { return static_cast<SwClient*>(GoStart()); }
400 SwClient* Next()
402 if(!IsChanged())
403 m_pPosition = GetRightOfPos();
404 return static_cast<SwClient*>(Sync());
406 using sw::ClientIteratorBase::IsChanged;
409 SwClient::SwClient( SwModify* pToRegisterIn )
410 : m_pRegisteredIn( nullptr )
412 if(pToRegisterIn)
413 pToRegisterIn->Add(this);
416 #endif
418 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */