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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27
28
29 // INCLUDE ---------------------------------------------------------------
30
31 #include <tools/debug.hxx>
32
33 #include "markarr.hxx"
34 #include "global.hxx"
35 #include "address.hxx"
36
37 // STATIC DATA -----------------------------------------------------------
38
39 //------------------------------------------------------------------------
40
ScMarkArray()41 ScMarkArray::ScMarkArray() :
42 nCount( 0 ),
43 nLimit( 0 ),
44 pData( NULL )
45 {
46 // special case "no marks" with pData = NULL
47 }
48
49 //------------------------------------------------------------------------
50
~ScMarkArray()51 ScMarkArray::~ScMarkArray()
52 {
53 delete[] pData;
54 }
55
56 //------------------------------------------------------------------------
57
Reset(sal_Bool bMarked)58 void ScMarkArray::Reset( sal_Bool bMarked )
59 {
60 // always create pData here
61 // (or have separate method to ensure pData)
62
63 delete[] pData;
64
65 nCount = nLimit = 1;
66 pData = new ScMarkEntry[1];
67 pData[0].nRow = MAXROW;
68 pData[0].bMarked = bMarked;
69 }
70
71 //------------------------------------------------------------------------
72
Search(SCROW nRow,SCSIZE & nIndex) const73 sal_Bool ScMarkArray::Search( SCROW nRow, SCSIZE& nIndex ) const
74 {
75 long nLo = 0;
76 long nHi = static_cast<long>(nCount) - 1;
77 long nStartRow = 0;
78 long nEndRow = 0;
79 long i = 0;
80 sal_Bool bFound = (nCount == 1);
81 if (pData)
82 {
83 while ( !bFound && nLo <= nHi )
84 {
85 i = (nLo + nHi) / 2;
86 if (i > 0)
87 nStartRow = (long) pData[i - 1].nRow;
88 else
89 nStartRow = -1;
90 nEndRow = (long) pData[i].nRow;
91 if (nEndRow < (long) nRow)
92 nLo = ++i;
93 else
94 if (nStartRow >= (long) nRow)
95 nHi = --i;
96 else
97 bFound = sal_True;
98 }
99 }
100 else
101 bFound = sal_False;
102
103 if (bFound)
104 nIndex=(SCSIZE)i;
105 else
106 nIndex=0;
107 return bFound;
108 }
109
GetMark(SCROW nRow) const110 sal_Bool ScMarkArray::GetMark( SCROW nRow ) const
111 {
112 SCSIZE i;
113 if (Search( nRow, i ))
114 return pData[i].bMarked;
115 else
116 return sal_False;
117
118 }
119
120 //------------------------------------------------------------------------
121
SetMarkArea(SCROW nStartRow,SCROW nEndRow,sal_Bool bMarked)122 void ScMarkArray::SetMarkArea( SCROW nStartRow, SCROW nEndRow, sal_Bool bMarked )
123 {
124 if (ValidRow(nStartRow) && ValidRow(nEndRow))
125 {
126 if ((nStartRow == 0) && (nEndRow == MAXROW))
127 {
128 Reset(bMarked);
129 }
130 else
131 {
132 if (!pData)
133 Reset(sal_False); // create pData for further processing - could use special case handling!
134
135 SCSIZE nNeeded = nCount + 2;
136 if ( nLimit < nNeeded )
137 {
138 nLimit += SC_MARKARRAY_DELTA;
139 if ( nLimit < nNeeded )
140 nLimit = nNeeded;
141 ScMarkEntry* pNewData = new ScMarkEntry[nLimit];
142 memcpy( pNewData, pData, nCount*sizeof(ScMarkEntry) );
143 delete[] pData;
144 pData = pNewData;
145 }
146
147 SCSIZE ni; // number of entries in beginning
148 SCSIZE nInsert; // insert position (MAXROW+1 := no insert)
149 sal_Bool bCombined = sal_False;
150 sal_Bool bSplit = sal_False;
151 if ( nStartRow > 0 )
152 {
153 // skip beginning
154 SCSIZE nIndex;
155 Search( nStartRow, nIndex );
156 ni = nIndex;
157
158 nInsert = MAXROWCOUNT;
159 if ( pData[ni].bMarked != bMarked )
160 {
161 if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
162 { // may be a split or a simple insert or just a shrink,
163 // row adjustment is done further down
164 if ( pData[ni].nRow > nEndRow )
165 bSplit = sal_True;
166 ni++;
167 nInsert = ni;
168 }
169 else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
170 nInsert = ni;
171 }
172 if ( ni > 0 && pData[ni-1].bMarked == bMarked )
173 { // combine
174 pData[ni-1].nRow = nEndRow;
175 nInsert = MAXROWCOUNT;
176 bCombined = sal_True;
177 }
178 }
179 else
180 {
181 nInsert = 0;
182 ni = 0;
183 }
184
185 SCSIZE nj = ni; // stop position of range to replace
186 while ( nj < nCount && pData[nj].nRow <= nEndRow )
187 nj++;
188 if ( !bSplit )
189 {
190 if ( nj < nCount && pData[nj].bMarked == bMarked )
191 { // combine
192 if ( ni > 0 )
193 {
194 if ( pData[ni-1].bMarked == bMarked )
195 { // adjacent entries
196 pData[ni-1].nRow = pData[nj].nRow;
197 nj++;
198 }
199 else if ( ni == nInsert )
200 pData[ni-1].nRow = nStartRow - 1; // shrink
201 }
202 nInsert = MAXROWCOUNT;
203 bCombined = sal_True;
204 }
205 else if ( ni > 0 && ni == nInsert )
206 pData[ni-1].nRow = nStartRow - 1; // shrink
207 }
208 if ( ni < nj )
209 { // remove middle entries
210 if ( !bCombined )
211 { // replace one entry
212 pData[ni].nRow = nEndRow;
213 pData[ni].bMarked = bMarked;
214 ni++;
215 nInsert = MAXROWCOUNT;
216 }
217 if ( ni < nj )
218 { // remove entries
219 memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScMarkEntry) );
220 nCount -= nj - ni;
221 }
222 }
223
224 if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
225 { // insert or append new entry
226 if ( nInsert <= nCount )
227 {
228 if ( !bSplit )
229 memmove( pData + nInsert + 1, pData + nInsert,
230 (nCount - nInsert) * sizeof(ScMarkEntry) );
231 else
232 {
233 memmove( pData + nInsert + 2, pData + nInsert,
234 (nCount - nInsert) * sizeof(ScMarkEntry) );
235 pData[nInsert+1] = pData[nInsert-1];
236 nCount++;
237 }
238 }
239 if ( nInsert )
240 pData[nInsert-1].nRow = nStartRow - 1;
241 pData[nInsert].nRow = nEndRow;
242 pData[nInsert].bMarked = bMarked;
243 nCount++;
244 }
245 }
246 }
247 // InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
248 }
249
250 //UNUSED2009-05 void ScMarkArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
251 //UNUSED2009-05 {
252 //UNUSED2009-05 SetMarkArea(nStartRow, nEndRow, sal_False);
253 //UNUSED2009-05 }
254
IsAllMarked(SCROW nStartRow,SCROW nEndRow) const255 sal_Bool ScMarkArray::IsAllMarked( SCROW nStartRow, SCROW nEndRow ) const
256 {
257 SCSIZE nStartIndex;
258 SCSIZE nEndIndex;
259
260 if (Search( nStartRow, nStartIndex ))
261 if (pData[nStartIndex].bMarked)
262 if (Search( nEndRow, nEndIndex ))
263 if (nEndIndex==nStartIndex)
264 return sal_True;
265
266 return sal_False;
267 }
268
HasOneMark(SCROW & rStartRow,SCROW & rEndRow) const269 sal_Bool ScMarkArray::HasOneMark( SCROW& rStartRow, SCROW& rEndRow ) const
270 {
271 sal_Bool bRet = sal_False;
272 if ( nCount == 1 )
273 {
274 if ( pData[0].bMarked )
275 {
276 rStartRow = 0;
277 rEndRow = MAXROW;
278 bRet = sal_True;
279 }
280 }
281 else if ( nCount == 2 )
282 {
283 if ( pData[0].bMarked )
284 {
285 rStartRow = 0;
286 rEndRow = pData[0].nRow;
287 }
288 else
289 {
290 rStartRow = pData[0].nRow + 1;
291 rEndRow = MAXROW;
292 }
293 bRet = sal_True;
294 }
295 else if ( nCount == 3 )
296 {
297 if ( pData[1].bMarked )
298 {
299 rStartRow = pData[0].nRow + 1;
300 rEndRow = pData[1].nRow;
301 bRet = sal_True;
302 }
303 }
304 return bRet;
305 }
306
CopyMarksTo(ScMarkArray & rDestMarkArray) const307 void ScMarkArray::CopyMarksTo( ScMarkArray& rDestMarkArray ) const
308 {
309 delete[] rDestMarkArray.pData;
310
311 if (pData)
312 {
313 rDestMarkArray.pData = new ScMarkEntry[nCount];
314 memmove( rDestMarkArray.pData, pData, nCount * sizeof(ScMarkEntry) );
315 }
316 else
317 rDestMarkArray.pData = NULL;
318
319 rDestMarkArray.nCount = rDestMarkArray.nLimit = nCount;
320 }
321
GetNextMarked(SCsROW nRow,sal_Bool bUp) const322 SCsROW ScMarkArray::GetNextMarked( SCsROW nRow, sal_Bool bUp ) const
323 {
324 if (!pData)
325 const_cast<ScMarkArray*>(this)->Reset(sal_False); // create pData for further processing
326
327 SCsROW nRet = nRow;
328 if (VALIDROW(nRow))
329 {
330 SCSIZE nIndex;
331 Search(nRow, nIndex);
332 if (!pData[nIndex].bMarked)
333 {
334 if (bUp)
335 {
336 if (nIndex>0)
337 nRet = pData[nIndex-1].nRow;
338 else
339 nRet = -1;
340 }
341 else
342 nRet = pData[nIndex].nRow + 1;
343 }
344 }
345 return nRet;
346 }
347
GetMarkEnd(SCROW nRow,sal_Bool bUp) const348 SCROW ScMarkArray::GetMarkEnd( SCROW nRow, sal_Bool bUp ) const
349 {
350 if (!pData)
351 const_cast<ScMarkArray*>(this)->Reset(sal_False); // create pData for further processing
352
353 SCROW nRet;
354 SCSIZE nIndex;
355 Search(nRow, nIndex);
356 DBG_ASSERT( pData[nIndex].bMarked, "GetMarkEnd ohne bMarked" );
357 if (bUp)
358 {
359 if (nIndex>0)
360 nRet = pData[nIndex-1].nRow + 1;
361 else
362 nRet = 0;
363 }
364 else
365 nRet = pData[nIndex].nRow;
366
367 return nRet;
368 }
369
370 //
371 // -------------- Iterator ----------------------------------------------
372 //
373
ScMarkArrayIter(const ScMarkArray * pNewArray)374 ScMarkArrayIter::ScMarkArrayIter( const ScMarkArray* pNewArray ) :
375 pArray( pNewArray ),
376 nPos( 0 )
377 {
378 }
379
~ScMarkArrayIter()380 ScMarkArrayIter::~ScMarkArrayIter()
381 {
382 }
383
Next(SCROW & rTop,SCROW & rBottom)384 sal_Bool ScMarkArrayIter::Next( SCROW& rTop, SCROW& rBottom )
385 {
386 if ( nPos >= pArray->nCount )
387 return sal_False;
388 while (!pArray->pData[nPos].bMarked)
389 {
390 ++nPos;
391 if ( nPos >= pArray->nCount )
392 return sal_False;
393 }
394 rBottom = pArray->pData[nPos].nRow;
395 if (nPos==0)
396 rTop = 0;
397 else
398 rTop = pArray->pData[nPos-1].nRow + 1;
399 ++nPos;
400 return sal_True;
401 }
402
403
404
405
406
407