xref: /aoo41x/main/sc/source/core/data/markarr.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 // INCLUDE ---------------------------------------------------------------
34 
35 #include <tools/debug.hxx>
36 
37 #include "markarr.hxx"
38 #include "global.hxx"
39 #include "address.hxx"
40 
41 // STATIC DATA -----------------------------------------------------------
42 
43 //------------------------------------------------------------------------
44 
45 ScMarkArray::ScMarkArray() :
46     nCount( 0 ),
47     nLimit( 0 ),
48     pData( NULL )
49 {
50     // special case "no marks" with pData = NULL
51 }
52 
53 //------------------------------------------------------------------------
54 
55 ScMarkArray::~ScMarkArray()
56 {
57     delete[] pData;
58 }
59 
60 //------------------------------------------------------------------------
61 
62 void ScMarkArray::Reset( sal_Bool bMarked )
63 {
64     // always create pData here
65     // (or have separate method to ensure pData)
66 
67     delete[] pData;
68 
69     nCount = nLimit = 1;
70     pData = new ScMarkEntry[1];
71     pData[0].nRow = MAXROW;
72     pData[0].bMarked = bMarked;
73 }
74 
75 //------------------------------------------------------------------------
76 
77 sal_Bool ScMarkArray::Search( SCROW nRow, SCSIZE& nIndex ) const
78 {
79 	long	nLo 		= 0;
80 	long	nHi 		= static_cast<long>(nCount) - 1;
81 	long	nStartRow	= 0;
82 	long	nEndRow 	= 0;
83 	long	i			= 0;
84 	sal_Bool	bFound		= (nCount == 1);
85 	if (pData)
86 	{
87 		while ( !bFound && nLo <= nHi )
88 		{
89 			i = (nLo + nHi) / 2;
90 			if (i > 0)
91 				nStartRow = (long) pData[i - 1].nRow;
92 			else
93 				nStartRow = -1;
94 			nEndRow = (long) pData[i].nRow;
95 			if (nEndRow < (long) nRow)
96 				nLo = ++i;
97 			else
98 				if (nStartRow >= (long) nRow)
99 					nHi = --i;
100 				else
101 					bFound = sal_True;
102 		}
103 	}
104 	else
105 		bFound = sal_False;
106 
107 	if (bFound)
108 		nIndex=(SCSIZE)i;
109 	else
110 		nIndex=0;
111 	return bFound;
112 }
113 
114 sal_Bool ScMarkArray::GetMark( SCROW nRow ) const
115 {
116 	SCSIZE i;
117 	if (Search( nRow, i ))
118 		return pData[i].bMarked;
119 	else
120 		return sal_False;
121 
122 }
123 
124 //------------------------------------------------------------------------
125 
126 void ScMarkArray::SetMarkArea( SCROW nStartRow, SCROW nEndRow, sal_Bool bMarked )
127 {
128 	if (ValidRow(nStartRow) && ValidRow(nEndRow))
129 	{
130 		if ((nStartRow == 0) && (nEndRow == MAXROW))
131 		{
132 			Reset(bMarked);
133 		}
134 		else
135 		{
136             if (!pData)
137                 Reset(sal_False);   // create pData for further processing - could use special case handling!
138 
139             SCSIZE nNeeded = nCount + 2;
140             if ( nLimit < nNeeded )
141             {
142                 nLimit += SC_MARKARRAY_DELTA;
143                 if ( nLimit < nNeeded )
144                     nLimit = nNeeded;
145                 ScMarkEntry* pNewData = new ScMarkEntry[nLimit];
146                 memcpy( pNewData, pData, nCount*sizeof(ScMarkEntry) );
147 				delete[] pData;
148 				pData = pNewData;
149             }
150 
151             SCSIZE ni;          // number of entries in beginning
152             SCSIZE nInsert;     // insert position (MAXROW+1 := no insert)
153             sal_Bool bCombined = sal_False;
154             sal_Bool bSplit = sal_False;
155             if ( nStartRow > 0 )
156             {
157                 // skip beginning
158                 SCSIZE nIndex;
159                 Search( nStartRow, nIndex );
160                 ni = nIndex;
161 
162                 nInsert = MAXROWCOUNT;
163                 if ( pData[ni].bMarked != bMarked )
164                 {
165                     if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
166                     {   // may be a split or a simple insert or just a shrink,
167                         // row adjustment is done further down
168                         if ( pData[ni].nRow > nEndRow )
169                             bSplit = sal_True;
170                         ni++;
171                         nInsert = ni;
172                     }
173                     else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
174                         nInsert = ni;
175                 }
176                 if ( ni > 0 && pData[ni-1].bMarked == bMarked )
177                 {   // combine
178                     pData[ni-1].nRow = nEndRow;
179                     nInsert = MAXROWCOUNT;
180                     bCombined = sal_True;
181                 }
182             }
183             else
184 	    {
185                 nInsert = 0;
186                 ni = 0;
187 	    }
188 
189             SCSIZE nj = ni;     // stop position of range to replace
190             while ( nj < nCount && pData[nj].nRow <= nEndRow )
191                 nj++;
192             if ( !bSplit )
193             {
194                 if ( nj < nCount && pData[nj].bMarked == bMarked )
195                 {   // combine
196                     if ( ni > 0 )
197                     {
198                         if ( pData[ni-1].bMarked == bMarked )
199                         {   // adjacent entries
200                             pData[ni-1].nRow = pData[nj].nRow;
201                             nj++;
202                         }
203                         else if ( ni == nInsert )
204                             pData[ni-1].nRow = nStartRow - 1;   // shrink
205                     }
206                     nInsert = MAXROWCOUNT;
207                     bCombined = sal_True;
208                 }
209                 else if ( ni > 0 && ni == nInsert )
210                     pData[ni-1].nRow = nStartRow - 1;   // shrink
211             }
212             if ( ni < nj )
213             {   // remove middle entries
214                 if ( !bCombined )
215                 {   // replace one entry
216                     pData[ni].nRow = nEndRow;
217                     pData[ni].bMarked = bMarked;
218                     ni++;
219                     nInsert = MAXROWCOUNT;
220                 }
221                 if ( ni < nj )
222                 {   // remove entries
223                     memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScMarkEntry) );
224                     nCount -= nj - ni;
225                 }
226             }
227 
228             if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
229             {   // insert or append new entry
230                 if ( nInsert <= nCount )
231                 {
232                     if ( !bSplit )
233                         memmove( pData + nInsert + 1, pData + nInsert,
234                             (nCount - nInsert) * sizeof(ScMarkEntry) );
235                     else
236                     {
237                         memmove( pData + nInsert + 2, pData + nInsert,
238                             (nCount - nInsert) * sizeof(ScMarkEntry) );
239                         pData[nInsert+1] = pData[nInsert-1];
240                         nCount++;
241                     }
242                 }
243                 if ( nInsert )
244                     pData[nInsert-1].nRow = nStartRow - 1;
245                 pData[nInsert].nRow = nEndRow;
246                 pData[nInsert].bMarked = bMarked;
247                 nCount++;
248             }
249 		}
250 	}
251 //	InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
252 }
253 
254 //UNUSED2009-05 void ScMarkArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
255 //UNUSED2009-05 {
256 //UNUSED2009-05     SetMarkArea(nStartRow, nEndRow, sal_False);
257 //UNUSED2009-05 }
258 
259 sal_Bool ScMarkArray::IsAllMarked( SCROW nStartRow, SCROW nEndRow ) const
260 {
261 	SCSIZE nStartIndex;
262 	SCSIZE nEndIndex;
263 
264 	if (Search( nStartRow, nStartIndex ))
265 		if (pData[nStartIndex].bMarked)
266 			if (Search( nEndRow, nEndIndex ))
267 				if (nEndIndex==nStartIndex)
268 					return sal_True;
269 
270 	return sal_False;
271 }
272 
273 sal_Bool ScMarkArray::HasOneMark( SCROW& rStartRow, SCROW& rEndRow ) const
274 {
275 	sal_Bool bRet = sal_False;
276 	if ( nCount == 1 )
277 	{
278 		if ( pData[0].bMarked )
279 		{
280 			rStartRow = 0;
281 			rEndRow = MAXROW;
282 			bRet = sal_True;
283 		}
284 	}
285 	else if ( nCount == 2 )
286 	{
287 		if ( pData[0].bMarked )
288 		{
289 			rStartRow = 0;
290 			rEndRow = pData[0].nRow;
291 		}
292 		else
293 		{
294 			rStartRow = pData[0].nRow + 1;
295 			rEndRow = MAXROW;
296 		}
297 		bRet = sal_True;
298 	}
299 	else if ( nCount == 3 )
300 	{
301 		if ( pData[1].bMarked )
302 		{
303 			rStartRow = pData[0].nRow + 1;
304 			rEndRow = pData[1].nRow;
305 			bRet = sal_True;
306 		}
307 	}
308 	return bRet;
309 }
310 
311 void ScMarkArray::CopyMarksTo( ScMarkArray& rDestMarkArray ) const
312 {
313 	delete[] rDestMarkArray.pData;
314 
315 	if (pData)
316 	{
317 		rDestMarkArray.pData = new ScMarkEntry[nCount];
318 		memmove( rDestMarkArray.pData, pData, nCount * sizeof(ScMarkEntry) );
319 	}
320 	else
321 		rDestMarkArray.pData = NULL;
322 
323     rDestMarkArray.nCount = rDestMarkArray.nLimit = nCount;
324 }
325 
326 SCsROW ScMarkArray::GetNextMarked( SCsROW nRow, sal_Bool bUp ) const
327 {
328     if (!pData)
329         const_cast<ScMarkArray*>(this)->Reset(sal_False);   // create pData for further processing
330 
331 	SCsROW nRet = nRow;
332 	if (VALIDROW(nRow))
333 	{
334 		SCSIZE nIndex;
335 		Search(nRow, nIndex);
336 		if (!pData[nIndex].bMarked)
337 		{
338 			if (bUp)
339 			{
340 				if (nIndex>0)
341 					nRet = pData[nIndex-1].nRow;
342 				else
343 					nRet = -1;
344 			}
345 			else
346 				nRet = pData[nIndex].nRow + 1;
347 		}
348 	}
349 	return nRet;
350 }
351 
352 SCROW ScMarkArray::GetMarkEnd( SCROW nRow, sal_Bool bUp ) const
353 {
354     if (!pData)
355         const_cast<ScMarkArray*>(this)->Reset(sal_False);   // create pData for further processing
356 
357 	SCROW nRet;
358 	SCSIZE nIndex;
359 	Search(nRow, nIndex);
360 	DBG_ASSERT( pData[nIndex].bMarked, "GetMarkEnd ohne bMarked" );
361 	if (bUp)
362 	{
363 		if (nIndex>0)
364 			nRet = pData[nIndex-1].nRow + 1;
365 		else
366 			nRet = 0;
367 	}
368 	else
369 		nRet = pData[nIndex].nRow;
370 
371 	return nRet;
372 }
373 
374 //
375 //	-------------- Iterator ----------------------------------------------
376 //
377 
378 ScMarkArrayIter::ScMarkArrayIter( const ScMarkArray* pNewArray ) :
379 	pArray( pNewArray ),
380 	nPos( 0 )
381 {
382 }
383 
384 ScMarkArrayIter::~ScMarkArrayIter()
385 {
386 }
387 
388 sal_Bool ScMarkArrayIter::Next( SCROW& rTop, SCROW& rBottom )
389 {
390 	if ( nPos >= pArray->nCount )
391 		return sal_False;
392 	while (!pArray->pData[nPos].bMarked)
393 	{
394 		++nPos;
395 		if ( nPos >= pArray->nCount )
396 			return sal_False;
397 	}
398 	rBottom = pArray->pData[nPos].nRow;
399 	if (nPos==0)
400 		rTop = 0;
401 	else
402 		rTop = pArray->pData[nPos-1].nRow + 1;
403 	++nPos;
404 	return sal_True;
405 }
406 
407 
408 
409 
410 
411