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/xmlnmspe.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  ScRangeStringConverter::GetRangeListFromString(aRangeList, sRange, GetScImport().GetDocument(),
103 
104  mxFormat.reset(new ScConditionalFormat(0, GetScImport().GetDocument()));
105  mxFormat->SetRange(aRangeList);
106 }
107 
108 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLConditionalFormatContext::createFastChildContext(
109  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
110 {
111  SvXMLImportContext* pContext = nullptr;
112  sax_fastparser::FastAttributeList *pAttribList =
114 
115  switch (nElement)
116  {
117  case XML_ELEMENT( CALC_EXT, XML_CONDITION ):
118  pContext = new ScXMLCondContext( GetScImport(), pAttribList, mxFormat.get() );
119  break;
120  case XML_ELEMENT( CALC_EXT, XML_COLOR_SCALE ):
121  pContext = new ScXMLColorScaleFormatContext( GetScImport(), mxFormat.get() );
122  break;
123  case XML_ELEMENT( CALC_EXT, XML_DATA_BAR ):
124  pContext = new ScXMLDataBarFormatContext( GetScImport(), pAttribList, mxFormat.get() );
125  break;
126  case XML_ELEMENT( CALC_EXT, XML_ICON_SET ):
127  pContext = new ScXMLIconSetFormatContext( GetScImport(), pAttribList, mxFormat.get() );
128  break;
129  case XML_ELEMENT( CALC_EXT, XML_DATE_IS ):
130  pContext = new ScXMLDateContext( GetScImport(), pAttribList, mxFormat.get() );
131  break;
132  default:
133  break;
134  }
135 
136  return pContext;
137 }
138 
139 static bool HasRelRefIgnoringSheet0Relative( ScDocument* pDoc, const ScTokenArray* pTokens, sal_uInt16 nRecursion = 0 )
140 {
141  if (pTokens)
142  {
143  formula::FormulaTokenArrayPlainIterator aIter( *pTokens );
145  for( t = aIter.Next(); t; t = aIter.Next() )
146  {
147  switch( t->GetType() )
148  {
150  {
151  ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
152  if ( rRef2.IsColRel() || rRef2.IsRowRel() || (rRef2.IsFlag3D() && rRef2.IsTabRel()) )
153  return true;
154  [[fallthrough]];
155  }
156 
158  {
159  ScSingleRefData& rRef1 = *t->GetSingleRef();
160  if ( rRef1.IsColRel() || rRef1.IsRowRel() || (rRef1.IsFlag3D() && rRef1.IsTabRel()) )
161  return true;
162  }
163  break;
164 
165  case formula::svIndex:
166  {
167  if( t->GetOpCode() == ocName ) // DB areas always absolute
168  if( ScRangeData* pRangeData = pDoc->FindRangeNameBySheetAndIndex( t->GetSheet(), t->GetIndex()) )
169  if( (nRecursion < 42) && HasRelRefIgnoringSheet0Relative( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
170  return true;
171  }
172  break;
173 
174  // #i34474# function result dependent on cell position
175  case formula::svByte:
176  {
177  switch( t->GetOpCode() )
178  {
179  case ocRow: // ROW() returns own row index
180  case ocColumn: // COLUMN() returns own column index
181  case ocSheet: // SHEET() returns own sheet index
182  case ocCell: // CELL() may return own cell address
183  return true;
184  default:
185  break;
186  }
187  }
188  break;
189 
190  default:
191  break;
192  }
193  }
194  }
195  return false;
196 }
197 
198 static bool HasOneSingleFullyRelativeReference( const ScTokenArray* pTokens, ScSingleRefData& rOffset )
199 {
200  int nCount = 0;
201  if (pTokens)
202  {
203  formula::FormulaTokenArrayPlainIterator aIter( *pTokens );
205  for( t = aIter.Next(); t; t = aIter.Next() )
206  {
207  switch( t->GetType() )
208  {
210  {
211  ScSingleRefData& rRef1 = *t->GetSingleRef();
212  if ( rRef1.IsColRel() && rRef1.IsRowRel() && !rRef1.IsFlag3D() && rRef1.IsTabRel() )
213  {
214  nCount++;
215  if (nCount == 1)
216  {
217  rOffset = rRef1;
218  }
219  }
220  }
221  break;
222 
223  default:
224  break;
225  }
226  }
227  }
228  return nCount == 1;
229 }
230 
231 void SAL_CALL ScXMLConditionalFormatContext::endFastElement( sal_Int32 /*nElement*/ )
232 {
233  ScDocument* pDoc = GetScImport().GetDocument();
234 
236  std::unique_ptr<ScConditionalFormat> pFormat(std::move(mxFormat));
237 
238  bool bEligibleForCache = true;
239  bool bSingleRelativeReference = false;
240  ScSingleRefData aOffsetForSingleRelRef;
241  std::unique_ptr<ScTokenArray> pTokens;
242  for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx)
243  {
244  auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx);
245  auto pCondFormatEntry = dynamic_cast<const ScCondFormatEntry*>(pFormatEntry);
246 
247  if (pCondFormatEntry == nullptr ||
248  (pCondFormatEntry->GetOperation() != ScConditionMode::Equal &&
249  pCondFormatEntry->GetOperation() != ScConditionMode::Direct))
250  {
251  bEligibleForCache = false;
252  break;
253  }
254 
255  ScAddress aSrcPos;
256  OUString aSrcString = pCondFormatEntry->GetSrcString();
257  if ( !aSrcString.isEmpty() )
258  aSrcPos.Parse( aSrcString, pDoc );
259  ScCompiler aComp( pDoc, aSrcPos );
261  pTokens = aComp.CompileString( pCondFormatEntry->GetExpression(aSrcPos, 0), "" );
262  if (HasRelRefIgnoringSheet0Relative( pDoc, pTokens.get() ))
263  {
264  // In general not eligible, but some might be. We handle one very special case: When the
265  // conditional format has one entry, the reference position is the first cell of the
266  // range, and with a single fully relative reference in its expression. (Possibly these
267  // conditions could be loosened, but I am too tired to think on that right now.)
268  if (pFormat->size() == 1 &&
269  pFormat->GetRange().size() == 1 &&
270  pFormat->GetRange()[0].aStart == aSrcPos &&
271  HasOneSingleFullyRelativeReference( pTokens.get(), aOffsetForSingleRelRef ))
272  {
273  bSingleRelativeReference = true;
274  }
275  else
276  {
277  bEligibleForCache = false;
278  break;
279  }
280  }
281  }
282 
283  if (bEligibleForCache)
284  {
285  for (auto& aCacheEntry : mrParent.maCache)
286  if (aCacheEntry.mnAge < SAL_MAX_INT64)
287  aCacheEntry.mnAge++;
288 
289  for (auto& aCacheEntry : mrParent.maCache)
290  {
291  if (!aCacheEntry.mpFormat)
292  continue;
293 
294  if (aCacheEntry.mpFormat->size() != pFormat->size())
295  continue;
296 
297  // Check if the conditional format is identical to an existing one (but with different range) and can be shared
298  for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx)
299  {
300  auto pCacheFormatEntry = aCacheEntry.mpFormat->GetEntry(nFormatEntryIx);
301  auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx);
302  if (pCacheFormatEntry->GetType() != pFormatEntry->GetType() ||
303  pFormatEntry->GetType() != ScFormatEntry::Type::Condition)
304  break;
305 
306  auto pCacheCondFormatEntry = static_cast<const ScCondFormatEntry*>(pCacheFormatEntry);
307  auto pCondFormatEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
308 
309  if (pCacheCondFormatEntry->GetStyle() != pCondFormatEntry->GetStyle())
310  break;
311 
312  // Note That comparing the formulas of the ScConditionEntry at this stage is
313  // comparing just the *strings* of the formulas. For the bSingleRelativeReference
314  // case we compare the tokenized ("compiled") formulas.
315  if (bSingleRelativeReference)
316  {
317  if (aCacheEntry.mbSingleRelativeReference &&
318  pTokens->EqualTokens(aCacheEntry.mpTokens.get()))
319  ;
320  else
321  break;
322  }
323  else if (!pCacheCondFormatEntry->IsEqual(*pCondFormatEntry, /*bIgnoreSrcPos*/true))
324  {
325  break;
326  }
327  // If we get here on the last round through the for loop, we have a cache hit
328  if (nFormatEntryIx == pFormat->size() - 1)
329  {
330  // Mark cache entry as fresh, do necessary mangling of it and just return
331  aCacheEntry.mnAge = 0;
332  for (size_t k = 0; k < pFormat->GetRange().size(); ++k)
333  aCacheEntry.mpFormat->GetRangeList().Join(pFormat->GetRange()[k]);
334  return;
335  }
336  }
337  }
338  }
339 
340  sal_uLong nIndex = pDoc->AddCondFormat(std::move(pFormat), nTab);
341  ScConditionalFormat* pInsertedFormat = pDoc->GetCondFormList(nTab)->GetFormat(nIndex);
342  assert(pInsertedFormat && pInsertedFormat->GetKey() == nIndex);
343 
344  mrParent.mvCondFormatData.push_back( { pInsertedFormat, nTab } );
345 
346  if (!bEligibleForCache)
347  return;
348 
349  // Not found in cache, replace oldest cache entry
350  sal_Int64 nOldestAge = -1;
351  size_t nIndexOfOldest = 0;
352  for (auto& aCacheEntry : mrParent.maCache)
353  {
354  if (aCacheEntry.mnAge > nOldestAge)
355  {
356  nOldestAge = aCacheEntry.mnAge;
357  nIndexOfOldest = (&aCacheEntry - &mrParent.maCache.front());
358  }
359  }
360  mrParent.maCache[nIndexOfOldest].mpFormat = pInsertedFormat;
361  mrParent.maCache[nIndexOfOldest].mbSingleRelativeReference = bSingleRelativeReference;
362  mrParent.maCache[nIndexOfOldest].mpTokens = std::move(pTokens);
363  mrParent.maCache[nIndexOfOldest].mnAge = 0;
364 }
365 
367 {
368 }
369 
371  ScConditionalFormat* pFormat):
372  ScXMLImportContext( rImport ),
373  pColorScaleFormat(nullptr)
374 {
375  pColorScaleFormat = new ScColorScaleFormat(GetScImport().GetDocument());
376  pFormat->AddEntry(pColorScaleFormat);
377 }
378 
379 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLColorScaleFormatContext::createFastChildContext(
380  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
381 {
382  SvXMLImportContext* pContext = nullptr;
383  sax_fastparser::FastAttributeList *pAttribList =
385 
386  switch (nElement)
387  {
388  case XML_ELEMENT( CALC_EXT, XML_COLOR_SCALE_ENTRY ):
389  pContext = new ScXMLColorScaleFormatEntryContext( GetScImport(), pAttribList, pColorScaleFormat );
390  break;
391  default:
392  break;
393  }
394 
395  return pContext;
396 }
397 
400  ScConditionalFormat* pFormat):
401  ScXMLImportContext( rImport ),
402  mpFormatData(nullptr),
403  mpParent(pFormat),
404  mnIndex(0)
405 {
406  OUString sPositiveColor;
407  OUString sNegativeColor;
408  OUString sGradient;
409  OUString sAxisPosition;
410  OUString sShowValue;
411  OUString sAxisColor;
412  OUString sMinLength;
413  OUString sMaxLength;
414 
415  if ( rAttrList.is() )
416  {
417  for (auto &aIter : *rAttrList)
418  {
419  switch (aIter.getToken())
420  {
421  case XML_ELEMENT( CALC_EXT, XML_POSITIVE_COLOR ):
422  sPositiveColor = aIter.toString();
423  break;
424  case XML_ELEMENT( CALC_EXT, XML_GRADIENT ):
425  sGradient = aIter.toString();
426  break;
427  case XML_ELEMENT( CALC_EXT, XML_NEGATIVE_COLOR ):
428  sNegativeColor = aIter.toString();
429  break;
430  case XML_ELEMENT( CALC_EXT, XML_AXIS_POSITION ):
431  sAxisPosition = aIter.toString();
432  break;
433  case XML_ELEMENT( CALC_EXT, XML_SHOW_VALUE ):
434  sShowValue = aIter.toString();
435  break;
436  case XML_ELEMENT( CALC_EXT, XML_AXIS_COLOR ):
437  sAxisColor = aIter.toString();
438  break;
439  case XML_ELEMENT( CALC_EXT, XML_MIN_LENGTH ):
440  sMinLength = aIter.toString();
441  break;
442  case XML_ELEMENT( CALC_EXT, XML_MAX_LENGTH ):
443  sMaxLength = aIter.toString();
444  break;
445  default:
446  break;
447  }
448  }
449  }
450 
451  ScDataBarFormat* pDataBarFormat = new ScDataBarFormat(rImport.GetDocument());
453  pDataBarFormat->SetDataBarData(mpFormatData);
454  if(!sGradient.isEmpty())
455  {
456  bool bGradient = true;
457  (void)sax::Converter::convertBool( bGradient, sGradient);
458  mpFormatData->mbGradient = bGradient;
459  }
460 
461  if(!sPositiveColor.isEmpty())
462  {
463  sax::Converter::convertColor( mpFormatData->maPositiveColor, sPositiveColor );
464  }
465 
466  if(!sNegativeColor.isEmpty())
467  {
468  // we might check here for 0xff0000 and don't write it
469  Color nColor;
470  sax::Converter::convertColor( nColor, sNegativeColor );
471  mpFormatData->mpNegativeColor.reset(new Color(nColor));
472  }
473  else
474  mpFormatData->mbNeg = false;
475 
476  if(!sAxisPosition.isEmpty())
477  {
478  if(sAxisPosition == "middle")
479  mpFormatData->meAxisPosition = databar::MIDDLE;
480  else if (sAxisPosition == "none")
481  mpFormatData->meAxisPosition = databar::NONE;
482  }
483 
484  if(!sAxisColor.isEmpty())
485  {
486  sax::Converter::convertColor( mpFormatData->maAxisColor, sAxisColor );
487  }
488 
489  if(!sShowValue.isEmpty())
490  {
491  bool bShowValue = true;
492  (void)sax::Converter::convertBool( bShowValue, sShowValue );
493  mpFormatData->mbOnlyBar = !bShowValue;
494  }
495 
496  if (!sMinLength.isEmpty())
497  {
498  double nVal = sMinLength.toDouble();
499  mpFormatData->mnMinLength = nVal;
500  }
501 
502  if (!sMaxLength.isEmpty())
503  {
504  double nVal = sMaxLength.toDouble();
505  if (nVal == 0.0)
506  nVal = 100.0;
507  mpFormatData->mnMaxLength = nVal;
508  }
509 
510  pFormat->AddEntry(pDataBarFormat);
511 }
512 
513 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLDataBarFormatContext::createFastChildContext(
514  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
515 {
516  SvXMLImportContext* pContext = nullptr;
517  sax_fastparser::FastAttributeList *pAttribList =
519 
520  switch (nElement)
521  {
522  case XML_ELEMENT( CALC_EXT, XML_FORMATTING_ENTRY ):
523  case XML_ELEMENT( CALC_EXT, XML_DATA_BAR_ENTRY ):
524  {
525  ScColorScaleEntry* pEntry(nullptr);
526  pContext = new ScXMLFormattingEntryContext( GetScImport(), pAttribList, pEntry );
527  pEntry->SetRepaintCallback(mpParent);
528  if(mnIndex == 0)
529  {
530  mpFormatData->mpLowerLimit.reset(pEntry);
531  }
532  else if (mnIndex == 1)
533  {
534  mpFormatData->mpUpperLimit.reset(pEntry);
535  }
536  else
537  {
538  // data bars only support 2 entries
539  assert(false);
540  }
541  ++mnIndex;
542  }
543  break;
544  default:
545  break;
546  }
547 
548  return pContext;
549 }
550 
553  ScConditionalFormat* pFormat):
554  ScXMLImportContext( rImport ),
555  mpParent(pFormat)
556 {
557  OUString aIconSetType, sShowValue;
558  if ( rAttrList.is() )
559  {
560  for (auto &aIter : *rAttrList)
561  {
562  switch (aIter.getToken())
563  {
564  case XML_ELEMENT( CALC_EXT, XML_ICON_SET_TYPE ):
565  aIconSetType = aIter.toString();
566  break;
567  case XML_ELEMENT( CALC_EXT, XML_SHOW_VALUE ):
568  sShowValue = aIter.toString();
569  break;
570  default:
571  break;
572  }
573  }
574  }
575 
578  for(; pMap->pName; ++pMap)
579  {
580  OUString aName = OUString::createFromAscii(pMap->pName);
581  if(aName ==aIconSetType)
582  {
583  eType = pMap->eType;
584  break;
585  }
586  }
587 
588  ScIconSetFormat* pIconSetFormat = new ScIconSetFormat(GetScImport().GetDocument());
589  ScIconSetFormatData* pIconSetFormatData = new ScIconSetFormatData;
590 
591  if(!sShowValue.isEmpty())
592  {
593  bool bShowValue = true;
594  (void)sax::Converter::convertBool( bShowValue, sShowValue );
595  pIconSetFormatData->mbShowValue = !bShowValue;
596  }
597 
598  pIconSetFormatData->eIconSetType = eType;
599  pIconSetFormat->SetIconSetData(pIconSetFormatData);
600  pFormat->AddEntry(pIconSetFormat);
601 
602  mpFormatData = pIconSetFormatData;
603 }
604 
605 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLIconSetFormatContext::createFastChildContext(
606  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
607 {
608  SvXMLImportContext* pContext = nullptr;
609  sax_fastparser::FastAttributeList *pAttribList =
611 
612  switch (nElement)
613  {
614  case XML_ELEMENT( CALC_EXT, XML_FORMATTING_ENTRY ):
615  {
616  ScColorScaleEntry* pEntry(nullptr);
617  pContext = new ScXMLFormattingEntryContext( GetScImport(), pAttribList, pEntry );
618  mpFormatData->m_Entries.emplace_back(pEntry);
619  pEntry->SetRepaintCallback(mpParent);
620  }
621  break;
622  default:
623  break;
624  }
625 
626  return pContext;
627 }
628 
629 namespace {
630 
631 void GetConditionData(const OUString& rValue, ScConditionMode& eMode, OUString& rExpr1, OUString& rExpr2)
632 {
633  if(rValue.startsWith("unique"))
634  {
636  }
637  else if(rValue.startsWith("duplicate"))
638  {
640  }
641  else if(rValue.startsWith("between"))
642  {
643  const sal_Unicode* pStr = rValue.getStr();
644  const sal_Unicode* pStart = pStr + 8;
645  const sal_Unicode* pEnd = pStr + rValue.getLength();
646  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ',');
647  rExpr2 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
648  eMode = ScConditionMode::Between;
649  }
650  else if(rValue.startsWith("not-between"))
651  {
652  const sal_Unicode* pStr = rValue.getStr();
653  const sal_Unicode* pStart = pStr + 12;
654  const sal_Unicode* pEnd = pStr + rValue.getLength();
655  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ',');
656  rExpr2 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
658  }
659  else if(rValue.startsWith("<="))
660  {
661  rExpr1 = rValue.copy(2);
662  eMode = ScConditionMode::EqLess;
663  }
664  else if(rValue.startsWith(">="))
665  {
666  rExpr1 = rValue.copy(2);
668  }
669  else if(rValue.startsWith("!="))
670  {
671  rExpr1 = rValue.copy(2);
673  }
674  else if(rValue.startsWith("<"))
675  {
676  rExpr1 = rValue.copy(1);
677  eMode = ScConditionMode::Less;
678  }
679  else if(rValue.startsWith("="))
680  {
681  rExpr1 = rValue.copy(1);
682  eMode = ScConditionMode::Equal;
683  }
684  else if(rValue.startsWith(">"))
685  {
686  rExpr1 = rValue.copy(1);
687  eMode = ScConditionMode::Greater;
688  }
689  else if(rValue.startsWith("formula-is"))
690  {
691  const sal_Unicode* pStr = rValue.getStr();
692  const sal_Unicode* pStart = pStr + 11;
693  const sal_Unicode* pEnd = pStr + rValue.getLength();
694  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
695  eMode = ScConditionMode::Direct;
696  }
697  else if(rValue.startsWith("top-elements"))
698  {
699  const sal_Unicode* pStr = rValue.getStr();
700  const sal_Unicode* pStart = pStr + 13;
701  const sal_Unicode* pEnd = pStr + rValue.getLength();
702  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
703  eMode = ScConditionMode::Top10;
704  }
705  else if(rValue.startsWith("bottom-elements"))
706  {
707  const sal_Unicode* pStr = rValue.getStr();
708  const sal_Unicode* pStart = pStr + 16;
709  const sal_Unicode* pEnd = pStr + rValue.getLength();
710  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
712  }
713  else if(rValue.startsWith("top-percent"))
714  {
715  const sal_Unicode* pStr = rValue.getStr();
716  const sal_Unicode* pStart = pStr + 12;
717  const sal_Unicode* pEnd = pStr + rValue.getLength();
718  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
720  }
721  else if(rValue.startsWith("bottom-percent"))
722  {
723  const sal_Unicode* pStr = rValue.getStr();
724  const sal_Unicode* pStart = pStr + 15;
725  const sal_Unicode* pEnd = pStr + rValue.getLength();
726  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
728  }
729  else if(rValue.startsWith("above-average"))
730  {
732  }
733  else if(rValue.startsWith("below-average"))
734  {
736  }
737  else if(rValue.startsWith("above-equal-average"))
738  {
740  }
741  else if(rValue.startsWith("below-equal-average"))
742  {
744  }
745  else if(rValue.startsWith("is-error"))
746  {
747  eMode = ScConditionMode::Error;
748  }
749  else if(rValue.startsWith("is-no-error"))
750  {
751  eMode = ScConditionMode::NoError;
752  }
753  else if(rValue.startsWith("begins-with"))
754  {
756  const sal_Unicode* pStr = rValue.getStr();
757  const sal_Unicode* pStart = pStr + 12;
758  const sal_Unicode* pEnd = pStr + rValue.getLength();
759  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
760  }
761  else if(rValue.startsWith("ends-with"))
762  {
764  const sal_Unicode* pStr = rValue.getStr();
765  const sal_Unicode* pStart = pStr + 10;
766  const sal_Unicode* pEnd = pStr + rValue.getLength();
767  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
768  }
769  else if(rValue.startsWith("contains-text"))
770  {
772  const sal_Unicode* pStr = rValue.getStr();
773  const sal_Unicode* pStart = pStr + 14;
774  const sal_Unicode* pEnd = pStr + rValue.getLength();
775  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
776  }
777  else if(rValue.startsWith("not-contains-text"))
778  {
780  const sal_Unicode* pStr = rValue.getStr();
781  const sal_Unicode* pStart = pStr + 18;
782  const sal_Unicode* pEnd = pStr + rValue.getLength();
783  rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
784  }
785  else
786  eMode = ScConditionMode::NONE;
787 }
788 
789 }
790 
793  ScConditionalFormat* pFormat ):
794  ScXMLImportContext( rImport )
795 {
796  OUString sExpression;
797  OUString sStyle;
798  OUString sAddress;
799 
800  if ( rAttrList.is() )
801  {
802  for (auto &aIter : *rAttrList)
803  {
804  switch (aIter.getToken())
805  {
806  case XML_ELEMENT( CALC_EXT, XML_VALUE ):
807  sExpression = aIter.toString();
808  break;
809  case XML_ELEMENT( CALC_EXT, XML_APPLY_STYLE_NAME ):
810  sStyle = ScStyleNameConversion::ProgrammaticToDisplayName(aIter.toString(), SfxStyleFamily::Para );
811  break;
812  case XML_ELEMENT( CALC_EXT, XML_BASE_CELL_ADDRESS ):
813  sAddress = aIter.toString();
814  break;
815  default:
816  break;
817  }
818  }
819  }
820 
821  OUString aExpr1;
822  OUString aExpr2;
823  ScConditionMode eMode;
824  GetConditionData(sExpression, eMode, aExpr1, aExpr2);
825 
826  ScCondFormatEntry* pFormatEntry = new ScCondFormatEntry(eMode, aExpr1, aExpr2, GetScImport().GetDocument(), ScAddress(), sStyle,
828  pFormatEntry->SetSrcString(sAddress);
829 
830  pFormat->AddEntry(pFormatEntry);
831 }
832 
833 namespace {
834 
835 void setColorEntryType(const OUString& rType, ScColorScaleEntry* pEntry, const OUString& rFormula,
836  ScXMLImport& rImport)
837 {
838  if(rType == "minimum")
839  pEntry->SetType(COLORSCALE_MIN);
840  else if(rType == "maximum")
841  pEntry->SetType(COLORSCALE_MAX);
842  else if(rType == "percentile")
844  else if(rType == "percent")
845  pEntry->SetType(COLORSCALE_PERCENT);
846  else if(rType == "formula")
847  {
848  pEntry->SetType(COLORSCALE_FORMULA);
849  //position does not matter, only table is important
850  pEntry->SetFormula(rFormula, rImport.GetDocument(), ScAddress(0,0,rImport.GetTables().GetCurrentSheet()), formula::FormulaGrammar::GRAM_ODFF);
851  }
852  else if(rType == "auto-minimum")
853  pEntry->SetType(COLORSCALE_AUTO);
854  else if(rType == "auto-maximum")
855  pEntry->SetType(COLORSCALE_AUTO);
856 }
857 
858 }
859 
862  ScColorScaleFormat* pFormat):
863  ScXMLImportContext( rImport )
864 {
865  double nVal = 0;
866  Color aColor;
867 
868  OUString sType;
869  OUString sVal;
870  OUString sColor;
871 
872  if ( rAttrList.is() )
873  {
874  for (auto &aIter : *rAttrList)
875  {
876  switch (aIter.getToken())
877  {
878  case XML_ELEMENT( CALC_EXT, XML_TYPE ):
879  sType = aIter.toString();
880  break;
881  case XML_ELEMENT( CALC_EXT, XML_VALUE ):
882  sVal = aIter.toString();
883  break;
884  case XML_ELEMENT( CALC_EXT, XML_COLOR ):
885  sColor = aIter.toString();
886  break;
887  default:
888  break;
889  }
890  }
891  }
892 
893  sax::Converter::convertColor(aColor, sColor);
894 
895  if(!sVal.isEmpty())
896  sax::Converter::convertDouble(nVal, sVal);
897 
898  auto pFormatEntry = new ScColorScaleEntry(nVal, aColor);
899  setColorEntryType(sType, pFormatEntry, sVal, GetScImport());
900  pFormat->AddEntry(pFormatEntry);
901 }
902 
905  ScColorScaleEntry*& pColorScaleEntry):
906  ScXMLImportContext( rImport )
907 {
908  OUString sVal;
909  OUString sType;
910 
911  if ( rAttrList.is() )
912  {
913  for (auto &aIter : *rAttrList)
914  {
915  switch (aIter.getToken())
916  {
917  case XML_ELEMENT( CALC_EXT, XML_TYPE ):
918  sType = aIter.toString();
919  break;
920  case XML_ELEMENT( CALC_EXT, XML_VALUE ):
921  sVal = aIter.toString();
922  break;
923  default:
924  break;
925  }
926  }
927  }
928 
929  double nVal = 0;
930  if(!sVal.isEmpty())
931  sax::Converter::convertDouble(nVal, sVal);
932 
933  pColorScaleEntry = new ScColorScaleEntry(nVal, Color());
934  setColorEntryType(sType, pColorScaleEntry, sVal, GetScImport());
935 }
936 
937 namespace {
938 
939 condformat::ScCondFormatDateType getDateFromString(const OUString& rString)
940 {
941  if(rString == "today")
942  return condformat::TODAY;
943  else if(rString == "yesterday")
944  return condformat::YESTERDAY;
945  else if(rString == "tomorrow")
946  return condformat::TOMORROW;
947  else if(rString == "last-7-days")
948  return condformat::LAST7DAYS;
949  else if(rString == "this-week")
950  return condformat::THISWEEK;
951  else if(rString == "last-week")
952  return condformat::LASTWEEK;
953  else if(rString == "next-week")
954  return condformat::NEXTWEEK;
955  else if(rString == "this-month")
956  return condformat::THISMONTH;
957  else if(rString == "last-month")
958  return condformat::LASTMONTH;
959  else if(rString == "next-month")
960  return condformat::NEXTMONTH;
961  else if(rString == "this-year")
962  return condformat::THISYEAR;
963  else if(rString == "last-year")
964  return condformat::LASTYEAR;
965  else if(rString == "next-year")
966  return condformat::NEXTYEAR;
967 
968  SAL_WARN("sc", "unknown date type: " << rString);
969  return condformat::TODAY;
970 }
971 
972 }
973 
976  ScConditionalFormat* pFormat ):
977  ScXMLImportContext( rImport )
978 {
979  OUString sDateType, sStyle;
980  if ( rAttrList.is() )
981  {
982  for (auto &aIter : *rAttrList)
983  {
984  switch (aIter.getToken())
985  {
986  case XML_ELEMENT( CALC_EXT, XML_DATE ):
987  sDateType = aIter.toString();
988  break;
989  case XML_ELEMENT( CALC_EXT, XML_STYLE ):
990  sStyle = ScStyleNameConversion::ProgrammaticToDisplayName(aIter.toString(), SfxStyleFamily::Para );
991  break;
992  default:
993  break;
994  }
995  }
996  }
997 
998  ScCondDateFormatEntry* pFormatEntry = new ScCondDateFormatEntry(GetScImport().GetDocument());
999  pFormatEntry->SetStyleName(sStyle);
1000  pFormatEntry->SetDateType(getDateFromString(sDateType));
1001  pFormat->AddEntry(pFormatEntry);
1002 
1003 }
1004 
1005 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsTabRel() const
Definition: refdata.hxx:70
void SetGrammar(const formula::FormulaGrammar::Grammar eGrammar)
Definition: compiler.cxx:207
void SetRepaintCallback(ScConditionalFormat *pParent)
Definition: colorscale.cxx:315
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:4478
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 SetFormula(const OUString &rFormula, ScDocument *pDoc, const ScAddress &rAddr, formula::FormulaGrammar::Grammar eGrammar=formula::FormulaGrammar::GRAM_DEFAULT)
Definition: colorscale.cxx:206
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:401
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
static bool GetRangeListFromString(ScRangeList &rRangeList, const OUString &rRangeListStr, const ScDocument *pDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Unicode cSeparator= ' ', sal_Unicode cQuote= '\'')
Definition: rangeutl.cxx:528
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
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
ScIconSetType
Definition: colorscale.hxx:189
XML_BASE_CELL_ADDRESS
#define SAL_WARN(area, stream)
void SetType(ScColorScaleEntryType eType)
Definition: colorscale.cxx:323
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:250
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)
SC_DLLPUBLIC ScRefFlags Parse(const OUString &, const ScDocument *=nullptr, 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:1543
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:720
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:4809
ocColumn
XML_CONDITION
void SetNewCondFormatData()
Definition: xmlimprt.hxx:364
virtual ~ScXMLConditionalFormatContext() override
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo