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