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