fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / global2.cxx
blobe3aa0f78774360431cfaee170a2082742757bc99
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sfx2/docfile.hxx>
21 #include <sfx2/objsh.hxx>
22 #include <unotools/pathoptions.hxx>
23 #include <unotools/useroptions.hxx>
24 #include <tools/urlobj.hxx>
25 #include <unotools/charclass.hxx>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <unotools/syslocale.hxx>
29 #include <svl/zforlist.hxx>
30 #include <formula/errorcodes.hxx>
32 #include "global.hxx"
33 #include "rangeutl.hxx"
34 #include "rechead.hxx"
35 #include "compiler.hxx"
36 #include "paramisc.hxx"
37 #include "calcconfig.hxx"
39 #include "sc.hrc"
40 #include "globstr.hrc"
42 using ::std::vector;
44 // struct ScImportParam:
46 ScImportParam::ScImportParam() :
47 nCol1(0),
48 nRow1(0),
49 nCol2(0),
50 nRow2(0),
51 bImport(false),
52 bNative(false),
53 bSql(true),
54 nType(ScDbTable)
58 ScImportParam::ScImportParam( const ScImportParam& r ) :
59 nCol1 (r.nCol1),
60 nRow1 (r.nRow1),
61 nCol2 (r.nCol2),
62 nRow2 (r.nRow2),
63 bImport (r.bImport),
64 aDBName (r.aDBName),
65 aStatement (r.aStatement),
66 bNative (r.bNative),
67 bSql (r.bSql),
68 nType (r.nType)
72 ScImportParam::~ScImportParam()
76 ScImportParam& ScImportParam::operator=( const ScImportParam& r )
78 nCol1 = r.nCol1;
79 nRow1 = r.nRow1;
80 nCol2 = r.nCol2;
81 nRow2 = r.nRow2;
82 bImport = r.bImport;
83 aDBName = r.aDBName;
84 aStatement = r.aStatement;
85 bNative = r.bNative;
86 bSql = r.bSql;
87 nType = r.nType;
89 return *this;
92 bool ScImportParam::operator==( const ScImportParam& rOther ) const
94 return( nCol1 == rOther.nCol1 &&
95 nRow1 == rOther.nRow1 &&
96 nCol2 == rOther.nCol2 &&
97 nRow2 == rOther.nRow2 &&
98 bImport == rOther.bImport &&
99 aDBName == rOther.aDBName &&
100 aStatement == rOther.aStatement &&
101 bNative == rOther.bNative &&
102 bSql == rOther.bSql &&
103 nType == rOther.nType );
105 //TODO: are nQuerySh and pConnection equal ?
108 // struct ScConsolidateParam:
110 ScConsolidateParam::ScConsolidateParam() :
111 ppDataAreas( NULL )
113 Clear();
116 ScConsolidateParam::ScConsolidateParam( const ScConsolidateParam& r ) :
117 nCol(r.nCol),nRow(r.nRow),nTab(r.nTab),
118 eFunction(r.eFunction),nDataAreaCount(0),
119 ppDataAreas( NULL ),
120 bByCol(r.bByCol),bByRow(r.bByRow),bReferenceData(r.bReferenceData)
122 if ( r.nDataAreaCount > 0 )
124 nDataAreaCount = r.nDataAreaCount;
125 ppDataAreas = new ScArea*[nDataAreaCount];
126 for ( sal_uInt16 i=0; i<nDataAreaCount; i++ )
127 ppDataAreas[i] = new ScArea( *(r.ppDataAreas[i]) );
131 ScConsolidateParam::~ScConsolidateParam()
133 ClearDataAreas();
136 void ScConsolidateParam::ClearDataAreas()
138 if ( ppDataAreas )
140 for ( sal_uInt16 i=0; i<nDataAreaCount; i++ )
141 delete ppDataAreas[i];
142 delete [] ppDataAreas;
143 ppDataAreas = NULL;
145 nDataAreaCount = 0;
148 void ScConsolidateParam::Clear()
150 ClearDataAreas();
152 nCol = 0;
153 nRow = 0;
154 nTab = 0;
155 bByCol = bByRow = bReferenceData = false;
156 eFunction = SUBTOTAL_FUNC_SUM;
159 ScConsolidateParam& ScConsolidateParam::operator=( const ScConsolidateParam& r )
161 nCol = r.nCol;
162 nRow = r.nRow;
163 nTab = r.nTab;
164 bByCol = r.bByCol;
165 bByRow = r.bByRow;
166 bReferenceData = r.bReferenceData;
167 eFunction = r.eFunction;
168 SetAreas( r.ppDataAreas, r.nDataAreaCount );
170 return *this;
173 bool ScConsolidateParam::operator==( const ScConsolidateParam& r ) const
175 bool bEqual = (nCol == r.nCol)
176 && (nRow == r.nRow)
177 && (nTab == r.nTab)
178 && (bByCol == r.bByCol)
179 && (bByRow == r.bByRow)
180 && (bReferenceData == r.bReferenceData)
181 && (nDataAreaCount == r.nDataAreaCount)
182 && (eFunction == r.eFunction);
184 if ( nDataAreaCount == 0 )
185 bEqual = bEqual && (ppDataAreas == NULL) && (r.ppDataAreas == NULL);
186 else
187 bEqual = bEqual && (ppDataAreas != NULL) && (r.ppDataAreas != NULL);
189 if ( bEqual && (nDataAreaCount > 0) )
190 for ( sal_uInt16 i=0; i<nDataAreaCount && bEqual; i++ )
191 bEqual = *(ppDataAreas[i]) == *(r.ppDataAreas[i]);
193 return bEqual;
196 void ScConsolidateParam::SetAreas( ScArea* const* ppAreas, sal_uInt16 nCount )
198 ClearDataAreas();
199 if ( ppAreas && nCount > 0 )
201 ppDataAreas = new ScArea*[nCount];
202 for ( sal_uInt16 i=0; i<nCount; i++ )
203 ppDataAreas[i] = new ScArea( *(ppAreas[i]) );
204 nDataAreaCount = nCount;
208 // struct ScSolveParam
210 ScSolveParam::ScSolveParam()
211 : pStrTargetVal( NULL )
215 ScSolveParam::ScSolveParam( const ScSolveParam& r )
216 : aRefFormulaCell ( r.aRefFormulaCell ),
217 aRefVariableCell( r.aRefVariableCell ),
218 pStrTargetVal ( r.pStrTargetVal
219 ? new OUString(*r.pStrTargetVal)
220 : NULL )
224 ScSolveParam::ScSolveParam( const ScAddress& rFormulaCell,
225 const ScAddress& rVariableCell,
226 const OUString& rTargetValStr )
227 : aRefFormulaCell ( rFormulaCell ),
228 aRefVariableCell( rVariableCell ),
229 pStrTargetVal ( new OUString(rTargetValStr) )
233 ScSolveParam::~ScSolveParam()
235 delete pStrTargetVal;
238 ScSolveParam& ScSolveParam::operator=( const ScSolveParam& r )
240 delete pStrTargetVal;
242 aRefFormulaCell = r.aRefFormulaCell;
243 aRefVariableCell = r.aRefVariableCell;
244 pStrTargetVal = r.pStrTargetVal
245 ? new OUString(*r.pStrTargetVal)
246 : NULL;
247 return *this;
250 bool ScSolveParam::operator==( const ScSolveParam& r ) const
252 bool bEqual = (aRefFormulaCell == r.aRefFormulaCell)
253 && (aRefVariableCell == r.aRefVariableCell);
255 if ( bEqual )
257 if ( !pStrTargetVal && !r.pStrTargetVal )
258 bEqual = true;
259 else if ( !pStrTargetVal || !r.pStrTargetVal )
260 bEqual = false;
261 else if ( pStrTargetVal && r.pStrTargetVal )
262 bEqual = ( *pStrTargetVal == *(r.pStrTargetVal) );
265 return bEqual;
268 // struct ScTabOpParam
270 ScTabOpParam::ScTabOpParam() : meMode(Column) {}
272 ScTabOpParam::ScTabOpParam( const ScTabOpParam& r )
273 : aRefFormulaCell ( r.aRefFormulaCell ),
274 aRefFormulaEnd ( r.aRefFormulaEnd ),
275 aRefRowCell ( r.aRefRowCell ),
276 aRefColCell ( r.aRefColCell ),
277 meMode(r.meMode)
281 ScTabOpParam::ScTabOpParam( const ScRefAddress& rFormulaCell,
282 const ScRefAddress& rFormulaEnd,
283 const ScRefAddress& rRowCell,
284 const ScRefAddress& rColCell,
285 Mode eMode )
286 : aRefFormulaCell ( rFormulaCell ),
287 aRefFormulaEnd ( rFormulaEnd ),
288 aRefRowCell ( rRowCell ),
289 aRefColCell ( rColCell ),
290 meMode(eMode)
294 ScTabOpParam& ScTabOpParam::operator=( const ScTabOpParam& r )
296 aRefFormulaCell = r.aRefFormulaCell;
297 aRefFormulaEnd = r.aRefFormulaEnd;
298 aRefRowCell = r.aRefRowCell;
299 aRefColCell = r.aRefColCell;
300 meMode = r.meMode;
301 return *this;
304 bool ScTabOpParam::operator==( const ScTabOpParam& r ) const
306 return ( (aRefFormulaCell == r.aRefFormulaCell)
307 && (aRefFormulaEnd == r.aRefFormulaEnd)
308 && (aRefRowCell == r.aRefRowCell)
309 && (aRefColCell == r.aRefColCell)
310 && (meMode == r.meMode) );
313 OUString ScGlobal::GetAbsDocName( const OUString& rFileName,
314 SfxObjectShell* pShell )
316 OUString aAbsName;
317 if ( !pShell->HasName() )
318 { // maybe relative to document path working directory
319 INetURLObject aObj;
320 SvtPathOptions aPathOpt;
321 aObj.SetSmartURL( aPathOpt.GetWorkPath() );
322 aObj.setFinalSlash(); // it IS a path
323 bool bWasAbs = true;
324 aAbsName = aObj.smartRel2Abs( rFileName, bWasAbs ).GetMainURL(INetURLObject::NO_DECODE);
325 // returned string must be encoded because it's used directly to create SfxMedium
327 else
329 const SfxMedium* pMedium = pShell->GetMedium();
330 if ( pMedium )
332 bool bWasAbs = true;
333 aAbsName = pMedium->GetURLObject().smartRel2Abs( rFileName, bWasAbs ).GetMainURL(INetURLObject::NO_DECODE);
335 else
336 { // This can't happen, but ...
337 // just to be sure to have the same encoding
338 INetURLObject aObj;
339 aObj.SetSmartURL( aAbsName );
340 aAbsName = aObj.GetMainURL(INetURLObject::NO_DECODE);
343 return aAbsName;
346 OUString ScGlobal::GetDocTabName( const OUString& rFileName,
347 const OUString& rTabName )
349 OUString aDocTab('\'');
350 aDocTab += rFileName;
351 sal_Int32 nPos = 1;
352 while( (nPos = aDocTab.indexOf( '\'', nPos )) != -1 )
353 { // escape Quotes
354 aDocTab = aDocTab.replaceAt( nPos, 0, "\\" );
355 nPos += 2;
357 aDocTab += "'";
358 aDocTab += OUString(SC_COMPILER_FILE_TAB_SEP);
359 aDocTab += rTabName; // "'Doc'#Tab"
360 return aDocTab;
363 namespace
365 bool isEmptyString( const OUString& rStr )
367 if (rStr.isEmpty())
368 return true;
369 else if (rStr[0] == ' ')
371 const sal_Unicode* p = rStr.getStr() + 1;
372 const sal_Unicode* const pStop = p - 1 + rStr.getLength();
373 while (p < pStop && *p == ' ')
374 ++p;
375 if (p == pStop)
376 return true;
378 return false;
382 double ScGlobal::ConvertStringToValue( const OUString& rStr, const ScCalcConfig& rConfig,
383 sal_uInt16 & rError, sal_uInt16 nStringNoValueError,
384 SvNumberFormatter* pFormatter, short & rCurFmtType )
386 // We keep ScCalcConfig::StringConversion::LOCALE default until
387 // we provide a friendly way to convert string numbers into numbers in the UI.
389 double fValue = 0.0;
390 if (nStringNoValueError == errCellNoValue)
392 // Requested that all strings result in 0, error handled by caller.
393 rError = nStringNoValueError;
394 return fValue;
397 switch (rConfig.meStringConversion)
399 case ScCalcConfig::StringConversion::ILLEGAL:
400 rError = nStringNoValueError;
401 return fValue;
402 case ScCalcConfig::StringConversion::ZERO:
403 return fValue;
404 case ScCalcConfig::StringConversion::LOCALE:
406 if (rConfig.mbEmptyStringAsZero)
408 // The number scanner does not accept empty strings or strings
409 // containing only spaces, be on par in these cases with what was
410 // accepted in OOo and is in AOO (see also the
411 // StringConversion::UNAMBIGUOUS branch) and convert to 0 to prevent
412 // interoperability nightmares.
414 if (isEmptyString( rStr))
415 return fValue;
418 if (!pFormatter)
419 goto Label_fallback_to_unambiguous;
421 sal_uInt32 nFIndex = 0;
422 if (!pFormatter->IsNumberFormat(rStr, nFIndex, fValue))
424 rError = nStringNoValueError;
425 fValue = 0.0;
427 return fValue;
429 break;
430 case ScCalcConfig::StringConversion::UNAMBIGUOUS:
431 Label_fallback_to_unambiguous:
433 if (!rConfig.mbEmptyStringAsZero)
435 if (isEmptyString( rStr))
437 rError = nStringNoValueError;
438 return fValue;
442 // continue below, pulled from switch case for better readability
443 break;
446 OUString aStr( rStr);
447 rtl_math_ConversionStatus eStatus;
448 sal_Int32 nParseEnd;
449 // Decimal and group separator 0 => only integer and possibly exponent,
450 // stops at first non-digit non-sign.
451 fValue = ::rtl::math::stringToDouble( aStr, 0, 0, &eStatus, &nParseEnd);
452 sal_Int32 nLen;
453 if (eStatus == rtl_math_ConversionStatus_Ok && nParseEnd < (nLen = aStr.getLength()))
455 // Not at string end, check for trailing blanks or switch to date or
456 // time parsing or bail out.
457 const sal_Unicode* const pStart = aStr.getStr();
458 const sal_Unicode* p = pStart + nParseEnd;
459 const sal_Unicode* const pStop = pStart + nLen;
460 switch (*p++)
462 case ' ':
463 while (p < pStop && *p == ' ')
464 ++p;
465 if (p < pStop)
466 rError = nStringNoValueError;
467 break;
468 case '-':
469 case ':':
471 bool bDate = (*(p-1) == '-');
472 enum State { year = 0, month, day, hour, minute, second, fraction, done, blank, stop };
473 sal_Int32 nUnit[done] = {0,0,0,0,0,0,0};
474 const sal_Int32 nLimit[done] = {0,12,31,0,59,59,0};
475 State eState = (bDate ? month : minute);
476 rCurFmtType = (bDate ? css::util::NumberFormat::DATE : css::util::NumberFormat::TIME);
477 nUnit[eState-1] = aStr.copy( 0, nParseEnd).toInt32();
478 const sal_Unicode* pLastStart = p;
479 // Ensure there's no preceding sign. Negative dates
480 // currently aren't handled correctly. Also discard
481 // +CCYY-MM-DD
482 p = pStart;
483 while (p < pStop && *p == ' ')
484 ++p;
485 if (p < pStop && !rtl::isAsciiDigit(*p))
486 rError = nStringNoValueError;
487 p = pLastStart;
488 while (p < pStop && !rError && eState < blank)
490 if (eState == minute)
491 rCurFmtType |= css::util::NumberFormat::TIME;
492 if (rtl::isAsciiDigit(*p))
494 // Maximum 2 digits per unit, except fractions.
495 if (p - pLastStart >= 2 && eState != fraction)
496 rError = nStringNoValueError;
498 else if (p > pLastStart)
500 // We had at least one digit.
501 if (eState < done)
503 nUnit[eState] = aStr.copy( pLastStart - pStart, p - pLastStart).toInt32();
504 if (nLimit[eState] && nLimit[eState] < nUnit[eState])
505 rError = nStringNoValueError;
507 pLastStart = p + 1; // hypothetical next start
508 // Delimiters must match, a trailing delimiter
509 // yields an invalid date/time.
510 switch (eState)
512 case month:
513 // Month must be followed by separator and
514 // day, no trailing blanks.
515 if (*p != '-' || (p+1 == pStop))
516 rError = nStringNoValueError;
517 break;
518 case day:
519 if ((*p != 'T' || (p+1 == pStop)) && *p != ' ')
520 rError = nStringNoValueError;
521 // Take one blank as a valid delimiter
522 // between date and time.
523 break;
524 case hour:
525 // Hour must be followed by separator and
526 // minute, no trailing blanks.
527 if (*p != ':' || (p+1 == pStop))
528 rError = nStringNoValueError;
529 break;
530 case minute:
531 if ((*p != ':' || (p+1 == pStop)) && *p != ' ')
532 rError = nStringNoValueError;
533 if (*p == ' ')
534 eState = done;
535 break;
536 case second:
537 if (((*p != ',' && *p != '.') || (p+1 == pStop)) && *p != ' ')
538 rError = nStringNoValueError;
539 if (*p == ' ')
540 eState = done;
541 break;
542 case fraction:
543 eState = done;
544 break;
545 case year:
546 case done:
547 case blank:
548 case stop:
549 rError = nStringNoValueError;
550 break;
552 eState = static_cast<State>(eState + 1);
554 else
555 rError = nStringNoValueError;
556 ++p;
558 if (eState == blank)
560 while (p < pStop && *p == ' ')
561 ++p;
562 if (p < pStop)
563 rError = nStringNoValueError;
564 eState = stop;
567 // Month without day, or hour without minute.
568 if (eState == month || (eState == day && p <= pLastStart) ||
569 eState == hour || (eState == minute && p <= pLastStart))
570 rError = nStringNoValueError;
572 if (!rError)
574 // Catch the very last unit at end of string.
575 if (p > pLastStart && eState < done)
577 nUnit[eState] = aStr.copy( pLastStart - pStart, p - pLastStart).toInt32();
578 if (nLimit[eState] && nLimit[eState] < nUnit[eState])
579 rError = nStringNoValueError;
581 if (bDate && nUnit[hour] > 23)
582 rError = nStringNoValueError;
583 if (!rError)
585 if (bDate && nUnit[day] == 0)
586 nUnit[day] = 1;
587 double fFraction = (nUnit[fraction] <= 0 ? 0.0 :
588 ::rtl::math::pow10Exp( nUnit[fraction],
589 static_cast<int>( -ceil( log10( static_cast<double>( nUnit[fraction]))))));
590 if (!bDate)
591 fValue = 0.0;
592 else
594 Date aDate(
595 sal::static_int_cast<sal_Int16>(nUnit[day]),
596 sal::static_int_cast<sal_Int16>(nUnit[month]),
597 sal::static_int_cast<sal_Int16>(nUnit[year]));
598 if (!aDate.IsValidDate())
599 rError = nStringNoValueError;
600 else
602 if (pFormatter)
603 fValue = aDate - *(pFormatter->GetNullDate());
604 else
606 SAL_WARN("sc.core","ScGlobal::ConvertStringToValue - fixed null date");
607 static Date aDefaultNullDate( 30, 12, 1899);
608 fValue = aDate - aDefaultNullDate;
612 fValue += ((nUnit[hour] * 3600) + (nUnit[minute] * 60) + nUnit[second] + fFraction) / 86400.0;
616 break;
617 default:
618 rError = nStringNoValueError;
620 if (rError)
621 fValue = 0.0;
623 return fValue;
626 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */