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