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