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