xref: /trunk/main/sc/source/core/tool/collect.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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 <string.h>
34 #include <tools/stream.hxx>
35 #include <unotools/transliterationwrapper.hxx>
36 
37 #include "rechead.hxx"
38 #include "collect.hxx"
39 #include "document.hxx"         // fuer TypedStrData Konstruktor
40 
41 // -----------------------------------------------------------------------
42 
43 ScDataObject::~ScDataObject()
44 {
45 }
46 
47 //------------------------------------------------------------------------
48 // Collection
49 //------------------------------------------------------------------------
50 
51 void lcl_DeleteScDataObjects( ScDataObject** p, sal_uInt16 nCount )
52 {
53     if ( p )
54     {
55         for (sal_uInt16 i = 0; i < nCount; i++) delete p[i];
56         delete[] p;
57         p = NULL;
58     }
59 }
60 
61 ScCollection::ScCollection(sal_uInt16 nLim, sal_uInt16 nDel) :
62     nCount ( 0 ),
63     nLimit ( nLim ),
64     nDelta ( nDel ),
65     pItems ( NULL )
66 {
67     if (nDelta > MAXDELTA)
68         nDelta = MAXDELTA;
69     else if (nDelta == 0)
70         nDelta = 1;
71     if (nLimit > MAXCOLLECTIONSIZE)
72         nLimit = MAXCOLLECTIONSIZE;
73     else if (nLimit < nDelta)
74         nLimit = nDelta;
75     pItems = new ScDataObject*[nLimit];
76 }
77 
78 ScCollection::ScCollection(const ScCollection& rCollection)
79     :   ScDataObject(),
80         nCount ( 0 ),
81         nLimit ( 0 ),
82         nDelta ( 0 ),
83         pItems ( NULL )
84 {
85     *this = rCollection;
86 }
87 
88 //------------------------------------------------------------------------
89 
90 ScCollection::~ScCollection()
91 {
92     lcl_DeleteScDataObjects( pItems, nCount );
93 }
94 
95 //------------------------------------------------------------------------
96 sal_uInt16 ScCollection::GetCount() const { return nCount; }
97 void ScCollection::AtFree(sal_uInt16 nIndex)
98 {
99     if ((pItems) && (nIndex < nCount))
100     {
101         delete pItems[nIndex];
102         --nCount;               // before memmove
103         memmove ( &pItems[nIndex], &pItems[nIndex + 1], (nCount - nIndex) * sizeof(ScDataObject*));
104         pItems[nCount] = NULL;
105     }
106 }
107 
108 //------------------------------------------------------------------------
109 
110 void ScCollection::Free(ScDataObject* pScDataObject)
111 {
112     AtFree(IndexOf(pScDataObject));
113 }
114 
115 //------------------------------------------------------------------------
116 
117 void ScCollection::FreeAll()
118 {
119     lcl_DeleteScDataObjects( pItems, nCount );
120     nCount = 0;
121     pItems = new ScDataObject*[nLimit];
122 }
123 
124 //------------------------------------------------------------------------
125 
126 sal_Bool ScCollection::AtInsert(sal_uInt16 nIndex, ScDataObject* pScDataObject)
127 {
128     if ((nCount < MAXCOLLECTIONSIZE) && (nIndex <= nCount) && pItems)
129     {
130         if (nCount == nLimit)
131         {
132             ScDataObject** pNewItems = new ScDataObject*[nLimit + nDelta];
133             if (!pNewItems)
134                 return sal_False;
135             nLimit = sal::static_int_cast<sal_uInt16>( nLimit + nDelta );
136             memmove(pNewItems, pItems, nCount * sizeof(ScDataObject*));
137             delete[] pItems;
138             pItems = pNewItems;
139         }
140         if (nCount > nIndex)
141             memmove(&pItems[nIndex + 1], &pItems[nIndex], (nCount - nIndex) * sizeof(ScDataObject*));
142         pItems[nIndex] = pScDataObject;
143         nCount++;
144         return sal_True;
145     }
146     return sal_False;
147 }
148 
149 //------------------------------------------------------------------------
150 
151 sal_Bool ScCollection::Insert(ScDataObject* pScDataObject)
152 {
153     return AtInsert(nCount, pScDataObject);
154 }
155 
156 //------------------------------------------------------------------------
157 
158 ScDataObject* ScCollection::At(sal_uInt16 nIndex) const
159 {
160     if (nIndex < nCount)
161         return pItems[nIndex];
162     else
163         return NULL;
164 }
165 
166 //------------------------------------------------------------------------
167 
168 sal_uInt16 ScCollection::IndexOf(ScDataObject* pScDataObject) const
169 {
170     sal_uInt16 nIndex = 0xffff;
171     for (sal_uInt16 i = 0; ((i < nCount) && (nIndex == 0xffff)); i++)
172     {
173         if (pItems[i] == pScDataObject) nIndex = i;
174     }
175     return nIndex;
176 }
177 
178 //------------------------------------------------------------------------
179 
180 ScCollection& ScCollection::operator=( const ScCollection& r )
181 {
182     lcl_DeleteScDataObjects( pItems, nCount );
183 
184     nCount = r.nCount;
185     nLimit = r.nLimit;
186     nDelta = r.nDelta;
187     pItems = new ScDataObject*[nLimit];
188     for ( sal_uInt16 i=0; i<nCount; i++ )
189         pItems[i] = r.pItems[i]->Clone();
190 
191     return *this;
192 }
193 
194 //------------------------------------------------------------------------
195 
196 ScDataObject*   ScCollection::Clone() const
197 {
198     return new ScCollection(*this);
199 }
200 
201 //------------------------------------------------------------------------
202 // ScSortedCollection
203 //------------------------------------------------------------------------
204 
205 ScSortedCollection::ScSortedCollection(sal_uInt16 nLim, sal_uInt16 nDel, sal_Bool bDup) :
206     ScCollection (nLim, nDel),
207     bDuplicates ( bDup)
208 {
209 }
210 
211 //------------------------------------------------------------------------
212 
213 sal_uInt16 ScSortedCollection::IndexOf(ScDataObject* pScDataObject) const
214 {
215     sal_uInt16 nIndex;
216     if (Search(pScDataObject, nIndex))
217         return nIndex;
218     else
219         return 0xffff;
220 }
221 
222 //------------------------------------------------------------------------
223 
224 sal_Bool ScSortedCollection::Search(ScDataObject* pScDataObject, sal_uInt16& rIndex) const
225 {
226     rIndex = nCount;
227     sal_Bool bFound = sal_False;
228     short nLo = 0;
229     short nHi = nCount - 1;
230     short nIndex;
231     short nCompare;
232     while (nLo <= nHi)
233     {
234         nIndex = (nLo + nHi) / 2;
235         nCompare = Compare(pItems[nIndex], pScDataObject);
236         if (nCompare < 0)
237             nLo = nIndex + 1;
238         else
239         {
240             nHi = nIndex - 1;
241             if (nCompare == 0)
242             {
243                 bFound = sal_True;
244                 nLo = nIndex;
245             }
246         }
247     }
248     rIndex = nLo;
249     return bFound;
250 }
251 
252 //------------------------------------------------------------------------
253 
254 sal_Bool ScSortedCollection::Insert(ScDataObject* pScDataObject)
255 {
256     sal_uInt16 nIndex;
257     sal_Bool bFound = Search(pScDataObject, nIndex);
258     if (bFound)
259     {
260         if (bDuplicates)
261             return AtInsert(nIndex, pScDataObject);
262         else
263             return sal_False;
264     }
265     else
266         return AtInsert(nIndex, pScDataObject);
267 }
268 
269 //------------------------------------------------------------------------
270 
271 sal_Bool ScSortedCollection::InsertPos(ScDataObject* pScDataObject, sal_uInt16& nIndex)
272 {
273     sal_Bool bFound = Search(pScDataObject, nIndex);
274     if (bFound)
275     {
276         if (bDuplicates)
277             return AtInsert(nIndex, pScDataObject);
278         else
279             return sal_False;
280     }
281     else
282         return AtInsert(nIndex, pScDataObject);
283 }
284 
285 //------------------------------------------------------------------------
286 
287 sal_Bool ScSortedCollection::operator==(const ScSortedCollection& rCmp) const
288 {
289     if ( nCount != rCmp.nCount )
290         return sal_False;
291     for (sal_uInt16 i=0; i<nCount; i++)
292         if ( !IsEqual(pItems[i],rCmp.pItems[i]) )
293             return sal_False;
294     return sal_True;
295 }
296 
297 //------------------------------------------------------------------------
298 
299 //  IsEqual - komplette Inhalte vergleichen
300 
301 sal_Bool ScSortedCollection::IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const
302 {
303     return ( Compare(pKey1, pKey2) == 0 );      // Default: nur Index vergleichen
304 }
305 
306 //------------------------------------------------------------------------
307 
308 ScDataObject*   StrData::Clone() const
309 {
310     return new StrData(*this);
311 }
312 
313 //------------------------------------------------------------------------
314 
315 short ScStrCollection::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
316 {
317     StringCompare eComp = ((StrData*)pKey1)->aStr.CompareTo(((StrData*)pKey2)->aStr);
318     if (eComp == COMPARE_EQUAL)
319         return 0;
320     else if (eComp == COMPARE_LESS)
321         return -1;
322     else
323         return 1;
324 }
325 
326 //------------------------------------------------------------------------
327 
328 ScDataObject*   ScStrCollection::Clone() const
329 {
330     return new ScStrCollection(*this);
331 }
332 
333 //------------------------------------------------------------------------
334 // TypedScStrCollection
335 //------------------------------------------------------------------------
336 
337 //UNUSED2008-05  TypedStrData::TypedStrData( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab,
338 //UNUSED2008-05                                  sal_Bool bAllStrings )
339 //UNUSED2008-05  {
340 //UNUSED2008-05      if ( pDoc->HasValueData( nCol, nRow, nTab ) )
341 //UNUSED2008-05      {
342 //UNUSED2008-05          pDoc->GetValue( nCol, nRow, nTab, nValue );
343 //UNUSED2008-05          if (bAllStrings)
344 //UNUSED2008-05              pDoc->GetString( nCol, nRow, nTab, aStrValue );
345 //UNUSED2008-05          nStrType = 0;
346 //UNUSED2008-05      }
347 //UNUSED2008-05      else
348 //UNUSED2008-05      {
349 //UNUSED2008-05          pDoc->GetString( nCol, nRow, nTab, aStrValue );
350 //UNUSED2008-05          nValue = 0.0;
351 //UNUSED2008-05          nStrType = 1;       //! Typ uebergeben ?
352 //UNUSED2008-05      }
353 //UNUSED2008-05  }
354 
355 
356 ScDataObject*   TypedStrData::Clone() const
357 {
358     return new TypedStrData(*this);
359 }
360 
361 TypedScStrCollection::TypedScStrCollection( sal_uInt16 nLim , sal_uInt16 nDel , sal_Bool bDup  )
362     : ScSortedCollection( nLim, nDel, bDup )
363 {
364     bCaseSensitive = sal_False;
365 }
366 
367 TypedScStrCollection::~TypedScStrCollection()
368 {}
369 ScDataObject* TypedScStrCollection::Clone() const
370 {
371     return new TypedScStrCollection(*this);
372 }
373 
374 TypedStrData*    TypedScStrCollection::operator[]( const sal_uInt16 nIndex) const
375 {
376     return (TypedStrData*)At(nIndex);
377 }
378 
379 void    TypedScStrCollection::SetCaseSensitive( sal_Bool bSet )
380 {
381     bCaseSensitive = bSet;
382 }
383 
384 short TypedScStrCollection::Compare( ScDataObject* pKey1, ScDataObject* pKey2 ) const
385 {
386     short nResult = 0;
387 
388     if ( pKey1 && pKey2 )
389     {
390         TypedStrData& rData1 = (TypedStrData&)*pKey1;
391         TypedStrData& rData2 = (TypedStrData&)*pKey2;
392 
393         if ( rData1.nStrType > rData2.nStrType )
394             nResult = 1;
395         else if ( rData1.nStrType < rData2.nStrType )
396             nResult = -1;
397         else if ( !rData1.nStrType /* && !rData2.nStrType */ )
398         {
399             //--------------------
400             // Zahlen vergleichen:
401             //--------------------
402             if ( rData1.nValue == rData2.nValue )
403                 nResult = 0;
404             else if ( rData1.nValue < rData2.nValue )
405                 nResult = -1;
406             else
407                 nResult = 1;
408         }
409         else /* if ( rData1.nStrType && rData2.nStrType ) */
410         {
411             //---------------------
412             // Strings vergleichen:
413             //---------------------
414             if ( bCaseSensitive )
415                 nResult = (short) ScGlobal::GetCaseTransliteration()->compareString(
416                     rData1.aStrValue, rData2.aStrValue );
417             else
418                 nResult = (short) ScGlobal::GetpTransliteration()->compareString(
419                     rData1.aStrValue, rData2.aStrValue );
420         }
421     }
422 
423     return nResult;
424 }
425 
426 sal_Bool TypedScStrCollection::FindText( const String& rStart, String& rResult,
427                                     sal_uInt16& rPos, sal_Bool bBack ) const
428 {
429     //  Die Collection ist nach String-Vergleichen sortiert, darum muss hier
430     //  alles durchsucht werden
431 
432     sal_Bool bFound = sal_False;
433 
434     String aOldResult;
435     if ( rPos != SCPOS_INVALID && rPos < nCount )
436     {
437         TypedStrData* pData = (TypedStrData*) pItems[rPos];
438         if (pData->nStrType)
439             aOldResult = pData->aStrValue;
440     }
441 
442     if ( bBack )                                    // rueckwaerts
443     {
444         sal_uInt16 nStartPos = nCount;
445         if ( rPos != SCPOS_INVALID )
446             nStartPos = rPos;                       // weitersuchen...
447 
448         for ( sal_uInt16 i=nStartPos; i>0; )
449         {
450             --i;
451             TypedStrData* pData = (TypedStrData*) pItems[i];
452             if (pData->nStrType)
453             {
454                 if ( ScGlobal::GetpTransliteration()->isMatch( rStart, pData->aStrValue ) )
455                 {
456                     //  If the collection is case sensitive, it may contain several entries
457                     //  that are equal when compared case-insensitive. They are skipped here.
458                     if ( !bCaseSensitive || !aOldResult.Len() ||
459                             !ScGlobal::GetpTransliteration()->isEqual(
460                             pData->aStrValue, aOldResult ) )
461                     {
462                         rResult = pData->aStrValue;
463                         rPos = i;
464                         bFound = sal_True;
465                         break;
466                     }
467                 }
468             }
469         }
470     }
471     else                                            // vorwaerts
472     {
473         sal_uInt16 nStartPos = 0;
474         if ( rPos != SCPOS_INVALID )
475             nStartPos = rPos + 1;                   // weitersuchen...
476 
477         for ( sal_uInt16 i=nStartPos; i<nCount; i++ )
478         {
479             TypedStrData* pData = (TypedStrData*) pItems[i];
480             if (pData->nStrType)
481             {
482                 if ( ScGlobal::GetpTransliteration()->isMatch( rStart, pData->aStrValue ) )
483                 {
484                     //  If the collection is case sensitive, it may contain several entries
485                     //  that are equal when compared case-insensitive. They are skipped here.
486                     if ( !bCaseSensitive || !aOldResult.Len() ||
487                             !ScGlobal::GetpTransliteration()->isEqual(
488                             pData->aStrValue, aOldResult ) )
489                     {
490                         rResult = pData->aStrValue;
491                         rPos = i;
492                         bFound = sal_True;
493                         break;
494                     }
495                 }
496             }
497         }
498     }
499 
500     return bFound;
501 }
502 
503         // Gross-/Kleinschreibung anpassen
504 
505 sal_Bool TypedScStrCollection::GetExactMatch( String& rString ) const
506 {
507     for (sal_uInt16 i=0; i<nCount; i++)
508     {
509         TypedStrData* pData = (TypedStrData*) pItems[i];
510         if ( pData->nStrType && ScGlobal::GetpTransliteration()->isEqual(
511                 pData->aStrValue, rString ) )
512         {
513             rString = pData->aStrValue;                         // String anpassen
514             return sal_True;
515         }
516     }
517 
518     return sal_False;
519 }
520 
521 
522 
523