1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #ifndef SC_BCASLOT_HXX
25 #define SC_BCASLOT_HXX
26
27 #include <set>
28 #include <hash_set>
29 #include <functional>
30 #include <svl/broadcast.hxx>
31 #include <svl/svarray.hxx>
32
33 #include "global.hxx"
34 #include "brdcst.hxx"
35
36 /**
37 Used in a Unique Associative Container.
38 */
39
40 class ScBroadcastArea
41 {
42 private:
43 ScBroadcastArea* pUpdateChainNext;
44 SvtBroadcaster aBroadcaster;
45 ScRange aRange;
46 sal_uLong nRefCount;
47 sal_Bool bInUpdateChain;
48
49 public:
ScBroadcastArea(const ScRange & rRange)50 ScBroadcastArea( const ScRange& rRange )
51 : pUpdateChainNext( NULL ), aRange( rRange ),
52 nRefCount( 0 ), bInUpdateChain( sal_False ) {}
GetBroadcaster()53 inline SvtBroadcaster& GetBroadcaster() { return aBroadcaster; }
GetBroadcaster() const54 inline const SvtBroadcaster& GetBroadcaster() const { return aBroadcaster; }
UpdateRange(const ScRange & rNewRange)55 inline void UpdateRange( const ScRange& rNewRange )
56 { aRange = rNewRange; }
GetRange() const57 inline const ScRange& GetRange() const { return aRange; }
GetStart() const58 inline const ScAddress& GetStart() const { return aRange.aStart; }
GetEnd() const59 inline const ScAddress& GetEnd() const { return aRange.aEnd; }
IncRef()60 inline void IncRef() { ++nRefCount; }
DecRef()61 inline sal_uLong DecRef() { return nRefCount ? --nRefCount : 0; }
GetRef()62 inline sal_uLong GetRef() { return nRefCount; }
GetUpdateChainNext() const63 inline ScBroadcastArea* GetUpdateChainNext() const { return pUpdateChainNext; }
SetUpdateChainNext(ScBroadcastArea * p)64 inline void SetUpdateChainNext( ScBroadcastArea* p ) { pUpdateChainNext = p; }
IsInUpdateChain() const65 inline sal_Bool IsInUpdateChain() const { return bInUpdateChain; }
SetInUpdateChain(sal_Bool b)66 inline void SetInUpdateChain( sal_Bool b ) { bInUpdateChain = b; }
67
68 /** Equalness of this or range. */
69 inline bool operator==( const ScBroadcastArea & rArea ) const;
70 };
71
operator ==(const ScBroadcastArea & rArea) const72 inline bool ScBroadcastArea::operator==( const ScBroadcastArea & rArea ) const
73 {
74 return aRange == rArea.aRange;
75 }
76
77 //=============================================================================
78
79 struct ScBroadcastAreaHash
80 {
operator ()ScBroadcastAreaHash81 size_t operator()( const ScBroadcastArea* p ) const
82 {
83 return p->GetRange().hashArea();
84 }
85 };
86
87 struct ScBroadcastAreaEqual
88 {
operator ()ScBroadcastAreaEqual89 bool operator()( const ScBroadcastArea* p1, const ScBroadcastArea* p2) const
90 {
91 return *p1 == *p2;
92 }
93 };
94
95 typedef ::std::hash_set< ScBroadcastArea*, ScBroadcastAreaHash, ScBroadcastAreaEqual > ScBroadcastAreas;
96
97 //=============================================================================
98
99 struct ScBroadcastAreaBulkHash
100 {
operator ()ScBroadcastAreaBulkHash101 size_t operator()( const ScBroadcastArea* p ) const
102 {
103 return reinterpret_cast<size_t>(p);
104 }
105 };
106
107 struct ScBroadcastAreaBulkEqual
108 {
operator ()ScBroadcastAreaBulkEqual109 bool operator()( const ScBroadcastArea* p1, const ScBroadcastArea* p2) const
110 {
111 return p1 == p2;
112 }
113 };
114
115 typedef ::std::hash_set< const ScBroadcastArea*, ScBroadcastAreaBulkHash,
116 ScBroadcastAreaBulkEqual > ScBroadcastAreasBulk;
117
118 //=============================================================================
119
120 class ScBroadcastAreaSlotMachine;
121
122 /// Collection of BroadcastAreas
123 class ScBroadcastAreaSlot
124 {
125 private:
126 ScBroadcastAreas aBroadcastAreaTbl;
127 mutable ScBroadcastArea aTmpSeekBroadcastArea; // for FindBroadcastArea()
128 ScDocument* pDoc;
129 ScBroadcastAreaSlotMachine* pBASM;
130
131 ScBroadcastAreas::const_iterator FindBroadcastArea( const ScRange& rRange ) const;
132
133 /**
134 More hypothetical (memory would probably be doomed anyway) check
135 whether there would be an overflow when adding an area, setting the
136 proper state if so.
137
138 @return sal_True if a HardRecalcState is effective and area is not to be
139 added.
140 */
141 bool CheckHardRecalcStateCondition() const;
142
143 public:
144 ScBroadcastAreaSlot( ScDocument* pDoc,
145 ScBroadcastAreaSlotMachine* pBASM );
146 ~ScBroadcastAreaSlot();
GetBroadcastAreas() const147 const ScBroadcastAreas& GetBroadcastAreas() const
148 { return aBroadcastAreaTbl; }
149
150 /**
151 Only here new ScBroadcastArea objects are created, prevention of dupes.
152
153 @param rpArea
154 If NULL, a new ScBroadcastArea is created and assigned ton the
155 reference if a matching area wasn't found. If a matching area was
156 found, that is assigned. In any case, the SvtListener is added to
157 the broadcaster.
158
159 If not NULL then no listeners are startet, only the area is
160 inserted and the reference count incremented. Effectively the same
161 as InsertListeningArea(), so use that instead.
162
163 @return
164 sal_True if rpArea passed was NULL and ScBroadcastArea is newly
165 created.
166 */
167 bool StartListeningArea( const ScRange& rRange,
168 SvtListener* pListener,
169 ScBroadcastArea*& rpArea );
170
171 /**
172 Insert a ScBroadcastArea obtained via StartListeningArea() to
173 subsequent slots.
174 */
175 void InsertListeningArea( ScBroadcastArea* pArea );
176
177 void EndListeningArea( const ScRange& rRange,
178 SvtListener* pListener,
179 ScBroadcastArea*& rpArea );
180 sal_Bool AreaBroadcast( const ScHint& rHint ) const;
181 /// @return sal_True if at least one broadcast occurred.
182 sal_Bool AreaBroadcastInRange( const ScRange& rRange,
183 const ScHint& rHint ) const;
184 void DelBroadcastAreasInRange( const ScRange& rRange );
185 void UpdateRemove( UpdateRefMode eUpdateRefMode,
186 const ScRange& rRange,
187 SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
188 void UpdateRemoveArea( ScBroadcastArea* pArea );
189 void UpdateInsert( ScBroadcastArea* pArea );
190 };
191
192
193 /**
194 BroadcastAreaSlots and their management, once per document.
195 */
196
197 class ScBroadcastAreaSlotMachine
198 {
199 private:
200
201 /**
202 Slot offset arrangement of columns and rows, once per sheet.
203
204 +---+---+
205 | 0 | 3 |
206 +---+---+
207 | 1 | 4 |
208 +---+---+
209 | 2 | 5 |
210 +---+---+
211 */
212
213 class TableSlots
214 {
215 public:
216 TableSlots();
217 ~TableSlots();
getSlots()218 inline ScBroadcastAreaSlot** getSlots() { return ppSlots; }
219
220 /**
221 Obtain slot pointer, no check on validity! It is assumed that
222 all calls are made with the results of ComputeSlotOffset(),
223 ComputeAreaPoints() and ComputeNextSlot()
224 */
getAreaSlot(SCSIZE nOff)225 inline ScBroadcastAreaSlot* getAreaSlot( SCSIZE nOff ) { return *(ppSlots + nOff); }
226
227 private:
228 ScBroadcastAreaSlot** ppSlots;
229
230 // prevent usage
231 TableSlots( const TableSlots& );
232 TableSlots& operator=( const TableSlots& );
233 };
234
235 typedef ::std::map< SCTAB, TableSlots* > TableSlotsMap;
236
237 private:
238 ScBroadcastAreasBulk aBulkBroadcastAreas;
239 TableSlotsMap aTableSlotsMap;
240 SvtBroadcaster *pBCAlways; // for the RC_ALWAYS special range
241 ScDocument *pDoc;
242 ScBroadcastArea *pUpdateChain;
243 ScBroadcastArea *pEOUpdateChain;
244 sal_uLong nInBulkBroadcast;
245
246 inline SCSIZE ComputeSlotOffset( const ScAddress& rAddress ) const;
247 void ComputeAreaPoints( const ScRange& rRange,
248 SCSIZE& nStart, SCSIZE& nEnd,
249 SCSIZE& nRowBreak ) const;
250
251 public:
252 ScBroadcastAreaSlotMachine( ScDocument* pDoc );
253 ~ScBroadcastAreaSlotMachine();
254 void StartListeningArea( const ScRange& rRange,
255 SvtListener* pListener );
256 void EndListeningArea( const ScRange& rRange,
257 SvtListener* pListener );
258 sal_Bool AreaBroadcast( const ScHint& rHint ) const;
259 // return: at least one broadcast occurred
260 sal_Bool AreaBroadcastInRange( const ScRange& rRange, const ScHint& rHint ) const;
261 void DelBroadcastAreasInRange( const ScRange& rRange );
262 void UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode,
263 const ScRange& rRange,
264 SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
265 void EnterBulkBroadcast();
266 void LeaveBulkBroadcast();
267 bool InsertBulkArea( const ScBroadcastArea* p );
268 /// @return: how many removed
269 size_t RemoveBulkArea( const ScBroadcastArea* p );
GetUpdateChain() const270 inline ScBroadcastArea* GetUpdateChain() const { return pUpdateChain; }
SetUpdateChain(ScBroadcastArea * p)271 inline void SetUpdateChain( ScBroadcastArea* p ) { pUpdateChain = p; }
GetEOUpdateChain() const272 inline ScBroadcastArea* GetEOUpdateChain() const { return pEOUpdateChain; }
SetEOUpdateChain(ScBroadcastArea * p)273 inline void SetEOUpdateChain( ScBroadcastArea* p ) { pEOUpdateChain = p; }
IsInBulkBroadcast() const274 inline bool IsInBulkBroadcast() const { return nInBulkBroadcast > 0; }
275 };
276
277
278 class ScBulkBroadcast
279 {
280 ScBroadcastAreaSlotMachine* pBASM;
281 public:
ScBulkBroadcast(ScBroadcastAreaSlotMachine * p)282 explicit ScBulkBroadcast( ScBroadcastAreaSlotMachine* p ) : pBASM(p)
283 {
284 if (pBASM)
285 pBASM->EnterBulkBroadcast();
286 }
~ScBulkBroadcast()287 ~ScBulkBroadcast()
288 {
289 if (pBASM)
290 pBASM->LeaveBulkBroadcast();
291 }
LeaveBulkBroadcast()292 void LeaveBulkBroadcast()
293 {
294 if (pBASM)
295 {
296 pBASM->LeaveBulkBroadcast();
297 pBASM = NULL;
298 }
299 }
300 };
301
302 #endif
303