xref: /trunk/main/sc/source/core/data/markarr.cxx (revision b3f79822)
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