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