LibreOffice Module sc (master)  1
xmlcondformat.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <memory>
11 #include "xmlcondformat.hxx"
12 #include "xmlimprt.hxx"
13 #include <xmloff/xmlnamespace.hxx>
14 #include <xmloff/xmlictxt.hxx>
15 #include <sal/log.hxx>
16 
17 #include <compiler.hxx>
18 #include <colorscale.hxx>
19 #include <conditio.hxx>
20 #include <document.hxx>
21 #include <sax/tools/converter.hxx>
22 #include <rangelst.hxx>
23 #include <rangeutl.hxx>
24 #include "XMLConverter.hxx"
25 #include <stylehelper.hxx>
26 #include <tokenarray.hxx>
27 
28 using namespace xmloff::token;
29 
31  ScXMLImportContext( rImport )
32 {
34  GetScImport().GetDocument()->SetCondFormList(new ScConditionalFormatList(), GetScImport().GetTables().GetCurrentSheet());
35 }
36 
37 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLConditionalFormatsContext::createFastChildContext(
38  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
39 {
40  SvXMLImportContext* pContext = nullptr;
43 
44  switch (nElement)
45  {
46  case XML_ELEMENT( CALC_EXT, XML_CONDITIONAL_FORMAT ):
47  pContext = new ScXMLConditionalFormatContext( GetScImport(), pAttribList, *this );
48  break;
49  }
50 
51  return pContext;
52 }
53 
55 {
56  mvCondFormatData.erase(std::remove_if(mvCondFormatData.begin(), mvCondFormatData.end(),
57  [pFormat](CondFormatData& r){ return r.mpFormat == pFormat; }),
58  mvCondFormatData.end());
59 }
60 
61 void SAL_CALL ScXMLConditionalFormatsContext::endFastElement( sal_Int32 /*nElement*/ )
62 {
64 
66  ScConditionalFormatList* pCondFormatList = pDoc->GetCondFormList(nTab);
67  bool bDeleted = !pCondFormatList->CheckAllEntries(LINK(this, ScXMLConditionalFormatsContext, FormatDeletedHdl));
68 
69  SAL_WARN_IF(bDeleted, "sc", "conditional formats have been deleted because they contained empty range info");
70 
71  for (const auto& i : mvCondFormatData)
72  {
73  pDoc->AddCondFormatData( i.mpFormat->GetRange(), i.mnTab, i.mpFormat->GetKey() );
74  }
75 }
76 
80  ScXMLImportContext( rImport ),
81  mrParent( rParent )
82 {
83  OUString sRange;
84 
85  if ( rAttrList.is() )
86  {
87  for (auto &aIter : *rAttrList)
88  {
89  switch (aIter.getToken())
90  {
91  case XML_ELEMENT( CALC_EXT, XML_TARGET_RANGE_ADDRESS ):
92  sRange = aIter.toString();
93  break;
94  default:
95  break;
96  }
97  }
98  }
99 
100  ScRangeList aRangeList;
101  ScDocument* pDoc = GetScImport().GetDocument();
102  assert(pDoc);
103  ScRangeStringConverter::GetRangeListFromString(aRangeList, sRange, *pDoc,
105 
106  mxFormat.reset(new ScConditionalFormat(0, pDoc));
107  mxFormat->SetRange(aRangeList);
108 }
109 
110 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLConditionalFormatContext::createFastChildContext(
111  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
112 {
113  SvXMLImportContext* pContext = nullptr;
114  sax_fastparser::FastAttributeList *pAttribList =
116 
117  switch (nElement)
118  {
119  case XML_ELEMENT( CALC_EXT, XML_CONDITION ):
120  pContext = new ScXMLCondContext( GetScImport(), pAttribList, mxFormat.get() );
121  break;
122  case XML_ELEMENT( CALC_EXT, XML_COLOR_SCALE ):
123  pContext = new ScXMLColorScaleFormatContext( GetScImport(), mxFormat.get() );
124  break;
125  case XML_ELEMENT( CALC_EXT, XML_DATA_BAR ):
126  pContext = new ScXMLDataBarFormatContext( GetScImport(), pAttribList, mxFormat.get() );
127  break;
128  case XML_ELEMENT( CALC_EXT, XML_ICON_SET ):
129  pContext = new ScXMLIconSetFormatContext( GetScImport(), pAttribList, mxFormat.get() );
130  break;
131  case XML_ELEMENT( CALC_EXT, XML_DATE_IS ):
132  pContext = new ScXMLDateContext( GetScImport(), pAttribList, mxFormat.get() );
133  break;
134  default:
135  break;
136  }
137 
138  return pContext;
139 }
140 
141 static bool HasRelRefIgnoringSheet0Relative( ScDocument* pDoc, const ScTokenArray* pTokens, sal_uInt16 nRecursion = 0 )
142 {
143  if (pTokens)
144  {
145  formula::FormulaTokenArrayPlainIterator aIter( *pTokens );
147  for( t = aIter.Next(); t; t = aIter.Next() )
148  {
149  switch( t->GetType() )
150  {
152  {
153  ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
154  if ( rRef2.IsColRel() || rRef2.IsRowRel() || (rRef2.IsFlag3D() && rRef2.IsTabRel()) )
155  return true;
156  [[fallthrough]];
157  }
158 
160  {
161  ScSingleRefData& rRef1 = *t->GetSingleRef();
162  if ( rRef1.IsColRel() || rRef1.IsRowRel() || (rRef1.IsFlag3D() && rRef1.IsTabRel()) )
163  return true;
164  }
165  break;
166 
167  case formula::svIndex:
168  {
169  if( t->GetOpCode() == ocName ) // DB areas always absolute
170  if( ScRangeData* pRangeData = pDoc->FindRangeNameBySheetAndIndex( t->GetSheet(), t->GetIndex()) )
171  if( (nRecursion < 42) && HasRelRefIgnoringSheet0Relative( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
172  return true;
173  }
174  break;
175 
176  // #i34474# function result dependent on cell position
177  case formula::svByte:
178  {
179  switch( t->GetOpCode() )
180  {
181  case ocRow: // ROW() returns own row index
182  case ocColumn: // COLUMN() returns own column index
183  case ocSheet: // SHEET() returns own sheet index
184  case ocCell: // CELL() may return own cell address
185  return true;
186  default:
187  break;
188  }
189  }
190  break;
191 
192  default:
193  break;
194  }
195  }
196  }
197  return false;
198 }
199 
200 static bool HasOneSingleFullyRelativeReference( const ScTokenArray* pTokens, ScSingleRefData& rOffset )
201 {
202  int nCount = 0;
203  if (pTokens)
204  {
205  formula::FormulaTokenArrayPlainIterator aIter( *pTokens );
207  for( t = aIter.Next(); t; t = aIter.Next() )
208  {
209  switch( t->GetType() )
210  {
212  {
213  ScSingleRefData& rRef1 = *t->GetSingleRef();
214  if ( rRef1.IsColRel() && rRef1.IsRowRel() && !rRef1.IsFlag3D() && rRef1.IsTabRel() )
215  {
216  nCount++;
217  if (nCount == 1)
218  {
219  rOffset = rRef1;
220  }
221  }
222  }
223  break;
224 
225  default:
226  break;
227  }
228  }
229  }
230  return nCount == 1;
231 }
232 
233 void SAL_CALL ScXMLConditionalFormatContext::endFastElement( sal_Int32 /*nElement*/ )
234 {
235  ScDocument* pDoc = GetScImport().GetDocument();
236  assert(pDoc);
237 
239  std::unique_ptr<ScConditionalFormat> pFormat(std::move(mxFormat));
240 
241  bool bEligibleForCache = true;
242  bool bSingleRelativeReference = false;
243  ScSingleRefData aOffsetForSingleRelRef;
244  std::unique_ptr<ScTokenArray> pTokens;
245  for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx)
246  {
247  auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx);
248  auto pCondFormatEntry = dynamic_cast<const ScCondFormatEntry*>(pFormatEntry);
249 
250  if (pCondFormatEntry == nullptr ||
251  (pCondFormatEntry->GetOperation() != ScConditionMode::Equal &&
252  pCondFormatEntry->GetOperation() != ScConditionMode::Direct))
253  {
254  bEligibleForCache = false;
255  break;
256  }
257 
258  ScAddress aSrcPos;
259  OUString aSrcString = pCondFormatEntry->GetSrcString();
260  if ( !aSrcString.isEmpty() )
261  aSrcPos.Parse( aSrcString, *pDoc );
262  ScCompiler aComp( *pDoc, aSrcPos );
264  pTokens = aComp.CompileString( pCondFormatEntry->GetExpression(aSrcPos, 0), "" );
265  if (HasRelRefIgnoringSheet0Relative( pDoc, pTokens.get() ))
266  {
267  // In general not eligible, but some might be. We handle one very special case: When the
268  // conditional format has one entry, the reference position is the first cell of the
269  // range, and with a single fully relative reference in its expression. (Possibly these
270  // conditions could be loosened, but I am too tired to think on that right now.)
271  if (pFormat->size() == 1 &&
272  pFormat->GetRange().size() == 1 &&
273  pFormat->GetRange()[0].aStart == aSrcPos &&
274  HasOneSingleFullyRelativeReference( pTokens.get(), aOffsetForSingleRelRef ))
275  {
276  bSingleRelativeReference = true;
277  }
278  else
279  {
280  bEligibleForCache = false;
281  break;
282  }
283  }
284  }
285 
286  if (bEligibleForCache)
287  {
288  for (auto& aCacheEntry : mrParent.maCache)
289  if (aCacheEntry.mnAge < SAL_MAX_INT64)
290  aCacheEntry.mnAge++;
291 
292  for (auto& aCacheEntry : mrParent.maCache)
293  {
294  if (!aCacheEntry.mpFormat)
295  continue;
296 
297  if (aCacheEntry.mpFormat->size() != pFormat->size())
298  continue;
299 
300  // Check if the conditional format is identical to an existing one (but with different range) and can be shared
301  for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx)
302  {
303  auto pCacheFormatEntry = aCacheEntry.mpFormat->GetEntry(nFormatEntryIx);
304  auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx);
305  if (pCacheFormatEntry->GetType() != pFormatEntry->GetType() ||
306  pFormatEntry->GetType() != ScFormatEntry::Type::Condition)
307  break;
308 
309  auto pCacheCondFormatEntry = static_cast<const ScCondFormatEntry*>(pCacheFormatEntry);
310  auto pCondFormatEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
311 
312  if (pCacheCondFormatEntry->GetStyle() != pCondFormatEntry->GetStyle())
313  break;
314 
315  // Note That comparing the formulas of the ScConditionEntry at this stage is
316  // comparing just the *strings* of the formulas. For the bSingleRelativeReference
317  // case we compare the tokenized ("compiled") formulas.
318  if (bSingleRelativeReference)
319  {
320  if (aCacheEntry.mbSingleRelativeReference &&
321  pTokens->EqualTokens(aCacheEntry.mpTokens.get()))
322  ;
323  else
324  break;
325  }
326  else if (!pCacheCondFormatEntry->IsEqual(*pCondFormatEntry, /*bIgnoreSrcPos*/true))
327  {
328  break;
329  }
330  // If we get here on the last round through the for loop, we have a cache hit
331  if (nFormatEntryIx == pFormat->size() - 1)
332  {
333  // Mark cache entry as fresh, do necessary mangling of it and just return
334  aCacheEntry.mnAge = 0;
335  for (size_t k = 0; k < pFormat->GetRange().size(); ++k)
336  aCacheEntry.mpFormat->GetRangeList().Join(pFormat->GetRange()[k]);
337  return;
338  }
339  }
340  }
341  }
342 
343  sal_uLong nIndex = pDoc->AddCondFormat(std::move(pFormat), nTab);
344  ScConditionalFormat* pInsertedFormat = pDoc->GetCondFormList(nTab)->GetFormat(nIndex);
345  assert(pInsertedFormat && pInsertedFormat->GetKey() == nIndex);
346 
347  mrParent.mvCondFormatData.push_back( { pInsertedFormat, nTab } );
348 
349  if (!bEligibleForCache)
350  return;
351 
352  // Not found in cache, replace oldest cache entry
353  sal_Int64 nOldestAge = -1;
354  size_t nIndexOfOldest = 0;
355  for (auto& aCacheEntry : mrParent.maCache)
356  {
357  if (aCacheEntry.mnAge > nOldestAge)
358  {
359  nOldestAge = aCacheEntry.mnAge;
360  nIndexOfOldest = (&aCacheEntry - &mrParent.maCache.front());
361  }
362  }
363  mrParent.maCache[nIndexOfOldest].mpFormat = pInsertedFormat;
364  mrParent.maCache[nIndexOfOldest].mbSingleRelativeReference = bSingleRelativeReference;
365  mrParent.maCache[nIndexOfOldest].mpTokens = std::move(pTokens);
366  mrParent.maCache[nIndexOfOldest].mnAge = 0;
367 }
368 
370 {
371 }
372 
374  ScConditionalFormat* pFormat):
375  ScXMLImportContext( rImport ),
376  pColorScaleFormat(nullptr)
377 {
378  pColorScaleFormat = new ScColorScaleFormat(GetScImport().GetDocument());
379  pFormat->AddEntry(pColorScaleFormat);
380 }
381 
382 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLColorScaleFormatContext::createFastChildContext(
383  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
384 {
385  SvXMLImportContext* pContext = nullptr;
386  sax_fastparser::FastAttributeList *pAttribList =
388 
389  switch (nElement)
390  {
391  case XML_ELEMENT( CALC_EXT, XML_COLOR_SCALE_ENTRY ):
392  pContext = new ScXMLColorScaleFormatEntryContext( GetScImport(), pAttribList, pColorScaleFormat );
393  break;
394  default:
395  break;
396  }
397 
398  return pContext;
399 }
400 
403  ScConditionalFormat* pFormat):
404  ScXMLImportContext( rImport ),
405  mpFormatData(nullptr),
406  mpParent(pFormat),
407  mnIndex(0)
408 {
409  OUString sPositiveColor;
410  OUString sNegativeColor;
411  OUString sGradient;
412  OUString sAxisPosition;
413  OUString sShowValue;
414  OUString sAxisColor;
415  OUString sMinLength;
416  OUString sMaxLength;
417 
418  if ( rAttrList.is() )
419  {
420  for (auto &aIter : *rAttrList)
421  {
422  switch (aIter.getToken())
423  {
424  case XML_ELEMENT( CALC_EXT, XML_POSITIVE_COLOR ):
425  sPositiveColor = aIter.toString();
426  break;
427  case XML_ELEMENT( CALC_EXT, XML_GRADIENT ):
428  sGradient = aIter.toString();
429  break;
430  case XML_ELEMENT( CALC_EXT, XML_NEGATIVE_COLOR ):
431  sNegativeColor = aIter.toString();
432  break;
433  case XML_ELEMENT( CALC_EXT, XML_AXIS_POSITION ):
434  sAxisPosition = aIter.toString();
435  break;
436  case XML_ELEMENT( CALC_EXT, XML_SHOW_VALUE ):
437  sShowValue = aIter.toString();
438  break;
439  case XML_ELEMENT( CALC_EXT, XML_AXIS_COLOR ):
440  sAxisColor = aIter.toString();
441  break;
442  case XML_ELEMENT( CALC_EXT, XML_MIN_LENGTH ):
443  sMinLength = aIter.toString();
444  break;
445  case XML_ELEMENT( CALC_EXT, XML_MAX_LENGTH ):
446  sMaxLength = aIter.toString();
447  break;
448  default:
449  break;
450  }
451  }
452  }
453 
454  ScDataBarFormat* pDataBarFormat = new ScDataBarFormat(rImport.GetDocument());
456  pDataBarFormat->SetDataBarData(mpFormatData);
457  if(!sGradient.isEmpty())
458  {
459  bool bGradient = true;
460  (void)sax::Converter::convertBool( bGradient, sGradient);
461  mpFormatData->mbGradient = bGradient;
462  }
463 
464  if(!sPositiveColor.isEmpty())
465  {
466  sax::Converter::convertColor( mpFormatData->maPositiveColor, sPositiveColor );
467  }
468 
469  if(!sNegativeColor.isEmpty())
470  {
471  // we might check here for 0xff0000 and don't write it
472  Color nColor;
473  sax::Converter::convertColor( nColor, sNegativeColor );
474  mpFormatData->mpNegativeColor.reset(new Color(nColor));
475  }
476  else
477  mpFormatData->mbNeg = false;
478 
479  if(!sAxisPosition.isEmpty())
480  {
481  if(sAxisPosition == "middle")
482  mpFormatData->meAxisPosition = databar::MIDDLE;
483  else if (sAxisPosition == "none")
484  mpFormatData->meAxisPosition = databar::NONE;
485  }
486 
487  if(!sAxisColor.isEmpty())
488  {
489  sax::Converter::convertColor( mpFormatData->maAxisColor, sAxisColor );
490  }
491 
492  if(!sShowValue.isEmpty())
493  {
494  bool bShowValue = true;
495  (void)sax::Converter::convertBool( bShowValue, sShowValue );
496  mpFormatData->mbOnlyBar = !bShowValue;
497  }
498 
499  if (!sMinLength.isEmpty())
500  {
501  double nVal = sMinLength.toDouble();
502  mpFormatData->mnMinLength = nVal;
503  }
504 
505  if (!sMaxLength.isEmpty())
506  {
507  double nVal = sMaxLength.toDouble();
508  if (nVal == 0.0)
509  nVal = 100.0;
510  mpFormatData->mnMaxLength = nVal;
511  }
512 
513  pFormat->AddEntry(pDataBarFormat);
514 }
515 
516 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLDataBarFormatContext::createFastChildContext(
517  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
518 {
519  SvXMLImportContext* pContext = nullptr;
520  sax_fastparser::FastAttributeList *pAttribList =
522 
523  switch (nElement)
524  {
525  case XML_ELEMENT( CALC_EXT, XML_FORMATTING_ENTRY ):
526  case XML_ELEMENT( CALC_EXT, XML_DATA_BAR_ENTRY ):
527  {
528  ScColorScaleEntry* pEntry(nullptr);
529  pContext = new ScXMLFormattingEntryContext( GetScImport(), pAttribList, pEntry );
530  pEntry->SetRepaintCallback(mpParent);
531  if(mnIndex == 0)
532  {
533  mpFormatData->mpLowerLimit.reset(pEntry);
534  }
535  else if (mnIndex == 1)
536  {
537  mpFormatData->mpUpperLimit.reset(pEntry);
538  }
539  else
540  {
541  // data bars only support 2 entries
542  assert(false);
543  }
544  ++mnIndex;
545  }
546  break;
547  default:
548  break;
549  }
550 
551  return pContext;
552 }
553 
556  ScConditionalFormat* pFormat):
557  ScXMLImportContext( rImport ),
558  mpParent(pFormat)
559 {
560  OUString aIconSetType, sShowValue;
561  if ( rAttrList.is() )
562  {
563  for (auto &aIter : *rAttrList)
564  {
565  switch (aIter.getToken())
566  {
567  case XML_ELEMENT( CALC_EXT, XML_ICON_SET_TYPE ):
568  aIconSetType = aIter.toString();
569  break;
570  case XML_ELEMENT( CALC_EXT, XML_SHOW_VALUE ):
571  sShowValue = aIter.toString();
572  break;
573  default:
574  break;
575  }
576  }
577  }
578 
581  for(; pMap->pName; ++pMap)
582  {
583  OUString aName = OUString::createFromAscii(pMap->pName);
584  if(aName ==aIconSetType)
585  {
586  eType = pMap->eType;
587  break;
588  }
589  }
590 
591  ScIconSetFormat* pIconSetFormat = new ScIconSetFormat(GetScImport().GetDocument());
592  ScIconSetFormatData* pIconSetFormatData = new ScIconSetFormatData;
593 
594  if(!sShowValue.isEmpty())
595  {
596  bool bShowValue = true;
597  (void)sax::Converter::convertBool( bShowValue, sShowValue );
598  pIconSetFormatData->mbShowValue = !bShowValue;
599  }
600 
601  pIconSetFormatData->eIconSetType = eType;
602  pIconSetFormat->SetIconSetData(pIconSetFormatData);
603  pFormat->AddEntry(pIconSetFormat);
604 
605  mpFormatData = pIconSetFormatData;
606 }
607 
608 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLIconSetFormatContext::createFastChildContext(
609  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
610 {
611  SvXMLImportContext* pContext = nullptr;
612  sax_fastparser::FastAttributeList *pAttribList =
614 
615  switch (nElement)
616  {
617  case XML_ELEMENT( CALC_EXT, XML_FORMATTING_ENTRY ):
618  {
619  ScColorScaleEntry* pEntry(nullptr);
620  pContext = new ScXMLFormattingEntryContext( GetScImport(), pAttribList, pEntry );
621  mpFormatData->m_Entries.emplace_back(pEntry);
622  pEntry->SetRepaintCallback(mpParent);
623  }
624  break;
625  default:
626  break;
627  }
628 
629  return pContext;
630 }
631 
632 namespace {
633 
634 void GetConditionData(const OUString& rValue, ScConditionMode& eMode, OUString& rExpr1, OUString& rExpr2)
635 {
636  if(rValue.startsWith("unique"))
637  {
639  }
640  else if(rValue.startsWith("duplicate"))
641  {
643  }
644  else if(rValue.startsWith("between"))
645  {
646  const sal_Unicode* pStr = rValue.getStr();
647  const sal_Unicode* pStart = pStr + 8;
648  const sal_Unicode* pEnd = pStr + rValue.getLength();
649  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ',');
650  rExpr2 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
651  eMode = ScConditionMode::Between;
652  }
653  else if(rValue.startsWith("not-between"))
654  {
655  const sal_Unicode* pStr = rValue.getStr();
656  const sal_Unicode* pStart = pStr + 12;
657  const sal_Unicode* pEnd = pStr + rValue.getLength();
658  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ',');
659  rExpr2 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
661  }
662  else if(rValue.startsWith("<="))
663  {
664  rExpr1 = rValue.copy(2);
665  eMode = ScConditionMode::EqLess;
666  }
667  else if(rValue.startsWith(">="))
668  {
669  rExpr1 = rValue.copy(2);
671  }
672  else if(rValue.startsWith("!="))
673  {
674  rExpr1 = rValue.copy(2);
676  }
677  else if(rValue.startsWith("<"))
678  {
679  rExpr1 = rValue.copy(1);
680  eMode = ScConditionMode::Less;
681  }
682  else if(rValue.startsWith("="))
683  {
684  rExpr1 = rValue.copy(1);
685  eMode = ScConditionMode::Equal;
686  }
687  else if(rValue.startsWith(">"))
688  {
689  rExpr1 = rValue.copy(1);
690  eMode = ScConditionMode::Greater;
691  }
692  else if(rValue.startsWith("formula-is"))
693  {
694  const sal_Unicode* pStr = rValue.getStr();
695  const sal_Unicode* pStart = pStr + 11;
696  const sal_Unicode* pEnd = pStr + rValue.getLength();
697  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
698  eMode = ScConditionMode::Direct;
699  }
700  else if(rValue.startsWith("top-elements"))
701  {
702  const sal_Unicode* pStr = rValue.getStr();
703  const sal_Unicode* pStart = pStr + 13;
704  const sal_Unicode* pEnd = pStr + rValue.getLength();
705  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
706  eMode = ScConditionMode::Top10;
707  }
708  else if(rValue.startsWith("bottom-elements"))
709  {
710  const sal_Unicode* pStr = rValue.getStr();
711  const sal_Unicode* pStart = pStr + 16;
712  const sal_Unicode* pEnd = pStr + rValue.getLength();
713  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
715  }
716  else if(rValue.startsWith("top-percent"))
717  {
718  const sal_Unicode* pStr = rValue.getStr();
719  const sal_Unicode* pStart = pStr + 12;
720  const sal_Unicode* pEnd = pStr + rValue.getLength();
721  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
723  }
724  else if(rValue.startsWith("bottom-percent"))
725  {
726  const sal_Unicode* pStr = rValue.getStr();
727  const sal_Unicode* pStart = pStr + 15;
728  const sal_Unicode* pEnd = pStr + rValue.getLength();
729  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
731  }
732  else if(rValue.startsWith("above-average"))
733  {
735  }
736  else if(rValue.startsWith("below-average"))
737  {
739  }
740  else if(rValue.startsWith("above-equal-average"))
741  {
743  }
744  else if(rValue.startsWith("below-equal-average"))
745  {
747  }
748  else if(rValue.startsWith("is-error"))
749  {
750  eMode = ScConditionMode::Error;
751  }
752  else if(rValue.startsWith("is-no-error"))
753  {
754  eMode = ScConditionMode::NoError;
755  }
756  else if(rValue.startsWith("begins-with"))
757  {
759  const sal_Unicode* pStr = rValue.getStr();
760  const sal_Unicode* pStart = pStr + 12;
761  const sal_Unicode* pEnd = pStr + rValue.getLength();
762  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
763  }
764  else if(rValue.startsWith("ends-with"))
765  {
767  const sal_Unicode* pStr = rValue.getStr();
768  const sal_Unicode* pStart = pStr + 10;
769  const sal_Unicode* pEnd = pStr + rValue.getLength();
770  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
771  }
772  else if(rValue.startsWith("contains-text"))
773  {
775  const sal_Unicode* pStr = rValue.getStr();
776  const sal_Unicode* pStart = pStr + 14;
777  const sal_Unicode* pEnd = pStr + rValue.getLength();
778  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
779  }
780  else if(rValue.startsWith("not-contains-text"))
781  {
783  const sal_Unicode* pStr = rValue.getStr();
784  const sal_Unicode* pStart = pStr + 18;
785  const sal_Unicode* pEnd = pStr + rValue.getLength();
786  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
787  }
788  else
789  eMode = ScConditionMode::NONE;
790 }
791 
792 }
793 
796  ScConditionalFormat* pFormat ):
797  ScXMLImportContext( rImport )
798 {
799  OUString sExpression;
800  OUString sStyle;
801  OUString sAddress;
802 
803  if ( rAttrList.is() )
804  {
805  for (auto &aIter : *rAttrList)
806  {
807  switch (aIter.getToken())
808  {
809  case XML_ELEMENT( CALC_EXT, XML_VALUE ):
810  sExpression = aIter.toString();
811  break;
812  case XML_ELEMENT( CALC_EXT, XML_APPLY_STYLE_NAME ):
813  sStyle = ScStyleNameConversion::ProgrammaticToDisplayName(aIter.toString(), SfxStyleFamily::Para );
814  break;
815  case XML_ELEMENT( CALC_EXT, XML_BASE_CELL_ADDRESS ):
816  sAddress = aIter.toString();
817  break;
818  default:
819  break;
820  }
821  }
822  }
823 
824  OUString aExpr1;
825  OUString aExpr2;
826  ScConditionMode eMode;
827  GetConditionData(sExpression, eMode, aExpr1, aExpr2);
828 
829  ScCondFormatEntry* pFormatEntry = new ScCondFormatEntry(eMode, aExpr1, aExpr2, *GetScImport().GetDocument(), ScAddress(), sStyle,
831  pFormatEntry->SetSrcString(sAddress);
832 
833  pFormat->AddEntry(pFormatEntry);
834 }
835 
836 namespace {
837 
838 void setColorEntryType(const OUString& rType, ScColorScaleEntry* pEntry, const OUString& rFormula,
839  ScXMLImport& rImport)
840 {
841  if(rType == "minimum")
842  pEntry->SetType(COLORSCALE_MIN);
843  else if(rType == "maximum")
844  pEntry->SetType(COLORSCALE_MAX);
845  else if(rType == "percentile")
847  else if(rType == "percent")
848  pEntry->SetType(COLORSCALE_PERCENT);
849  else if(rType == "formula")
850  {
851  pEntry->SetType(COLORSCALE_FORMULA);
852  //position does not matter, only table is important
853  pEntry->SetFormula(rFormula, *rImport.GetDocument(), ScAddress(0,0,rImport.GetTables().GetCurrentSheet()), formula::FormulaGrammar::GRAM_ODFF);
854  }
855  else if(rType == "auto-minimum")
856  pEntry->SetType(COLORSCALE_AUTO);
857  else if(rType == "auto-maximum")
858  pEntry->SetType(COLORSCALE_AUTO);
859 }
860 
861 }
862 
865  ScColorScaleFormat* pFormat):
866  ScXMLImportContext( rImport )
867 {
868  double nVal = 0;
869  Color aColor;
870 
871  OUString sType;
872  OUString sVal;
873  OUString sColor;
874 
875  if ( rAttrList.is() )
876  {
877  for (auto &aIter : *rAttrList)
878  {
879  switch (aIter.getToken())
880  {
881  case XML_ELEMENT( CALC_EXT, XML_TYPE ):
882  sType = aIter.toString();
883  break;
884  case XML_ELEMENT( CALC_EXT, XML_VALUE ):
885  sVal = aIter.toString();
886  break;
887  case XML_ELEMENT( CALC_EXT, XML_COLOR ):
888  sColor = aIter.toString();
889  break;
890  default:
891  break;
892  }
893  }
894  }
895 
896  sax::Converter::convertColor(aColor, sColor);
897 
898  if(!sVal.isEmpty())
899  sax::Converter::convertDouble(nVal, sVal);
900 
901  auto pFormatEntry = new ScColorScaleEntry(nVal, aColor);
902  setColorEntryType(sType, pFormatEntry, sVal, GetScImport());
903  pFormat->AddEntry(pFormatEntry);
904 }
905 
908  ScColorScaleEntry*& pColorScaleEntry):
909  ScXMLImportContext( rImport )
910 {
911  OUString sVal;
912  OUString sType;
913 
914  if ( rAttrList.is() )
915  {
916  for (auto &aIter : *rAttrList)
917  {
918  switch (aIter.getToken())
919  {
920  case XML_ELEMENT( CALC_EXT, XML_TYPE ):
921  sType = aIter.toString();
922  break;
923  case XML_ELEMENT( CALC_EXT, XML_VALUE ):
924  sVal = aIter.toString();
925  break;
926  default:
927  break;
928  }
929  }
930  }
931 
932  double nVal = 0;
933  if(!sVal.isEmpty())
934  sax::Converter::convertDouble(nVal, sVal);
935 
936  pColorScaleEntry = new ScColorScaleEntry(nVal, Color());
937  setColorEntryType(sType, pColorScaleEntry, sVal, GetScImport());
938 }
939 
940 namespace {
941 
942 condformat::ScCondFormatDateType getDateFromString(const OUString& rString)
943 {
944  if(rString == "today")
945  return condformat::TODAY;
946  else if(rString == "yesterday")
947  return condformat::YESTERDAY;
948  else if(rString == "tomorrow")
949  return condformat::TOMORROW;
950  else if(rString == "last-7-days")
951  return condformat::LAST7DAYS;
952  else if(rString == "this-week")
953  return condformat::THISWEEK;
954  else if(rString == "last-week")
955  return condformat::LASTWEEK;
956  else if(rString == "next-week")
957  return condformat::NEXTWEEK;
958  else if(rString == "this-month")
959  return condformat::THISMONTH;
960  else if(rString == "last-month")
961  return condformat::LASTMONTH;
962  else if(rString == "next-month")
963  return condformat::NEXTMONTH;
964  else if(rString == "this-year")
965  return condformat::THISYEAR;
966  else if(rString == "last-year")
967  return condformat::LASTYEAR;
968  else if(rString == "next-year")
969  return condformat::NEXTYEAR;
970 
971  SAL_WARN("sc", "unknown date type: " << rString);
972  return condformat::TODAY;
973 }
974 
975 }
976 
979  ScConditionalFormat* pFormat ):
980  ScXMLImportContext( rImport )
981 {
982  OUString sDateType, sStyle;
983  if ( rAttrList.is() )
984  {
985  for (auto &aIter : *rAttrList)
986  {
987  switch (aIter.getToken())
988  {
989  case XML_ELEMENT( CALC_EXT, XML_DATE ):
990  sDateType = aIter.toString();
991  break;
992  case XML_ELEMENT( CALC_EXT, XML_STYLE ):
993  sStyle = ScStyleNameConversion::ProgrammaticToDisplayName(aIter.toString(), SfxStyleFamily::Para );
994  break;
995  default:
996  break;
997  }
998  }
999  }
1000 
1001  ScCondDateFormatEntry* pFormatEntry = new ScCondDateFormatEntry(GetScImport().GetDocument());
1002  pFormatEntry->SetStyleName(sStyle);
1003  pFormatEntry->SetDateType(getDateFromString(sDateType));
1004  pFormat->AddEntry(pFormatEntry);
1005 
1006 }
1007 
1008 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsTabRel() const
Definition: refdata.hxx:70
void SetGrammar(const formula::FormulaGrammar::Grammar eGrammar)
Definition: compiler.cxx:231
void SetRepaintCallback(ScConditionalFormat *pParent)
Definition: colorscale.cxx:316
sal_Int32 nIndex
ocCell
XML_FORMATTING_ENTRY
XML_ICON_SET_TYPE
ScXMLConditionalFormatsContext(ScXMLImport &rImport)
void AddEntry(ScFormatEntry *pNew)
Definition: conditio.cxx:1747
ocName
static bool convertBool(bool &rBool, const OUString &rString)
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
Single reference (one address) into the sheet.
Definition: refdata.hxx:30
SCTAB GetCurrentSheet() const
Definition: xmlsubti.hxx:85
ScDocument * GetDocument()
Definition: xmlimprt.hxx:296
sal_uIntPtr sal_uLong
XML_APPLY_STYLE_NAME
ScMyTables & GetTables()
Definition: xmlimprt.hxx:299
std::unique_ptr< ScTokenArray > CompileString(const OUString &rFormula)
Tokenize formula expression string into an array of tokens.
Definition: compiler.cxx:4535
XML_VALUE
XML_CONDITIONAL_FORMAT
XML_MAX_LENGTH
ScXMLFormattingEntryContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScColorScaleEntry *&pData)
XML_POSITIVE_COLOR
SC_DLLPUBLIC sal_uLong AddCondFormat(std::unique_ptr< ScConditionalFormat > pNew, SCTAB nTab)
Definition: documen4.cxx:705
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
OpCode GetOpCode() const
static OUString ProgrammaticToDisplayName(const OUString &rProgName, SfxStyleFamily nType)
ScXMLCondContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScConditionalFormat *pFormat)
ScCondFormatDateType
Definition: conditio.hxx:485
static const ScIconSetMap g_IconSetMap[]
Definition: colorscale.hxx:381
ScConditionalFormat * GetFormat(sal_uInt32 nKey)
Definition: conditio.cxx:2069
ScXMLConditionalFormatsContext & mrParent
ocRow
virtual sal_Int16 GetSheet() const
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
sal_uInt16 sal_Unicode
SC_DLLPUBLIC ScConditionalFormatList * GetCondFormList(SCTAB nTab) const
Definition: documen4.cxx:857
XML_STYLE
void SetSrcString(const OUString &rNew)
Definition: conditio.cxx:460
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
ScIconSetType eIconSetType
Definition: colorscale.hxx:334
bool CheckAllEntries(const Link< ScConditionalFormat *, void > &rLink=Link< ScConditionalFormat *, void >())
Checks that all cond formats have a non empty range.
Definition: conditio.cxx:2167
int nCount
XML_TYPE
virtual const ScSingleRefData * GetSingleRef() const
XML_COLOR_SCALE
ScXMLIconSetFormatContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScConditionalFormat *pFormat)
static bool HasOneSingleFullyRelativeReference(const ScTokenArray *pTokens, ScSingleRefData &rOffset)
ScConditionMode
Definition: conditio.hxx:61
ScColorScaleFormat * pColorScaleFormat
virtual void SAL_CALL endFastElement(sal_Int32 nElement) override
bool IsColRel() const
Definition: refdata.hxx:66
XML_AXIS_COLOR
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
DocumentType eType
ScXMLColorScaleFormatContext(ScXMLImport &rImport, ScConditionalFormat *pFormat)
sal_uInt32 GetKey() const
Definition: conditio.hxx:592
This class exists only to provide GetScImport() to its derived classes.
OptionalString sType
virtual const ScComplexRefData * GetDoubleRef() const
int i
XML_DATE
void AddEntry(ScColorScaleEntry *pEntry)
Definition: colorscale.cxx:402
ocSheet
ScSingleRefData Ref2
Definition: refdata.hxx:126
XML_ICON_SET
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
bool IsRowRel() const
Definition: refdata.hxx:68
ScIconSetType eType
Definition: colorscale.hxx:217
ScXMLImport & GetScImport()
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
XML_NEGATIVE_COLOR
XML_AXIS_POSITION
void SetFormula(const OUString &rFormula, ScDocument &rDoc, const ScAddress &rAddr, formula::FormulaGrammar::Grammar eGrammar=formula::FormulaGrammar::GRAM_DEFAULT)
Definition: colorscale.cxx:207
XML_COLOR_SCALE_ENTRY
ScDataBarFormatData * mpFormatData
virtual sal_uInt16 GetIndex() const
bool IsFlag3D() const
Definition: refdata.hxx:91
XPropertyListType t
RegionData_Impl * mpParent
XML_GRADIENT
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
IMPL_LINK(ScXMLConditionalFormatsContext, FormatDeletedHdl, ScConditionalFormat *, pFormat, void)
#define SAL_WARN_IF(condition, area, stream)
XML_DATA_BAR_ENTRY
void SetIconSetData(ScIconSetFormatData *pData)
std::unique_ptr< ScColorScaleEntry, o3tl::default_delete< ScColorScaleEntry > > mpUpperLimit
Definition: colorscale.hxx:185
OUString getExpression(const sal_Unicode *&rpcString, const sal_Unicode *pcEnd, sal_Unicode cEndChar)
static bool convertColor(sal_Int32 &rColor, const OUString &rValue)
ScXMLColorScaleFormatEntryContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScColorScaleFormat *pFormat)
OUString aName
#define XML_ELEMENT(prefix, name)
void SetDateType(condformat::ScCondFormatDateType eType)
Definition: conditio.cxx:1672
ScConditionalFormat * mpParent
XML_TARGET_RANGE_ADDRESS
XML_MIN_LENGTH
const char * pName
Definition: colorscale.hxx:216
ScConditionalFormat * mpParent
XML_SHOW_VALUE
static bool GetRangeListFromString(ScRangeList &rRangeList, const OUString &rRangeListStr, const ScDocument &rDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Unicode cSeparator= ' ', sal_Unicode cQuote= '\'')
Definition: rangeutl.cxx:526
ScIconSetType
Definition: colorscale.hxx:189
XML_BASE_CELL_ADDRESS
#define SAL_WARN(area, stream)
SC_DLLPUBLIC ScRefFlags Parse(const OUString &, const ScDocument &, const Details &rDetails=detailsOOOa1, ExternalInfo *pExtInfo=nullptr, const css::uno::Sequence< css::sheet::ExternalLinkInfo > *pExternalLinks=nullptr, sal_Int32 *pSheetEndPos=nullptr, const OUString *pErrRef=nullptr)
Definition: address.cxx:1539
void SetType(ScColorScaleEntryType eType)
Definition: colorscale.cxx:324
std::unique_ptr< ScColorScaleEntry, o3tl::default_delete< ScColorScaleEntry > > mpLowerLimit
Definition: colorscale.hxx:186
std::array< CacheEntry, 4 > maCache
XML_COLOR
int mnIndex
ScXMLConditionalFormatContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScXMLConditionalFormatsContext &rParent)
ScRangeData * FindRangeNameBySheetAndIndex(SCTAB nTab, sal_uInt16 nIndex) const
Find a named expression / range name in either global or a local scope.
Definition: documen3.cxx:264
static bool HasRelRefIgnoringSheet0Relative(ScDocument *pDoc, const ScTokenArray *pTokens, sal_uInt16 nRecursion=0)
virtual void SAL_CALL endFastElement(sal_Int32 nElement) override
ScIconSetFormatData * mpFormatData
XML_DATE_IS
StackVar GetType() const
BaseContainerNodeSharedPtr & mrParent
ScXMLDateContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScConditionalFormat *pFormat)
std::vector< CondFormatData > mvCondFormatData
#define SAL_MAX_INT64
ScXMLDataBarFormatContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScConditionalFormat *pFormat)
void SetCondFormList(ScConditionalFormatList *pList, SCTAB nTab)
Definition: documen4.cxx:865
void SetStyleName(const OUString &rStyleName)
Definition: conditio.cxx:1677
std::unique_ptr< ScConditionalFormat > mxFormat
void SetDataBarData(ScDataBarFormatData *pData)
Definition: colorscale.cxx:721
sal_Int16 SCTAB
Definition: types.hxx:23
XML_DATA_BAR
SC_DLLPUBLIC void AddCondFormatData(const ScRangeList &rRange, SCTAB nTab, sal_uInt32 nIndex)
Definition: document.cxx:4807
ocColumn
XML_CONDITION
void SetNewCondFormatData()
Definition: xmlimprt.hxx:364
virtual ~ScXMLConditionalFormatContext() override
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo