Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #ifndef INCLUDED_SC_SOURCE_CORE_INC_BCASLOT_HXX
21 : #define INCLUDED_SC_SOURCE_CORE_INC_BCASLOT_HXX
22 :
23 : #include <functional>
24 : #include <set>
25 : #include <unordered_set>
26 : #include <boost/ptr_container/ptr_map.hpp>
27 :
28 : #include <svl/broadcast.hxx>
29 :
30 : #include "global.hxx"
31 : #include "brdcst.hxx"
32 : #include <columnspanset.hxx>
33 :
34 : class ScBroadcastArea;
35 :
36 : namespace sc {
37 :
38 45 : struct AreaListener
39 : {
40 : ScRange maArea;
41 : bool mbGroupListening;
42 : SvtListener* mpListener;
43 :
44 : struct SortByArea : std::binary_function<AreaListener, AreaListener, bool>
45 : {
46 : bool operator() ( const AreaListener& rLeft, const AreaListener& rRight ) const;
47 : };
48 : };
49 :
50 : }
51 :
52 : /**
53 : Used in a Unique Associative Container.
54 : */
55 :
56 3708 : class ScBroadcastArea : boost::noncopyable
57 : {
58 : private:
59 : ScBroadcastArea* pUpdateChainNext;
60 : SvtBroadcaster aBroadcaster;
61 : ScRange aRange;
62 : sal_uLong nRefCount;
63 :
64 : bool mbInUpdateChain:1;
65 : bool mbGroupListening:1;
66 :
67 : public:
68 : ScBroadcastArea( const ScRange& rRange );
69 :
70 8400 : inline SvtBroadcaster& GetBroadcaster() { return aBroadcaster; }
71 : inline const SvtBroadcaster& GetBroadcaster() const { return aBroadcaster; }
72 7503 : inline void UpdateRange( const ScRange& rNewRange )
73 7503 : { aRange = rNewRange; }
74 16400 : inline const ScRange& GetRange() const { return aRange; }
75 : inline const ScAddress& GetStart() const { return aRange.aStart; }
76 : inline const ScAddress& GetEnd() const { return aRange.aEnd; }
77 3532 : inline void IncRef() { ++nRefCount; }
78 3456 : inline sal_uLong DecRef() { return nRefCount ? --nRefCount : 0; }
79 435 : inline sal_uLong GetRef() { return nRefCount; }
80 98 : inline ScBroadcastArea* GetUpdateChainNext() const { return pUpdateChainNext; }
81 49 : inline void SetUpdateChainNext( ScBroadcastArea* p ) { pUpdateChainNext = p; }
82 63 : inline bool IsInUpdateChain() const { return mbInUpdateChain; }
83 98 : inline void SetInUpdateChain( bool b ) { mbInUpdateChain = b; }
84 :
85 11601 : inline bool IsGroupListening() const { return mbGroupListening; }
86 9693 : void SetGroupListening( bool b ) { mbGroupListening = b; }
87 :
88 : /** Equalness of this or range. */
89 : inline bool operator==( const ScBroadcastArea & rArea ) const;
90 : };
91 :
92 5173 : inline bool ScBroadcastArea::operator==( const ScBroadcastArea & rArea ) const
93 : {
94 5173 : return aRange == rArea.aRange && mbGroupListening == rArea.mbGroupListening;
95 : }
96 :
97 : struct ScBroadcastAreaEntry
98 : {
99 : ScBroadcastArea* mpArea;
100 : mutable bool mbErasure; ///< TRUE if marked for erasure in this set
101 :
102 10987 : ScBroadcastAreaEntry( ScBroadcastArea* p ) : mpArea( p), mbErasure( false) {}
103 : };
104 :
105 : struct ScBroadcastAreaHash
106 : {
107 10987 : size_t operator()( const ScBroadcastAreaEntry& rEntry ) const
108 : {
109 10987 : return rEntry.mpArea->GetRange().hashArea() + static_cast<size_t>(rEntry.mpArea->IsGroupListening());
110 : }
111 : };
112 :
113 : struct ScBroadcastAreaEqual
114 : {
115 5173 : bool operator()( const ScBroadcastAreaEntry& rEntry1, const ScBroadcastAreaEntry& rEntry2) const
116 : {
117 5173 : return *rEntry1.mpArea == *rEntry2.mpArea;
118 : }
119 : };
120 :
121 : typedef std::unordered_set< ScBroadcastAreaEntry, ScBroadcastAreaHash, ScBroadcastAreaEqual > ScBroadcastAreas;
122 :
123 : struct ScBroadcastAreaBulkHash
124 : {
125 402 : size_t operator()( const ScBroadcastArea* p ) const
126 : {
127 402 : return reinterpret_cast<size_t>(p);
128 : }
129 : };
130 :
131 : struct ScBroadcastAreaBulkEqual
132 : {
133 192 : bool operator()( const ScBroadcastArea* p1, const ScBroadcastArea* p2) const
134 : {
135 192 : return p1 == p2;
136 : }
137 : };
138 :
139 : typedef std::unordered_set< const ScBroadcastArea*, ScBroadcastAreaBulkHash,
140 : ScBroadcastAreaBulkEqual > ScBroadcastAreasBulk;
141 :
142 : class ScBroadcastAreaSlotMachine;
143 :
144 : /// Collection of BroadcastAreas
145 : class ScBroadcastAreaSlot
146 : {
147 : private:
148 : ScBroadcastAreas aBroadcastAreaTbl;
149 : mutable ScBroadcastArea aTmpSeekBroadcastArea; // for FindBroadcastArea()
150 : ScDocument* pDoc;
151 : ScBroadcastAreaSlotMachine* pBASM;
152 : bool mbInBroadcastIteration;
153 :
154 : /**
155 : * If true, the slot has at least one area broadcaster marked for removal.
156 : * This flag is used only during broadcast iteration, to speed up
157 : * iteration. Using this flag is cheaper than dereferencing each iterator
158 : * and checking its own flag inside especially when no areas are marked
159 : * for removal.
160 : */
161 : bool mbHasErasedArea;
162 :
163 : ScBroadcastAreas::iterator FindBroadcastArea( const ScRange& rRange, bool bGroupListening );
164 :
165 : /**
166 : More hypothetical (memory would probably be doomed anyway) check
167 : whether there would be an overflow when adding an area, setting the
168 : proper state if so.
169 :
170 : @return true if a HardRecalcState is effective and area is not to be
171 : added.
172 : */
173 : bool CheckHardRecalcStateCondition() const;
174 :
175 : /** Finally erase all areas pushed as to-be-erased. */
176 : void FinallyEraseAreas();
177 :
178 591 : static bool isMarkedErased( const ScBroadcastAreas::const_iterator& rIter )
179 : {
180 591 : return rIter->mbErasure;
181 : }
182 :
183 : public:
184 : ScBroadcastAreaSlot( ScDocument* pDoc,
185 : ScBroadcastAreaSlotMachine* pBASM );
186 : ~ScBroadcastAreaSlot();
187 : const ScBroadcastAreas& GetBroadcastAreas() const
188 : { return aBroadcastAreaTbl; }
189 :
190 : /**
191 : Only here new ScBroadcastArea objects are created, prevention of dupes.
192 :
193 : @param rpArea
194 : If NULL, a new ScBroadcastArea is created and assigned ton the
195 : reference if a matching area wasn't found. If a matching area was
196 : found, that is assigned. In any case, the SvtListener is added to
197 : the broadcaster.
198 :
199 : If not NULL then no listeners are startet, only the area is
200 : inserted and the reference count incremented. Effectively the same
201 : as InsertListeningArea(), so use that instead.
202 :
203 : @return
204 : true if rpArea passed was NULL and ScBroadcastArea is newly
205 : created.
206 : */
207 : bool StartListeningArea(
208 : const ScRange& rRange, bool bGroupListening, SvtListener* pListener, ScBroadcastArea*& rpArea );
209 :
210 : /**
211 : Insert a ScBroadcastArea obtained via StartListeningArea() to
212 : subsequent slots.
213 : */
214 : void InsertListeningArea( ScBroadcastArea* pArea );
215 :
216 : void EndListeningArea(
217 : const ScRange& rRange, bool bGroupListening, SvtListener* pListener, ScBroadcastArea*& rpArea );
218 :
219 : bool AreaBroadcast( const ScRange& rRange, sal_uLong nHint );
220 : bool AreaBroadcast( const ScHint& rHint );
221 : void DelBroadcastAreasInRange( const ScRange& rRange );
222 : void UpdateRemove( UpdateRefMode eUpdateRefMode,
223 : const ScRange& rRange,
224 : SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
225 : void UpdateRemoveArea( ScBroadcastArea* pArea );
226 : void UpdateInsert( ScBroadcastArea* pArea );
227 :
228 1946 : bool IsInBroadcastIteration() const { return mbInBroadcastIteration; }
229 :
230 : /** Erase an area from set and delete it if last reference, or if
231 : mbInBroadcastIteration is set push it to the vector of to-be-erased
232 : areas instead.
233 :
234 : Meant to be used internally and from ScBroadcastAreaSlotMachine only.
235 : */
236 : void EraseArea( ScBroadcastAreas::iterator& rIter );
237 :
238 : void GetAllListeners(
239 : const ScRange& rRange, std::vector<sc::AreaListener>& rListeners,
240 : sc::AreaOverlapType eType, sc::ListenerGroupType eGroup );
241 :
242 : #if DEBUG_AREA_BROADCASTER
243 : void Dump() const;
244 : #endif
245 : };
246 :
247 : /**
248 : BroadcastAreaSlots and their management, once per document.
249 : */
250 :
251 : class ScBroadcastAreaSlotMachine
252 : {
253 : private:
254 : typedef boost::ptr_map<ScBroadcastArea*, sc::ColumnSpanSet> BulkGroupAreasType;
255 :
256 : /**
257 : Slot offset arrangement of columns and rows, once per sheet.
258 :
259 : +---+---+
260 : | 0 | 3 |
261 : +---+---+
262 : | 1 | 4 |
263 : +---+---+
264 : | 2 | 5 |
265 : +---+---+
266 : */
267 :
268 : class TableSlots
269 : {
270 : public:
271 : TableSlots();
272 : ~TableSlots();
273 7705 : inline ScBroadcastAreaSlot** getSlots() { return ppSlots; }
274 :
275 : /**
276 : Obtain slot pointer, no check on validity! It is assumed that
277 : all calls are made with the results of ComputeSlotOffset(),
278 : ComputeAreaPoints() and ComputeNextSlot()
279 : */
280 5377 : inline ScBroadcastAreaSlot* getAreaSlot( SCSIZE nOff ) { return *(ppSlots + nOff); }
281 :
282 : private:
283 : ScBroadcastAreaSlot** ppSlots;
284 :
285 : TableSlots( const TableSlots& ) SAL_DELETED_FUNCTION;
286 : TableSlots& operator=( const TableSlots& ) SAL_DELETED_FUNCTION;
287 : };
288 :
289 : typedef ::std::map< SCTAB, TableSlots* > TableSlotsMap;
290 :
291 : typedef ::std::vector< ::std::pair< ScBroadcastAreaSlot*, ScBroadcastAreas::iterator > > AreasToBeErased;
292 :
293 : private:
294 : ScBroadcastAreasBulk aBulkBroadcastAreas;
295 : BulkGroupAreasType maBulkGroupAreas;
296 : TableSlotsMap aTableSlotsMap;
297 : AreasToBeErased maAreasToBeErased;
298 : SvtBroadcaster *pBCAlways; // for the RC_ALWAYS special range
299 : ScDocument *pDoc;
300 : ScBroadcastArea *pUpdateChain;
301 : ScBroadcastArea *pEOUpdateChain;
302 : sal_uLong nInBulkBroadcast;
303 :
304 : static inline SCSIZE ComputeSlotOffset( const ScAddress& rAddress );
305 : static void ComputeAreaPoints( const ScRange& rRange,
306 : SCSIZE& nStart, SCSIZE& nEnd,
307 : SCSIZE& nRowBreak );
308 :
309 : public:
310 : ScBroadcastAreaSlotMachine( ScDocument* pDoc );
311 : ~ScBroadcastAreaSlotMachine();
312 : void StartListeningArea(
313 : const ScRange& rRange, bool bGroupListening, SvtListener* pListener );
314 :
315 : void EndListeningArea(
316 : const ScRange& rRange, bool bGroupListening, SvtListener* pListener );
317 :
318 : bool AreaBroadcast( const ScRange& rRange, sal_uLong nHint );
319 : bool AreaBroadcast( const ScHint& rHint ) const;
320 : // return: at least one broadcast occurred
321 : void DelBroadcastAreasInRange( const ScRange& rRange );
322 : void UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode,
323 : const ScRange& rRange,
324 : SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
325 : void EnterBulkBroadcast();
326 : void LeaveBulkBroadcast();
327 : bool InsertBulkArea( const ScBroadcastArea* p );
328 :
329 : void InsertBulkGroupArea( ScBroadcastArea* pArea, const ScRange& rRange );
330 : void BulkBroadcastGroupAreas();
331 :
332 : /// @return: how many removed
333 : size_t RemoveBulkArea( const ScBroadcastArea* p );
334 : inline ScBroadcastArea* GetUpdateChain() const { return pUpdateChain; }
335 49 : inline void SetUpdateChain( ScBroadcastArea* p ) { pUpdateChain = p; }
336 49 : inline ScBroadcastArea* GetEOUpdateChain() const { return pEOUpdateChain; }
337 49 : inline void SetEOUpdateChain( ScBroadcastArea* p ) { pEOUpdateChain = p; }
338 651 : inline bool IsInBulkBroadcast() const { return nInBulkBroadcast > 0; }
339 :
340 : // only for ScBroadcastAreaSlot
341 : void PushAreaToBeErased( ScBroadcastAreaSlot* pSlot,
342 : ScBroadcastAreas::iterator& rIter );
343 : // only for ScBroadcastAreaSlot
344 : void FinallyEraseAreas( ScBroadcastAreaSlot* pSlot );
345 :
346 : std::vector<sc::AreaListener> GetAllListeners(
347 : const ScRange& rRange, sc::AreaOverlapType eType,
348 : sc::ListenerGroupType eGroup = sc::ListenerBoth );
349 :
350 : #if DEBUG_AREA_BROADCASTER
351 : void Dump() const;
352 : #endif
353 : };
354 :
355 : class ScBulkBroadcast
356 : {
357 : ScBroadcastAreaSlotMachine* pBASM;
358 : public:
359 50990 : explicit ScBulkBroadcast( ScBroadcastAreaSlotMachine* p ) : pBASM(p)
360 : {
361 50990 : if (pBASM)
362 50923 : pBASM->EnterBulkBroadcast();
363 50990 : }
364 50990 : ~ScBulkBroadcast()
365 : {
366 50990 : if (pBASM)
367 50923 : pBASM->LeaveBulkBroadcast();
368 50990 : }
369 : void LeaveBulkBroadcast()
370 : {
371 : if (pBASM)
372 : {
373 : pBASM->LeaveBulkBroadcast();
374 : pBASM = NULL;
375 : }
376 : }
377 : };
378 :
379 : #endif
380 :
381 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|