Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "rangeutl.hxx"
21 : #include "document.hxx"
22 : #include "global.hxx"
23 : #include "dbdata.hxx"
24 : #include "rangenam.hxx"
25 : #include "scresid.hxx"
26 : #include "globstr.hrc"
27 : #include "convuno.hxx"
28 : #include "externalrefmgr.hxx"
29 : #include "compiler.hxx"
30 :
31 : using ::rtl::OUString;
32 : using ::rtl::OUStringBuffer;
33 : using ::formula::FormulaGrammar;
34 : using namespace ::com::sun::star;
35 :
36 : //------------------------------------------------------------------------
37 :
38 0 : sal_Bool ScRangeUtil::MakeArea( const String& rAreaStr,
39 : ScArea& rArea,
40 : ScDocument* pDoc,
41 : SCTAB nTab,
42 : ScAddress::Details const & rDetails ) const
43 : {
44 : // Input in rAreaStr: "$Tabelle1.$A1:$D17"
45 :
46 : // BROKEN BROKEN BROKEN
47 : // but it is only used in the consolidate dialog. Ignore for now.
48 :
49 0 : sal_Bool nSuccess = false;
50 0 : sal_uInt16 nPointPos = rAreaStr.Search('.');
51 0 : sal_uInt16 nColonPos = rAreaStr.Search(':');
52 0 : String aStrArea( rAreaStr );
53 0 : ScRefAddress startPos;
54 0 : ScRefAddress endPos;
55 :
56 0 : if ( nColonPos == STRING_NOTFOUND )
57 0 : if ( nPointPos != STRING_NOTFOUND )
58 : {
59 0 : aStrArea += ':';
60 0 : aStrArea += rAreaStr.Copy( nPointPos+1 ); // do not include '.' in copy
61 : }
62 :
63 0 : nSuccess = ConvertDoubleRef( pDoc, aStrArea, nTab, startPos, endPos, rDetails );
64 :
65 0 : if ( nSuccess )
66 0 : rArea = ScArea( startPos.Tab(),
67 0 : startPos.Col(), startPos.Row(),
68 0 : endPos.Col(), endPos.Row() );
69 :
70 0 : return nSuccess;
71 : }
72 :
73 : //------------------------------------------------------------------------
74 :
75 0 : void ScRangeUtil::CutPosString( const String& theAreaStr,
76 : String& thePosStr ) const
77 : {
78 0 : String aPosStr;
79 : // BROKEN BROKEN BROKEN
80 : // but it is only used in the consolidate dialog. Ignore for now.
81 :
82 0 : sal_uInt16 nColonPos = theAreaStr.Search(':');
83 :
84 0 : if ( nColonPos != STRING_NOTFOUND )
85 0 : aPosStr = theAreaStr.Copy( 0, nColonPos ); // do not include ':' in copy
86 : else
87 0 : aPosStr = theAreaStr;
88 :
89 0 : thePosStr = aPosStr;
90 0 : }
91 :
92 : //------------------------------------------------------------------------
93 :
94 0 : sal_Bool ScRangeUtil::IsAbsTabArea( const String& rAreaStr,
95 : ScDocument* pDoc,
96 : ScArea*** pppAreas,
97 : sal_uInt16* pAreaCount,
98 : sal_Bool /* bAcceptCellRef */,
99 : ScAddress::Details const & rDetails ) const
100 : {
101 : OSL_ENSURE( pDoc, "Kein Dokument uebergeben!" );
102 0 : if ( !pDoc )
103 0 : return false;
104 :
105 : // BROKEN BROKEN BROKEN
106 : // but it is only used in the consolidate dialog. Ignore for now.
107 :
108 : /*
109 : * Expects strings like:
110 : * "$Tabelle1.$A$1:$Tabelle3.$D$17"
111 : * If bAcceptCellRef == sal_True then also accept strings like:
112 : * "$Tabelle1.$A$1"
113 : *
114 : * as result a ScArea-Array is created,
115 : * which is published via ppAreas and also has to be deleted this route.
116 : */
117 :
118 0 : sal_Bool bStrOk = false;
119 0 : String aTempAreaStr(rAreaStr);
120 0 : String aStartPosStr;
121 0 : String aEndPosStr;
122 :
123 0 : if ( STRING_NOTFOUND == aTempAreaStr.Search(':') )
124 : {
125 0 : aTempAreaStr.Append(':');
126 0 : aTempAreaStr.Append(rAreaStr);
127 : }
128 :
129 0 : sal_uInt16 nColonPos = aTempAreaStr.Search(':');
130 :
131 0 : if ( STRING_NOTFOUND != nColonPos
132 0 : && STRING_NOTFOUND != aTempAreaStr.Search('.') )
133 : {
134 0 : ScRefAddress aStartPos;
135 0 : ScRefAddress aEndPos;
136 :
137 0 : aStartPosStr = aTempAreaStr.Copy( 0, nColonPos );
138 0 : aEndPosStr = aTempAreaStr.Copy( nColonPos+1, STRING_LEN );
139 :
140 0 : if ( ConvertSingleRef( pDoc, aStartPosStr, 0, aStartPos, rDetails ) )
141 : {
142 0 : if ( ConvertSingleRef( pDoc, aEndPosStr, aStartPos.Tab(), aEndPos, rDetails ) )
143 : {
144 0 : aStartPos.SetRelCol( false );
145 0 : aStartPos.SetRelRow( false );
146 0 : aStartPos.SetRelTab( false );
147 0 : aEndPos.SetRelCol( false );
148 0 : aEndPos.SetRelRow( false );
149 0 : aEndPos.SetRelTab( false );
150 :
151 0 : bStrOk = sal_True;
152 :
153 0 : if ( pppAreas && pAreaCount ) // Array returned ?
154 : {
155 0 : SCTAB nStartTab = aStartPos.Tab();
156 0 : SCTAB nEndTab = aEndPos.Tab();
157 0 : sal_uInt16 nTabCount = static_cast<sal_uInt16>(nEndTab-nStartTab+1);
158 0 : ScArea** theAreas = new ScArea*[nTabCount];
159 0 : SCTAB nTab = 0;
160 0 : sal_uInt16 i = 0;
161 0 : ScArea theArea( 0, aStartPos.Col(), aStartPos.Row(),
162 0 : aEndPos.Col(), aEndPos.Row() );
163 :
164 0 : nTab = nStartTab;
165 0 : for ( i=0; i<nTabCount; i++ )
166 : {
167 0 : theAreas[i] = new ScArea( theArea );
168 0 : theAreas[i]->nTab = nTab;
169 0 : nTab++;
170 : }
171 0 : *pppAreas = theAreas;
172 0 : *pAreaCount = nTabCount;
173 : }
174 : }
175 : }
176 : }
177 :
178 0 : return bStrOk;
179 : }
180 :
181 : //------------------------------------------------------------------------
182 :
183 0 : sal_Bool ScRangeUtil::IsAbsArea( const String& rAreaStr,
184 : ScDocument* pDoc,
185 : SCTAB nTab,
186 : String* pCompleteStr,
187 : ScRefAddress* pStartPos,
188 : ScRefAddress* pEndPos,
189 : ScAddress::Details const & rDetails ) const
190 : {
191 0 : sal_Bool bIsAbsArea = false;
192 0 : ScRefAddress startPos;
193 0 : ScRefAddress endPos;
194 :
195 0 : bIsAbsArea = ConvertDoubleRef( pDoc, rAreaStr, nTab, startPos, endPos, rDetails );
196 :
197 0 : if ( bIsAbsArea )
198 : {
199 0 : startPos.SetRelCol( false );
200 0 : startPos.SetRelRow( false );
201 0 : startPos.SetRelTab( false );
202 0 : endPos .SetRelCol( false );
203 0 : endPos .SetRelRow( false );
204 0 : endPos .SetRelTab( false );
205 :
206 0 : if ( pCompleteStr )
207 : {
208 0 : *pCompleteStr = startPos.GetRefString( pDoc, MAXTAB+1, rDetails );
209 0 : *pCompleteStr += ':';
210 0 : *pCompleteStr += endPos .GetRefString( pDoc, nTab, rDetails );
211 : }
212 :
213 0 : if ( pStartPos && pEndPos )
214 : {
215 0 : *pStartPos = startPos;
216 0 : *pEndPos = endPos;
217 : }
218 : }
219 :
220 0 : return bIsAbsArea;
221 : }
222 :
223 : //------------------------------------------------------------------------
224 :
225 0 : sal_Bool ScRangeUtil::IsAbsPos( const String& rPosStr,
226 : ScDocument* pDoc,
227 : SCTAB nTab,
228 : String* pCompleteStr,
229 : ScRefAddress* pPosTripel,
230 : ScAddress::Details const & rDetails ) const
231 : {
232 0 : sal_Bool bIsAbsPos = false;
233 0 : ScRefAddress thePos;
234 :
235 0 : bIsAbsPos = ConvertSingleRef( pDoc, rPosStr, nTab, thePos, rDetails );
236 0 : thePos.SetRelCol( false );
237 0 : thePos.SetRelRow( false );
238 0 : thePos.SetRelTab( false );
239 :
240 0 : if ( bIsAbsPos )
241 : {
242 0 : if ( pPosTripel )
243 0 : *pPosTripel = thePos;
244 0 : if ( pCompleteStr )
245 0 : *pCompleteStr = thePos.GetRefString( pDoc, MAXTAB+1, rDetails );
246 : }
247 :
248 0 : return bIsAbsPos;
249 : }
250 :
251 : //------------------------------------------------------------------------
252 :
253 0 : sal_Bool ScRangeUtil::MakeRangeFromName (
254 : const String& rName,
255 : ScDocument* pDoc,
256 : SCTAB nCurTab,
257 : ScRange& rRange,
258 : RutlNameScope eScope,
259 : ScAddress::Details const & rDetails ) const
260 : {
261 0 : sal_Bool bResult=false;
262 0 : ScRangeUtil aRangeUtil;
263 0 : SCTAB nTab = 0;
264 0 : SCCOL nColStart = 0;
265 0 : SCCOL nColEnd = 0;
266 0 : SCROW nRowStart = 0;
267 0 : SCROW nRowEnd = 0;
268 :
269 0 : if( eScope==RUTL_NAMES )
270 : {
271 : //first handle ui names like local1 (Sheet1), which point to a local range name
272 0 : rtl::OUString aName(rName);
273 0 : sal_Int32 nEndPos = aName.lastIndexOf(')');
274 0 : sal_Int32 nStartPos = aName.lastIndexOfAsciiL(" (",2);
275 0 : SCTAB nTable = nCurTab;
276 0 : if (nEndPos != -1 && nStartPos != -1)
277 : {
278 0 : rtl::OUString aSheetName = aName.copy(nStartPos+2, nEndPos-nStartPos-2);
279 0 : if (pDoc->GetTable(aSheetName, nTable))
280 : {
281 0 : aName = aName.copy(0, nStartPos);
282 : }
283 : else
284 0 : nTable = nCurTab;
285 : }
286 : //then check for local range names
287 0 : ScRangeName* pRangeNames = pDoc->GetRangeName( nTable );
288 0 : ScRangeData* pData = NULL;
289 0 : if ( pRangeNames )
290 0 : pData = pRangeNames->findByUpperName(ScGlobal::pCharClass->uppercase(aName));
291 0 : if (!pData)
292 0 : pData = pDoc->GetRangeName()->findByUpperName(ScGlobal::pCharClass->uppercase(aName));
293 0 : if (pData)
294 : {
295 0 : String aStrArea;
296 0 : ScRefAddress aStartPos;
297 0 : ScRefAddress aEndPos;
298 :
299 0 : pData->GetSymbol( aStrArea );
300 :
301 0 : if ( IsAbsArea( aStrArea, pDoc, nTable,
302 0 : NULL, &aStartPos, &aEndPos, rDetails ) )
303 : {
304 0 : nTab = aStartPos.Tab();
305 0 : nColStart = aStartPos.Col();
306 0 : nRowStart = aStartPos.Row();
307 0 : nColEnd = aEndPos.Col();
308 0 : nRowEnd = aEndPos.Row();
309 0 : bResult = sal_True;
310 : }
311 : else
312 : {
313 0 : CutPosString( aStrArea, aStrArea );
314 :
315 0 : if ( IsAbsPos( aStrArea, pDoc, nTable,
316 0 : NULL, &aStartPos, rDetails ) )
317 : {
318 0 : nTab = aStartPos.Tab();
319 0 : nColStart = nColEnd = aStartPos.Col();
320 0 : nRowStart = nRowEnd = aStartPos.Row();
321 0 : bResult = sal_True;
322 : }
323 0 : }
324 0 : }
325 : }
326 0 : else if( eScope==RUTL_DBASE )
327 : {
328 0 : ScDBCollection::NamedDBs& rDbNames = pDoc->GetDBCollection()->getNamedDBs();
329 0 : ScDBData* pData = rDbNames.findByUpperName(ScGlobal::pCharClass->uppercase(rName));
330 0 : if (pData)
331 : {
332 0 : pData->GetArea(nTab, nColStart, nRowStart, nColEnd, nRowEnd);
333 0 : bResult = true;
334 : }
335 : }
336 : else
337 : {
338 : OSL_FAIL( "ScRangeUtil::MakeRangeFromName" );
339 : }
340 :
341 0 : if( bResult )
342 : {
343 0 : rRange = ScRange( nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab );
344 : }
345 :
346 0 : return bResult;
347 : }
348 :
349 : //========================================================================
350 :
351 0 : void ScRangeStringConverter::AssignString(
352 : OUString& rString,
353 : const OUString& rNewStr,
354 : sal_Bool bAppendStr,
355 : sal_Unicode cSeperator)
356 : {
357 0 : if( bAppendStr )
358 : {
359 0 : if( !rNewStr.isEmpty() )
360 : {
361 0 : if( !rString.isEmpty() )
362 0 : rString += rtl::OUString(cSeperator);
363 0 : rString += rNewStr;
364 : }
365 : }
366 : else
367 0 : rString = rNewStr;
368 0 : }
369 :
370 124 : sal_Int32 ScRangeStringConverter::IndexOf(
371 : const OUString& rString,
372 : sal_Unicode cSearchChar,
373 : sal_Int32 nOffset,
374 : sal_Unicode cQuote )
375 : {
376 124 : sal_Int32 nLength = rString.getLength();
377 124 : sal_Int32 nIndex = nOffset;
378 124 : sal_Bool bQuoted = false;
379 124 : sal_Bool bExitLoop = false;
380 :
381 2356 : while( !bExitLoop && (nIndex < nLength) )
382 : {
383 2108 : sal_Unicode cCode = rString[ nIndex ];
384 2108 : bExitLoop = (cCode == cSearchChar) && !bQuoted;
385 2108 : bQuoted = (bQuoted != (cCode == cQuote));
386 2108 : if( !bExitLoop )
387 2096 : nIndex++;
388 : }
389 124 : return (nIndex < nLength) ? nIndex : -1;
390 : }
391 :
392 118 : sal_Int32 ScRangeStringConverter::IndexOfDifferent(
393 : const OUString& rString,
394 : sal_Unicode cSearchChar,
395 : sal_Int32 nOffset )
396 : {
397 118 : sal_Int32 nLength = rString.getLength();
398 118 : sal_Int32 nIndex = nOffset;
399 118 : sal_Bool bExitLoop = false;
400 :
401 248 : while( !bExitLoop && (nIndex < nLength) )
402 : {
403 12 : bExitLoop = (rString[ nIndex ] != cSearchChar);
404 12 : if( !bExitLoop )
405 6 : nIndex++;
406 : }
407 118 : return (nIndex < nLength) ? nIndex : -1;
408 : }
409 :
410 201 : void ScRangeStringConverter::GetTokenByOffset(
411 : OUString& rToken,
412 : const OUString& rString,
413 : sal_Int32& nOffset,
414 : sal_Unicode cSeperator,
415 : sal_Unicode cQuote)
416 : {
417 201 : sal_Int32 nLength = rString.getLength();
418 201 : if( nOffset >= nLength )
419 : {
420 83 : rToken = OUString();
421 83 : nOffset = -1;
422 : }
423 : else
424 : {
425 118 : sal_Int32 nTokenEnd = IndexOf( rString, cSeperator, nOffset, cQuote );
426 118 : if( nTokenEnd < 0 )
427 112 : nTokenEnd = nLength;
428 118 : rToken = rString.copy( nOffset, nTokenEnd - nOffset );
429 :
430 118 : sal_Int32 nNextBegin = IndexOfDifferent( rString, cSeperator, nTokenEnd );
431 118 : nOffset = (nNextBegin < 0) ? nLength : nNextBegin;
432 : }
433 201 : }
434 :
435 3 : void ScRangeStringConverter::AppendTableName(OUStringBuffer& rBuf, const OUString& rTabName, sal_Unicode /* cQuote */)
436 : {
437 : // quote character is always "'"
438 3 : String aQuotedTab(rTabName);
439 3 : ScCompiler::CheckTabQuotes(aQuotedTab, ::formula::FormulaGrammar::CONV_OOO);
440 3 : rBuf.append(aQuotedTab);
441 3 : }
442 :
443 0 : sal_Int32 ScRangeStringConverter::GetTokenCount( const OUString& rString, sal_Unicode cSeperator, sal_Unicode cQuote )
444 : {
445 0 : OUString sToken;
446 0 : sal_Int32 nCount = 0;
447 0 : sal_Int32 nOffset = 0;
448 0 : while( nOffset >= 0 )
449 : {
450 0 : GetTokenByOffset( sToken, rString, nOffset, cQuote, cSeperator );
451 0 : if( nOffset >= 0 )
452 0 : nCount++;
453 : }
454 0 : return nCount;
455 : }
456 :
457 : //___________________________________________________________________
458 :
459 23 : sal_Bool ScRangeStringConverter::GetAddressFromString(
460 : ScAddress& rAddress,
461 : const OUString& rAddressStr,
462 : const ScDocument* pDocument,
463 : FormulaGrammar::AddressConvention eConv,
464 : sal_Int32& nOffset,
465 : sal_Unicode cSeperator,
466 : sal_Unicode cQuote )
467 : {
468 23 : OUString sToken;
469 23 : GetTokenByOffset( sToken, rAddressStr, nOffset, cSeperator, cQuote );
470 23 : if( nOffset >= 0 )
471 : {
472 23 : if ((rAddress.Parse( sToken, const_cast<ScDocument*>(pDocument), eConv ) & SCA_VALID) == SCA_VALID)
473 23 : return true;
474 0 : ::formula::FormulaGrammar::AddressConvention eConvUI = pDocument->GetAddressConvention();
475 0 : if (eConv != eConvUI)
476 0 : return ((rAddress.Parse(sToken, const_cast<ScDocument*>(pDocument), eConvUI) & SCA_VALID) == SCA_VALID);
477 : }
478 0 : return false;
479 : }
480 :
481 6 : sal_Bool ScRangeStringConverter::GetRangeFromString(
482 : ScRange& rRange,
483 : const OUString& rRangeStr,
484 : const ScDocument* pDocument,
485 : FormulaGrammar::AddressConvention eConv,
486 : sal_Int32& nOffset,
487 : sal_Unicode cSeperator,
488 : sal_Unicode cQuote )
489 : {
490 6 : OUString sToken;
491 6 : sal_Bool bResult(false);
492 6 : GetTokenByOffset( sToken, rRangeStr, nOffset, cSeperator, cQuote );
493 6 : if( nOffset >= 0 )
494 : {
495 6 : sal_Int32 nIndex = IndexOf( sToken, ':', 0, cQuote );
496 6 : String aUIString(sToken);
497 :
498 6 : if( nIndex < 0 )
499 : {
500 0 : if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
501 0 : aUIString.Erase( 0, 1 );
502 0 : bResult = ((rRange.aStart.Parse( aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
503 0 : ::formula::FormulaGrammar::AddressConvention eConvUI = pDocument->GetAddressConvention();
504 0 : if (!bResult && eConv != eConvUI)
505 : bResult = ((rRange.aStart.Parse(
506 0 : aUIString, const_cast<ScDocument*>(pDocument), eConvUI) & SCA_VALID) == SCA_VALID);
507 0 : rRange.aEnd = rRange.aStart;
508 : }
509 : else
510 : {
511 6 : if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
512 : {
513 0 : aUIString.Erase( 0, 1 );
514 0 : --nIndex;
515 : }
516 :
517 12 : if ( nIndex < aUIString.Len() - 1 &&
518 6 : aUIString.GetChar((xub_StrLen)nIndex + 1) == (sal_Unicode) '.' )
519 0 : aUIString.Erase( (xub_StrLen)nIndex + 1, 1 );
520 :
521 6 : bResult = ((rRange.Parse(aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
522 :
523 : // #i77703# chart ranges in the file format contain both sheet names, even for an external reference sheet.
524 : // This isn't parsed by ScRange, so try to parse the two Addresses then.
525 6 : if (!bResult)
526 : {
527 : bResult = ((rRange.aStart.Parse( aUIString.Copy(0, (xub_StrLen)nIndex), const_cast<ScDocument*>(pDocument),
528 0 : eConv) & SCA_VALID) == SCA_VALID) &&
529 : ((rRange.aEnd.Parse( aUIString.Copy((xub_StrLen)nIndex+1), const_cast<ScDocument*>(pDocument),
530 0 : eConv) & SCA_VALID) == SCA_VALID);
531 :
532 0 : ::formula::FormulaGrammar::AddressConvention eConvUI = pDocument->GetAddressConvention();
533 0 : if (!bResult && eConv != eConvUI)
534 : {
535 : bResult = ((rRange.aStart.Parse( aUIString.Copy(0, (xub_StrLen)nIndex), const_cast<ScDocument*>(pDocument),
536 0 : eConvUI) & SCA_VALID) == SCA_VALID) &&
537 : ((rRange.aEnd.Parse( aUIString.Copy((xub_StrLen)nIndex+1), const_cast<ScDocument*>(pDocument),
538 0 : eConvUI) & SCA_VALID) == SCA_VALID);
539 : }
540 : }
541 6 : }
542 : }
543 6 : return bResult;
544 : }
545 :
546 0 : sal_Bool ScRangeStringConverter::GetRangeListFromString(
547 : ScRangeList& rRangeList,
548 : const OUString& rRangeListStr,
549 : const ScDocument* pDocument,
550 : FormulaGrammar::AddressConvention eConv,
551 : sal_Unicode cSeperator,
552 : sal_Unicode cQuote )
553 : {
554 0 : sal_Bool bRet = sal_True;
555 : OSL_ENSURE( !rRangeListStr.isEmpty(), "ScXMLConverter::GetRangeListFromString - empty string!" );
556 0 : sal_Int32 nOffset = 0;
557 0 : while( nOffset >= 0 )
558 : {
559 0 : ScRange* pRange = new ScRange;
560 0 : if (
561 0 : GetRangeFromString( *pRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) &&
562 : (nOffset >= 0)
563 : )
564 : {
565 0 : rRangeList.push_back( pRange );
566 0 : pRange = NULL;
567 : }
568 0 : else if (nOffset > -1)
569 0 : bRet = false;
570 : //if ownership transferred to rRangeList pRange was NULLed, otherwwise
571 : //delete it
572 0 : delete pRange;
573 : }
574 0 : return bRet;
575 : }
576 :
577 :
578 : //___________________________________________________________________
579 :
580 0 : sal_Bool ScRangeStringConverter::GetAreaFromString(
581 : ScArea& rArea,
582 : const OUString& rRangeStr,
583 : const ScDocument* pDocument,
584 : FormulaGrammar::AddressConvention eConv,
585 : sal_Int32& nOffset,
586 : sal_Unicode cSeperator,
587 : sal_Unicode cQuote )
588 : {
589 0 : ScRange aScRange;
590 0 : sal_Bool bResult(false);
591 0 : if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
592 : {
593 0 : rArea.nTab = aScRange.aStart.Tab();
594 0 : rArea.nColStart = aScRange.aStart.Col();
595 0 : rArea.nRowStart = aScRange.aStart.Row();
596 0 : rArea.nColEnd = aScRange.aEnd.Col();
597 0 : rArea.nRowEnd = aScRange.aEnd.Row();
598 0 : bResult = sal_True;
599 : }
600 0 : return bResult;
601 : }
602 :
603 :
604 : //___________________________________________________________________
605 :
606 2 : sal_Bool ScRangeStringConverter::GetAddressFromString(
607 : table::CellAddress& rAddress,
608 : const OUString& rAddressStr,
609 : const ScDocument* pDocument,
610 : FormulaGrammar::AddressConvention eConv,
611 : sal_Int32& nOffset,
612 : sal_Unicode cSeperator,
613 : sal_Unicode cQuote )
614 : {
615 2 : ScAddress aScAddress;
616 2 : sal_Bool bResult(false);
617 2 : if( GetAddressFromString( aScAddress, rAddressStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
618 : {
619 2 : ScUnoConversion::FillApiAddress( rAddress, aScAddress );
620 2 : bResult = sal_True;
621 : }
622 2 : return bResult;
623 : }
624 :
625 0 : sal_Bool ScRangeStringConverter::GetRangeFromString(
626 : table::CellRangeAddress& rRange,
627 : const OUString& rRangeStr,
628 : const ScDocument* pDocument,
629 : FormulaGrammar::AddressConvention eConv,
630 : sal_Int32& nOffset,
631 : sal_Unicode cSeperator,
632 : sal_Unicode cQuote )
633 : {
634 0 : ScRange aScRange;
635 0 : sal_Bool bResult(false);
636 0 : if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
637 : {
638 0 : ScUnoConversion::FillApiRange( rRange, aScRange );
639 0 : bResult = sal_True;
640 : }
641 0 : return bResult;
642 : }
643 :
644 0 : sal_Bool ScRangeStringConverter::GetRangeListFromString(
645 : uno::Sequence< table::CellRangeAddress >& rRangeSeq,
646 : const OUString& rRangeListStr,
647 : const ScDocument* pDocument,
648 : FormulaGrammar::AddressConvention eConv,
649 : sal_Unicode cSeperator,
650 : sal_Unicode cQuote )
651 : {
652 0 : sal_Bool bRet = sal_True;
653 : OSL_ENSURE( !rRangeListStr.isEmpty(), "ScXMLConverter::GetRangeListFromString - empty string!" );
654 0 : table::CellRangeAddress aRange;
655 0 : sal_Int32 nOffset = 0;
656 0 : while( nOffset >= 0 )
657 : {
658 0 : if( GetRangeFromString( aRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
659 : {
660 0 : rRangeSeq.realloc( rRangeSeq.getLength() + 1 );
661 0 : rRangeSeq[ rRangeSeq.getLength() - 1 ] = aRange;
662 : }
663 : else
664 0 : bRet = false;
665 : }
666 0 : return bRet;
667 : }
668 :
669 :
670 : //___________________________________________________________________
671 :
672 0 : void ScRangeStringConverter::GetStringFromAddress(
673 : OUString& rString,
674 : const ScAddress& rAddress,
675 : const ScDocument* pDocument,
676 : FormulaGrammar::AddressConvention eConv,
677 : sal_Unicode cSeperator,
678 : sal_Bool bAppendStr,
679 : sal_uInt16 nFormatFlags )
680 : {
681 0 : if (pDocument && pDocument->HasTable(rAddress.Tab()))
682 : {
683 0 : String sAddress;
684 0 : rAddress.Format( sAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
685 0 : AssignString( rString, sAddress, bAppendStr, cSeperator );
686 : }
687 0 : }
688 :
689 0 : void ScRangeStringConverter::GetStringFromRange(
690 : OUString& rString,
691 : const ScRange& rRange,
692 : const ScDocument* pDocument,
693 : FormulaGrammar::AddressConvention eConv,
694 : sal_Unicode cSeperator,
695 : sal_Bool bAppendStr,
696 : sal_uInt16 nFormatFlags )
697 : {
698 0 : if (pDocument && pDocument->HasTable(rRange.aStart.Tab()))
699 : {
700 0 : ScAddress aStartAddress( rRange.aStart );
701 0 : ScAddress aEndAddress( rRange.aEnd );
702 0 : String sStartAddress;
703 0 : String sEndAddress;
704 0 : aStartAddress.Format( sStartAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
705 0 : aEndAddress.Format( sEndAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
706 0 : OUString sOUStartAddress( sStartAddress );
707 0 : sOUStartAddress += OUString(':');
708 0 : sOUStartAddress += OUString( sEndAddress );
709 0 : AssignString( rString, sOUStartAddress, bAppendStr, cSeperator );
710 : }
711 0 : }
712 :
713 0 : void ScRangeStringConverter::GetStringFromRangeList(
714 : OUString& rString,
715 : const ScRangeList* pRangeList,
716 : const ScDocument* pDocument,
717 : FormulaGrammar::AddressConvention eConv,
718 : sal_Unicode cSeperator,
719 : sal_uInt16 nFormatFlags )
720 : {
721 0 : OUString sRangeListStr;
722 0 : if( pRangeList )
723 : {
724 0 : for( size_t nIndex = 0, nCount = pRangeList->size(); nIndex < nCount; nIndex++ )
725 : {
726 0 : const ScRange* pRange = (*pRangeList)[nIndex];
727 0 : if( pRange )
728 0 : GetStringFromRange( sRangeListStr, *pRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
729 : }
730 : }
731 0 : rString = sRangeListStr;
732 0 : }
733 :
734 :
735 : //___________________________________________________________________
736 :
737 0 : void ScRangeStringConverter::GetStringFromArea(
738 : OUString& rString,
739 : const ScArea& rArea,
740 : const ScDocument* pDocument,
741 : FormulaGrammar::AddressConvention eConv,
742 : sal_Unicode cSeperator,
743 : sal_Bool bAppendStr,
744 : sal_uInt16 nFormatFlags )
745 : {
746 0 : ScRange aRange( rArea.nColStart, rArea.nRowStart, rArea.nTab, rArea.nColEnd, rArea.nRowEnd, rArea.nTab );
747 0 : GetStringFromRange( rString, aRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
748 0 : }
749 :
750 :
751 : //___________________________________________________________________
752 :
753 0 : void ScRangeStringConverter::GetStringFromAddress(
754 : OUString& rString,
755 : const table::CellAddress& rAddress,
756 : const ScDocument* pDocument,
757 : FormulaGrammar::AddressConvention eConv,
758 : sal_Unicode cSeperator,
759 : sal_Bool bAppendStr,
760 : sal_uInt16 nFormatFlags )
761 : {
762 0 : ScAddress aScAddress( static_cast<SCCOL>(rAddress.Column), static_cast<SCROW>(rAddress.Row), rAddress.Sheet );
763 0 : GetStringFromAddress( rString, aScAddress, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
764 0 : }
765 :
766 0 : void ScRangeStringConverter::GetStringFromRange(
767 : OUString& rString,
768 : const table::CellRangeAddress& rRange,
769 : const ScDocument* pDocument,
770 : FormulaGrammar::AddressConvention eConv,
771 : sal_Unicode cSeperator,
772 : sal_Bool bAppendStr,
773 : sal_uInt16 nFormatFlags )
774 : {
775 : ScRange aScRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), rRange.Sheet,
776 0 : static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), rRange.Sheet );
777 0 : GetStringFromRange( rString, aScRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
778 0 : }
779 :
780 2 : void ScRangeStringConverter::GetStringFromRangeList(
781 : OUString& rString,
782 : const uno::Sequence< table::CellRangeAddress >& rRangeSeq,
783 : const ScDocument* pDocument,
784 : FormulaGrammar::AddressConvention eConv,
785 : sal_Unicode cSeperator,
786 : sal_uInt16 nFormatFlags )
787 : {
788 2 : OUString sRangeListStr;
789 2 : sal_Int32 nCount = rRangeSeq.getLength();
790 2 : for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
791 : {
792 0 : const table::CellRangeAddress& rRange = rRangeSeq[ nIndex ];
793 0 : GetStringFromRange( sRangeListStr, rRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
794 : }
795 2 : rString = sRangeListStr;
796 2 : }
797 :
798 0 : static void lcl_appendCellAddress(
799 : rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell,
800 : const ScAddress::ExternalInfo& rExtInfo)
801 : {
802 0 : if (rExtInfo.mbExternal)
803 : {
804 0 : ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
805 0 : const OUString* pFilePath = pRefMgr->getExternalFileName(rExtInfo.mnFileId, true);
806 0 : if (!pFilePath)
807 0 : return;
808 :
809 0 : sal_Unicode cQuote = '\'';
810 0 : rBuf.append(cQuote);
811 0 : rBuf.append(*pFilePath);
812 0 : rBuf.append(cQuote);
813 0 : rBuf.append(sal_Unicode('#'));
814 0 : rBuf.append(sal_Unicode('$'));
815 0 : ScRangeStringConverter::AppendTableName(rBuf, rExtInfo.maTabName);
816 0 : rBuf.append(sal_Unicode('.'));
817 :
818 0 : String aAddr;
819 0 : rCell.Format(aAddr, SCA_ABS, NULL, pDoc->GetAddressConvention());
820 0 : rBuf.append(aAddr);
821 : }
822 : else
823 : {
824 0 : String aAddr;
825 0 : rCell.Format(aAddr, SCA_ABS_3D, pDoc, pDoc->GetAddressConvention());
826 0 : rBuf.append(aAddr);
827 : }
828 : }
829 :
830 0 : static void lcl_appendCellRangeAddress(
831 : rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell1, const ScAddress& rCell2,
832 : const ScAddress::ExternalInfo& rExtInfo1, const ScAddress::ExternalInfo& rExtInfo2)
833 : {
834 0 : if (rExtInfo1.mbExternal)
835 : {
836 : OSL_ENSURE(rExtInfo2.mbExternal, "2nd address is not external!?");
837 : OSL_ENSURE(rExtInfo1.mnFileId == rExtInfo2.mnFileId, "File IDs do not match between 1st and 2nd addresses.");
838 :
839 0 : ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
840 0 : const OUString* pFilePath = pRefMgr->getExternalFileName(rExtInfo1.mnFileId, true);
841 0 : if (!pFilePath)
842 0 : return;
843 :
844 0 : sal_Unicode cQuote = '\'';
845 0 : rBuf.append(cQuote);
846 0 : rBuf.append(*pFilePath);
847 0 : rBuf.append(cQuote);
848 0 : rBuf.append(sal_Unicode('#'));
849 0 : rBuf.append(sal_Unicode('$'));
850 0 : ScRangeStringConverter::AppendTableName(rBuf, rExtInfo1.maTabName);
851 0 : rBuf.append(sal_Unicode('.'));
852 :
853 0 : String aAddr;
854 0 : rCell1.Format(aAddr, SCA_ABS, NULL, pDoc->GetAddressConvention());
855 0 : rBuf.append(aAddr);
856 :
857 0 : rBuf.appendAscii(":");
858 :
859 0 : if (rExtInfo1.maTabName != rExtInfo2.maTabName)
860 : {
861 0 : rBuf.append(sal_Unicode('$'));
862 0 : ScRangeStringConverter::AppendTableName(rBuf, rExtInfo2.maTabName);
863 0 : rBuf.append(sal_Unicode('.'));
864 : }
865 :
866 0 : rCell2.Format(aAddr, SCA_ABS, NULL, pDoc->GetAddressConvention());
867 0 : rBuf.append(aAddr);
868 : }
869 : else
870 : {
871 0 : ScRange aRange;
872 0 : aRange.aStart = rCell1;
873 0 : aRange.aEnd = rCell2;
874 0 : String aAddr;
875 0 : aRange.Format(aAddr, SCR_ABS_3D, pDoc, pDoc->GetAddressConvention());
876 0 : rBuf.append(aAddr);
877 : }
878 : }
879 :
880 0 : void ScRangeStringConverter::GetStringFromXMLRangeString( OUString& rString, const OUString& rXMLRange, ScDocument* pDoc )
881 : {
882 0 : FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
883 0 : const sal_Unicode cSep = ' ';
884 0 : const sal_Unicode cSepNew = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
885 0 : const sal_Unicode cQuote = '\'';
886 :
887 0 : OUStringBuffer aRetStr;
888 0 : sal_Int32 nOffset = 0;
889 0 : bool bFirst = true;
890 :
891 0 : while (nOffset >= 0)
892 : {
893 0 : OUString aToken;
894 0 : GetTokenByOffset(aToken, rXMLRange, nOffset, cSep, cQuote);
895 0 : if (nOffset < 0)
896 : break;
897 :
898 0 : sal_Int32 nSepPos = IndexOf(aToken, ':', 0, cQuote);
899 0 : if (nSepPos >= 0)
900 : {
901 : // Cell range
902 0 : OUString aBeginCell = aToken.copy(0, nSepPos);
903 0 : OUString aEndCell = aToken.copy(nSepPos+1);
904 :
905 0 : if (aBeginCell.isEmpty() || aEndCell.isEmpty())
906 : // both cell addresses must exist for this to work.
907 0 : continue;
908 :
909 0 : sal_Int32 nEndCellDotPos = aEndCell.indexOf('.');
910 0 : if (nEndCellDotPos <= 0)
911 : {
912 : // initialize buffer with table name...
913 0 : sal_Int32 nDotPos = IndexOf(aBeginCell, sal_Unicode('.'), 0, cQuote);
914 0 : OUStringBuffer aBuf = aBeginCell.copy(0, nDotPos);
915 :
916 0 : if (nEndCellDotPos == 0)
917 : {
918 : // workaround for old syntax (probably pre-chart2 age?)
919 : // e.g. Sheet1.A1:.B2
920 0 : aBuf.append(aEndCell);
921 : }
922 0 : else if (nEndCellDotPos < 0)
923 : {
924 : // sheet name in the end cell is omitted (e.g. Sheet2.A1:B2).
925 0 : aBuf.append(sal_Unicode('.'));
926 0 : aBuf.append(aEndCell);
927 : }
928 0 : aEndCell = aBuf.makeStringAndClear();
929 : }
930 :
931 0 : ScAddress::ExternalInfo aExtInfo1, aExtInfo2;
932 0 : ScAddress aCell1, aCell2;
933 0 : rtl::OUString aBuf;
934 0 : sal_uInt16 nRet = aCell1.Parse(aBeginCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo1);
935 0 : if ((nRet & SCA_VALID) != SCA_VALID)
936 : {
937 : // first cell is invalid.
938 0 : if (eConv == FormulaGrammar::CONV_OOO)
939 0 : continue;
940 :
941 0 : nRet = aCell1.Parse(aBeginCell, pDoc, eConv, &aExtInfo1);
942 0 : if ((nRet & SCA_VALID) != SCA_VALID)
943 : // first cell is really invalid.
944 0 : continue;
945 : }
946 :
947 0 : nRet = aCell2.Parse(aEndCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo2);
948 0 : if ((nRet & SCA_VALID) != SCA_VALID)
949 : {
950 : // second cell is invalid.
951 0 : if (eConv == FormulaGrammar::CONV_OOO)
952 0 : continue;
953 :
954 0 : nRet = aCell2.Parse(aEndCell, pDoc, eConv, &aExtInfo2);
955 0 : if ((nRet & SCA_VALID) != SCA_VALID)
956 : // second cell is really invalid.
957 0 : continue;
958 : }
959 :
960 0 : if (aExtInfo1.mnFileId != aExtInfo2.mnFileId || aExtInfo1.mbExternal != aExtInfo2.mbExternal)
961 : // external info inconsistency.
962 0 : continue;
963 :
964 : // All looks good!
965 :
966 0 : if (bFirst)
967 0 : bFirst = false;
968 : else
969 0 : aRetStr.append(cSepNew);
970 :
971 0 : lcl_appendCellRangeAddress(aRetStr, pDoc, aCell1, aCell2, aExtInfo1, aExtInfo2);
972 : }
973 : else
974 : {
975 : // Chart always saves ranges using CONV_OOO convention.
976 0 : ScAddress::ExternalInfo aExtInfo;
977 0 : ScAddress aCell;
978 0 : sal_uInt16 nRet = aCell.Parse(aToken, pDoc, ::formula::FormulaGrammar::CONV_OOO, &aExtInfo);
979 0 : if ((nRet & SCA_VALID) != SCA_VALID)
980 : {
981 0 : nRet = aCell.Parse(aToken, pDoc, eConv, &aExtInfo);
982 0 : if ((nRet & SCA_VALID) != SCA_VALID)
983 0 : continue;
984 : }
985 :
986 : // Looks good!
987 :
988 0 : if (bFirst)
989 0 : bFirst = false;
990 : else
991 0 : aRetStr.append(cSepNew);
992 :
993 0 : lcl_appendCellAddress(aRetStr, pDoc, aCell, aExtInfo);
994 : }
995 0 : }
996 :
997 0 : rString = aRetStr.makeStringAndClear();
998 0 : }
999 :
1000 8 : ScRangeData* ScRangeStringConverter::GetRangeDataFromString(const rtl::OUString& rString, const SCTAB nTab, const ScDocument* pDoc)
1001 : {
1002 8 : ScRangeName* pLocalRangeName = pDoc->GetRangeName(nTab);
1003 8 : ScRangeData* pData = NULL;
1004 8 : rtl::OUString aUpperName = ScGlobal::pCharClass->uppercase(rString);
1005 8 : if(pLocalRangeName)
1006 : {
1007 8 : pData = pLocalRangeName->findByUpperName(aUpperName);
1008 : }
1009 8 : if (!pData)
1010 : {
1011 8 : ScRangeName* pGlobalRangeName = pDoc->GetRangeName();
1012 8 : if (pGlobalRangeName)
1013 : {
1014 8 : pData = pGlobalRangeName->findByUpperName(aUpperName);
1015 : }
1016 : }
1017 8 : return pData;
1018 : }
1019 :
1020 : //========================================================================
1021 :
1022 0 : ScArea::ScArea( SCTAB tab,
1023 : SCCOL colStart, SCROW rowStart,
1024 : SCCOL colEnd, SCROW rowEnd ) :
1025 : nTab ( tab ),
1026 : nColStart( colStart ), nRowStart( rowStart ),
1027 0 : nColEnd ( colEnd ), nRowEnd ( rowEnd )
1028 : {
1029 0 : }
1030 :
1031 : //------------------------------------------------------------------------
1032 :
1033 0 : ScArea::ScArea( const ScArea& r ) :
1034 : nTab ( r.nTab ),
1035 : nColStart( r.nColStart ), nRowStart( r.nRowStart ),
1036 0 : nColEnd ( r.nColEnd ), nRowEnd ( r.nRowEnd )
1037 : {
1038 0 : }
1039 :
1040 : //------------------------------------------------------------------------
1041 :
1042 0 : ScArea& ScArea::operator=( const ScArea& r )
1043 : {
1044 0 : nTab = r.nTab;
1045 0 : nColStart = r.nColStart;
1046 0 : nRowStart = r.nRowStart;
1047 0 : nColEnd = r.nColEnd;
1048 0 : nRowEnd = r.nRowEnd;
1049 0 : return *this;
1050 : }
1051 :
1052 : //------------------------------------------------------------------------
1053 :
1054 0 : sal_Bool ScArea::operator==( const ScArea& r ) const
1055 : {
1056 : return ( (nTab == r.nTab)
1057 : && (nColStart == r.nColStart)
1058 : && (nRowStart == r.nRowStart)
1059 : && (nColEnd == r.nColEnd)
1060 0 : && (nRowEnd == r.nRowEnd) );
1061 : }
1062 :
1063 : //------------------------------------------------------------------------
1064 :
1065 0 : ScAreaNameIterator::ScAreaNameIterator( ScDocument* pDoc ) :
1066 0 : pRangeName(pDoc->GetRangeName()),
1067 0 : pDBCollection(pDoc->GetDBCollection()),
1068 0 : bFirstPass(true)
1069 : {
1070 0 : if (pRangeName)
1071 : {
1072 0 : maRNPos = pRangeName->begin();
1073 0 : maRNEnd = pRangeName->end();
1074 : }
1075 0 : }
1076 :
1077 0 : bool ScAreaNameIterator::Next( rtl::OUString& rName, ScRange& rRange )
1078 : {
1079 : // Just a wrapper for rtl::OUString for now. It should replace the method
1080 : // below eventually.
1081 0 : String aTmp;
1082 0 : bool bRet = Next(aTmp, rRange);
1083 0 : rName = aTmp;
1084 0 : return bRet;
1085 : }
1086 :
1087 0 : bool ScAreaNameIterator::Next( String& rName, ScRange& rRange )
1088 : {
1089 0 : for (;;)
1090 : {
1091 0 : if ( bFirstPass ) // erst Bereichsnamen
1092 : {
1093 0 : if ( pRangeName && maRNPos != maRNEnd )
1094 : {
1095 0 : const ScRangeData& rData = *maRNPos->second;
1096 0 : ++maRNPos;
1097 0 : bool bValid = rData.IsValidReference(rRange);
1098 0 : if (bValid)
1099 : {
1100 0 : rName = rData.GetName();
1101 0 : return true; // found
1102 : }
1103 : }
1104 : else
1105 : {
1106 0 : bFirstPass = false;
1107 0 : if (pDBCollection)
1108 : {
1109 0 : const ScDBCollection::NamedDBs& rDBs = pDBCollection->getNamedDBs();
1110 0 : maDBPos = rDBs.begin();
1111 0 : maDBEnd = rDBs.end();
1112 : }
1113 : }
1114 : }
1115 :
1116 0 : if ( !bFirstPass ) // dann DB-Bereiche
1117 : {
1118 0 : if (pDBCollection && maDBPos != maDBEnd)
1119 : {
1120 0 : const ScDBData& rData = *maDBPos;
1121 0 : ++maDBPos;
1122 0 : rData.GetArea(rRange);
1123 0 : rName = rData.GetName();
1124 0 : return true; // found
1125 : }
1126 : else
1127 0 : return false; // nothing left
1128 : }
1129 : }
1130 : }
1131 :
1132 :
1133 :
1134 :
1135 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|