office-gobmx/sc/inc/conditio.hxx
Markus Mohrhard effa6dcb55 support undo of whole conditional format list, tdf#95617
Change-Id: I3ff0ddb05f794064e33164c60cd1b4e6b89dbcca
Reviewed-on: https://gerrit.libreoffice.org/36295
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
2017-04-08 20:57:59 +00:00

537 lines
18 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#ifndef INCLUDED_SC_INC_CONDITIO_HXX
#define INCLUDED_SC_INC_CONDITIO_HXX
#include "global.hxx"
#include "address.hxx"
#include <formula/grammar.hxx>
#include "scdllapi.h"
#include "rangelst.hxx"
#include <svl/hint.hxx>
#include <svl/listener.hxx>
#include <svl/broadcast.hxx>
#include <comphelper/stl_types.hxx>
#include <com/sun/star/sheet/ConditionOperator.hpp>
#include <rtl/math.hxx>
#include <tools/date.hxx>
#include <map>
#include <memory>
#include <set>
class ScFormulaCell;
class ScTokenArray;
struct ScRefCellValue;
namespace sc {
struct RefUpdateContext;
struct RefUpdateInsertTabContext;
struct RefUpdateDeleteTabContext;
struct RefUpdateMoveTabContext;
}
// nOptions Flags
#define SC_COND_NOBLANKS 1
enum ScConditionMode
{
SC_COND_EQUAL,
SC_COND_LESS,
SC_COND_GREATER,
SC_COND_EQLESS,
SC_COND_EQGREATER,
SC_COND_NOTEQUAL,
SC_COND_BETWEEN,
SC_COND_NOTBETWEEN,
SC_COND_DUPLICATE,
SC_COND_NOTDUPLICATE,
SC_COND_DIRECT,
SC_COND_TOP10,
SC_COND_BOTTOM10,
SC_COND_TOP_PERCENT,
SC_COND_BOTTOM_PERCENT,
SC_COND_ABOVE_AVERAGE,
SC_COND_BELOW_AVERAGE,
SC_COND_ABOVE_EQUAL_AVERAGE,
SC_COND_BELOW_EQUAL_AVERAGE,
SC_COND_ERROR,
SC_COND_NOERROR,
SC_COND_BEGINS_WITH,
SC_COND_ENDS_WITH,
SC_COND_CONTAINS_TEXT,
SC_COND_NOT_CONTAINS_TEXT,
SC_COND_NONE
};
class ScFormulaListener : public SvtListener
{
private:
std::vector<ScRange> maCells;
mutable bool mbDirty;
ScDocument* mpDoc;
std::function<void()> maCallbackFunction;
void startListening(ScTokenArray* pTokens, const ScRange& rPos);
public:
explicit ScFormulaListener(ScFormulaCell* pCell);
explicit ScFormulaListener(ScDocument* pDoc);
virtual ~ScFormulaListener() override;
void Notify( const SfxHint& rHint ) override;
bool NeedsRepaint() const;
void addTokenArray(ScTokenArray* pTokens, const ScRange& rRange);
void stopListening();
void setCallback(const std::function<void()>& aCallbackFunction);
};
class ScConditionalFormat;
struct ScDataBarInfo;
struct ScIconSetInfo;
namespace condformat
{
enum ScFormatEntryType
{
CONDITION,
COLORSCALE,
DATABAR,
ICONSET,
DATE
};
}
struct ScCondFormatData
{
ScCondFormatData():
pColorScale(nullptr),
pDataBar(nullptr),
pIconSet(nullptr) {}
Color* pColorScale;
ScDataBarInfo* pDataBar;
ScIconSetInfo* pIconSet;
OUString aStyleName;
};
class SC_DLLPUBLIC ScFormatEntry
{
public:
ScFormatEntry(ScDocument* pDoc);
virtual ~ScFormatEntry() {}
virtual condformat::ScFormatEntryType GetType() const = 0;
virtual void UpdateReference( sc::RefUpdateContext& rCxt ) = 0;
virtual void UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt ) = 0;
virtual void UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt ) = 0;
virtual void UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt ) = 0;
virtual ScFormatEntry* Clone( ScDocument* pDoc ) const = 0;
virtual void SetParent( ScConditionalFormat* pNew ) = 0;
bool operator==( const ScFormatEntry& ) const;
virtual void startRendering();
virtual void endRendering();
protected:
ScDocument* mpDoc;
};
class approx_less : public std::binary_function<double, double, bool>
{
public:
bool operator() (double nVal1, double nVal2) const
{
if(nVal1 < nVal2 && !rtl::math::approxEqual(nVal1, nVal2))
return true;
return false;
}
};
class SC_DLLPUBLIC ScConditionEntry : public ScFormatEntry
{
// stored data:
ScConditionMode eOp;
sal_uInt16 nOptions;
double nVal1; // input or calculated
double nVal2;
OUString aStrVal1; // input or calculated
OUString aStrVal2;
OUString aStrNmsp1; // namespace to be used on (re)compilation, e.g. in XML import
OUString aStrNmsp2; // namespace to be used on (re)compilation, e.g. in XML import
formula::FormulaGrammar::Grammar eTempGrammar1; // grammar to be used on (re)compilation, e.g. in XML import
formula::FormulaGrammar::Grammar eTempGrammar2; // grammar to be used on (re)compilation, e.g. in XML import
bool bIsStr1; // for recognition of empty strings
bool bIsStr2;
ScTokenArray* pFormula1; // entered formula
ScTokenArray* pFormula2;
ScAddress aSrcPos; // source position for formulas
// temporary data:
OUString aSrcString; // formula source position as text during XML import
ScFormulaCell* pFCell1;
ScFormulaCell* pFCell2;
bool bRelRef1;
bool bRelRef2;
bool bFirstRun;
std::unique_ptr<ScFormulaListener> mpListener;
void MakeCells( const ScAddress& rPos );
void Compile( const OUString& rExpr1, const OUString& rExpr2,
const OUString& rExprNmsp1, const OUString& rExprNmsp2,
formula::FormulaGrammar::Grammar eGrammar1,
formula::FormulaGrammar::Grammar eGrammar2,
bool bTextToReal );
void Interpret( const ScAddress& rPos );
bool IsValid( double nArg, const ScAddress& rPos ) const;
bool IsValidStr( const OUString& rArg, const ScAddress& rPos ) const;
void StartListening();
public:
ScConditionEntry( ScConditionMode eOper,
const OUString& rExpr1, const OUString& rExpr2,
ScDocument* pDocument, const ScAddress& rPos,
const OUString& rExprNmsp1, const OUString& rExprNmsp2,
formula::FormulaGrammar::Grammar eGrammar1,
formula::FormulaGrammar::Grammar eGrammar2 );
ScConditionEntry( ScConditionMode eOper,
const ScTokenArray* pArr1, const ScTokenArray* pArr2,
ScDocument* pDocument, const ScAddress& rPos );
ScConditionEntry( const ScConditionEntry& r ); // flat copy of formulas
// true copy of formulas (for Ref-Undo):
ScConditionEntry( ScDocument* pDocument, const ScConditionEntry& r );
virtual ~ScConditionEntry() override;
bool operator== ( const ScConditionEntry& r ) const;
virtual void SetParent( ScConditionalFormat* pNew ) override;
bool IsCellValid( ScRefCellValue& rCell, const ScAddress& rPos ) const;
ScConditionMode GetOperation() const { return eOp; }
void SetOperation(ScConditionMode eMode);
bool IsIgnoreBlank() const { return ( nOptions & SC_COND_NOBLANKS ) == 0; }
void SetIgnoreBlank(bool bSet);
const ScAddress& GetSrcPos() const { return aSrcPos; }
ScAddress GetValidSrcPos() const; // adjusted to allow textual representation of expressions
void SetSrcString( const OUString& rNew ); // for XML import
void SetFormula1( const ScTokenArray& rArray );
void SetFormula2( const ScTokenArray& rArray );
OUString GetExpression( const ScAddress& rCursor, sal_uInt16 nPos, sal_uLong nNumFmt = 0,
const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
/** Create a flat copy using ScTokenArray copy-ctor with
shared tokens. */
ScTokenArray* CreateFlatCopiedTokenArray( sal_uInt16 nPos ) const;
void CompileAll();
void CompileXML();
virtual void UpdateReference( sc::RefUpdateContext& rCxt ) override;
virtual void UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt ) override;
virtual void UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt ) override;
virtual void UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt ) override;
bool MarkUsedExternalReferences() const;
virtual condformat::ScFormatEntryType GetType() const override { return condformat::CONDITION; }
virtual ScFormatEntry* Clone(ScDocument* pDoc) const override;
static ScConditionMode GetModeFromApi(css::sheet::ConditionOperator nOperator);
virtual void endRendering() override;
virtual void startRendering() override;
bool NeedsRepaint() const;
protected:
virtual void DataChanged() const;
ScDocument* GetDocument() const { return mpDoc; }
ScConditionalFormat* pCondFormat;
private:
bool IsDuplicate(double nArg, const OUString& rStr) const;
bool IsTopNElement( double nArg ) const;
bool IsTopNPercent( double nArg ) const;
bool IsBottomNElement( double nArg ) const;
bool IsBottomNPercent( double nArg ) const;
bool IsAboveAverage( double nArg, bool bEqual ) const;
bool IsBelowAverage( double nArg, bool bEqual ) const;
bool IsError( const ScAddress& rPos ) const;
void FillCache() const;
struct ScConditionEntryCache
{
typedef std::map<OUString, sal_Int32> StringCacheType;
StringCacheType maStrings;
typedef std::map<double, sal_Int32, approx_less> ValueCacheType;
ValueCacheType maValues;
// cache them for easier access
size_t nValueItems;
ScConditionEntryCache():
nValueItems(0) {}
};
mutable std::unique_ptr<ScConditionEntryCache> mpCache;
};
// single condition entry for conditional formatting
class SC_DLLPUBLIC ScCondFormatEntry : public ScConditionEntry
{
OUString aStyleName;
using ScConditionEntry::operator==;
public:
ScCondFormatEntry( ScConditionMode eOper,
const OUString& rExpr1, const OUString& rExpr2,
ScDocument* pDocument, const ScAddress& rPos,
const OUString& rStyle,
const OUString& rExprNmsp1 = EMPTY_OUSTRING,
const OUString& rExprNmsp2 = EMPTY_OUSTRING,
formula::FormulaGrammar::Grammar eGrammar1 = formula::FormulaGrammar::GRAM_DEFAULT,
formula::FormulaGrammar::Grammar eGrammar2 = formula::FormulaGrammar::GRAM_DEFAULT );
ScCondFormatEntry( ScConditionMode eOper,
const ScTokenArray* pArr1, const ScTokenArray* pArr2,
ScDocument* pDocument, const ScAddress& rPos,
const OUString& rStyle );
ScCondFormatEntry( const ScCondFormatEntry& r );
ScCondFormatEntry( ScDocument* pDocument, const ScCondFormatEntry& r );
virtual ~ScCondFormatEntry() override;
bool operator== ( const ScCondFormatEntry& r ) const;
const OUString& GetStyle() const { return aStyleName; }
void UpdateStyleName(const OUString& rNew) { aStyleName=rNew; }
virtual ScFormatEntry* Clone(ScDocument* pDoc) const override;
protected:
virtual void DataChanged() const override;
};
namespace condformat {
enum ScCondFormatDateType
{
TODAY,
YESTERDAY,
TOMORROW,
LAST7DAYS,
THISWEEK,
LASTWEEK,
NEXTWEEK,
THISMONTH,
LASTMONTH,
NEXTMONTH,
THISYEAR,
LASTYEAR,
NEXTYEAR
};
}
class SC_DLLPUBLIC ScCondDateFormatEntry : public ScFormatEntry
{
public:
ScCondDateFormatEntry(ScDocument* pDoc);
ScCondDateFormatEntry(ScDocument* pDoc, const ScCondDateFormatEntry& rEntry);
bool IsValid( const ScAddress& rPos ) const;
void SetDateType(condformat::ScCondFormatDateType eType);
condformat::ScCondFormatDateType GetDateType() const { return meType;}
const OUString& GetStyleName() const { return maStyleName;}
void SetStyleName( const OUString& rStyleName );
virtual condformat::ScFormatEntryType GetType() const override { return condformat::DATE; }
virtual void UpdateReference( sc::RefUpdateContext& ) override {}
virtual void UpdateInsertTab( sc::RefUpdateInsertTabContext& ) override {}
virtual void UpdateDeleteTab( sc::RefUpdateDeleteTabContext& ) override {}
virtual void UpdateMoveTab( sc::RefUpdateMoveTabContext& ) override {}
virtual ScFormatEntry* Clone( ScDocument* pDoc ) const override;
virtual void SetParent( ScConditionalFormat* ) override {}
virtual void startRendering() override;
virtual void endRendering() override;
private:
condformat::ScCondFormatDateType meType;
mutable std::unique_ptr<Date> mpCache;
OUString maStyleName;
};
// complete conditional formatting
class SC_DLLPUBLIC ScConditionalFormat
{
ScDocument* pDoc;
sal_uInt32 nKey; // Index in attributes
typedef std::vector<std::unique_ptr<ScFormatEntry>> CondFormatContainer;
CondFormatContainer maEntries;
ScRangeList maRanges; // Ranges for conditional format
public:
ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument);
~ScConditionalFormat();
ScConditionalFormat(const ScConditionalFormat&) = delete;
const ScConditionalFormat& operator=(const ScConditionalFormat&) = delete;
// true copy of formulas (for Ref-Undo / between documents)
ScConditionalFormat* Clone(ScDocument* pNewDoc = nullptr) const;
void AddEntry( ScFormatEntry* pNew );
void RemoveEntry(size_t nIndex);
void SetRange( const ScRangeList& rRanges );
const ScRangeList& GetRange() const { return maRanges; }
// don't use the same name as for the const version
ScRangeList& GetRangeList() { return maRanges; }
bool IsEmpty() const;
size_t size() const;
void CompileAll();
void CompileXML();
void UpdateReference( sc::RefUpdateContext& rCxt, bool bCopyAsMove = false );
void UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt );
void UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt );
void UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt );
void InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowStart, SCSIZE nSize);
void InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColStart, SCSIZE nSize);
void DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
void RenameCellStyle( const OUString& rOld, const OUString& rNew );
const ScFormatEntry* GetEntry( sal_uInt16 nPos ) const;
const OUString& GetCellStyle( ScRefCellValue& rCell, const ScAddress& rPos ) const;
ScCondFormatData GetData( ScRefCellValue& rCell, const ScAddress& rPos ) const;
bool EqualEntries( const ScConditionalFormat& r ) const;
void DoRepaint();
sal_uInt32 GetKey() const { return nKey; }
void SetKey(sal_uInt32 nNew) { nKey = nNew; } // only if not inserted!
bool MarkUsedExternalReferences() const;
// sorted (via std::set) by Index
bool operator < ( const ScConditionalFormat& r ) const { return nKey < r.nKey; }
void startRendering();
void endRendering();
};
// List of all conditional formats in a sheet
class SC_DLLPUBLIC ScConditionalFormatList
{
private:
typedef std::set<std::unique_ptr<ScConditionalFormat>,
comphelper::UniquePtrValueLess<ScConditionalFormat>> ConditionalFormatContainer;
ConditionalFormatContainer m_ConditionalFormats;
void operator =(ScConditionalFormatList const &) = delete;
public:
ScConditionalFormatList() {}
ScConditionalFormatList(const ScConditionalFormatList& rList);
ScConditionalFormatList(ScDocument* pDoc, const ScConditionalFormatList& rList);
void InsertNew( ScConditionalFormat* pNew );
/**
* Checks that all cond formats have a non empty range.
* Deletes empty cond formats.
* @return true if all cond formats were valid
*/
bool CheckAllEntries();
ScConditionalFormat* GetFormat( sal_uInt32 nKey );
const ScConditionalFormat* GetFormat( sal_uInt32 nKey ) const;
void CompileAll();
void CompileXML();
void UpdateReference( sc::RefUpdateContext& rCxt );
void UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt );
void UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt );
void UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt );
void InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowStart, SCSIZE nSize);
void InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColStart, SCSIZE nSize);
void RenameCellStyle( const OUString& rOld, const OUString& rNew );
void DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
typedef ConditionalFormatContainer::iterator iterator;
typedef ConditionalFormatContainer::const_iterator const_iterator;
ScRangeList GetCombinedRange() const;
void RemoveFromDocument(ScDocument* pDoc) const;
void AddToDocument(ScDocument* pDoc) const;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
size_t size() const;
void erase(sal_uLong nIndex);
void clear();
void startRendering();
void endRendering();
sal_uInt32 getMaxKey() const;
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */