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