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