xref: /trunk/main/sc/source/core/tool/collect.cxx (revision b3f79822)
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