/*******************************************************************************
* You may amend and distribute as you like, but don't remove this header!
*
* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
* See http://www.codeplex.com/EPPlus for details.
*
* Copyright (C) 2011 Jan Källman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
*
* All code and executables are provided "as is" with no warranty either express or implied.
* The author accepts no liability for any damage or loss of business that this product may cause.
*
* Code change notes:
*
* Author Change Date
* ******************************************************************************
* Eyal Seagull Conditional Formatting 2012-04-03
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using OfficeOpenXml.Utils;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting.Contracts;
using System.Text.RegularExpressions;
using System.Drawing;
namespace OfficeOpenXml.ConditionalFormatting
{
///
/// Collection of .
/// This class is providing the API for EPPlus conditional formatting.
///
///
///
/// The public methods of this class (Add[...]ConditionalFormatting) will create a ConditionalFormatting/CfRule entry in the worksheet. When this
/// Conditional Formatting has been created changes to the properties will affect the workbook immediately.
///
///
/// Each type of Conditional Formatting Rule has diferente set of properties.
///
///
/// // Add a Three Color Scale conditional formatting
/// var cf = worksheet.ConditionalFormatting.AddThreeColorScale(new ExcelAddress("A1:C10"));
/// // Set the conditional formatting properties
/// cf.LowValue.Type = ExcelConditionalFormattingValueObjectType.Min;
/// cf.LowValue.Color = Color.White;
/// cf.MiddleValue.Type = ExcelConditionalFormattingValueObjectType.Percent;
/// cf.MiddleValue.Value = 50;
/// cf.MiddleValue.Color = Color.Blue;
/// cf.HighValue.Type = ExcelConditionalFormattingValueObjectType.Max;
/// cf.HighValue.Color = Color.Black;
///
///
public class ExcelConditionalFormattingCollection
: XmlHelper,
IEnumerable
{
/****************************************************************************************/
#region Private Properties
private List _rules = new List();
private ExcelWorksheet _worksheet = null;
#endregion Private Properties
/****************************************************************************************/
#region Constructors
///
/// Initialize the
///
///
internal ExcelConditionalFormattingCollection(
ExcelWorksheet worksheet)
: base(
worksheet.NameSpaceManager,
worksheet.WorksheetXml.DocumentElement)
{
Require.Argument(worksheet).IsNotNull("worksheet");
_worksheet = worksheet;
SchemaNodeOrder = _worksheet.SchemaNodeOrder;
// Look for all the
var conditionalFormattingNodes = TopNode.SelectNodes(
"//" + ExcelConditionalFormattingConstants.Paths.ConditionalFormatting,
_worksheet.NameSpaceManager);
// Check if we found at least 1 node
if ((conditionalFormattingNodes != null)
&& (conditionalFormattingNodes.Count > 0))
{
// Foreach
foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes)
{
// Check if @sqref attribute exists
if (conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Sqref] == null)
{
throw new Exception(
ExcelConditionalFormattingConstants.Errors.MissingSqrefAttribute);
}
// Get the @sqref attribute
ExcelAddress address = new ExcelAddress(
conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Sqref].Value);
// Check for all the nodes and load them
var cfRuleNodes = conditionalFormattingNode.SelectNodes(
ExcelConditionalFormattingConstants.Paths.CfRule,
_worksheet.NameSpaceManager);
// Foreach inside the current
foreach (XmlNode cfRuleNode in cfRuleNodes)
{
// Check if @type attribute exists
if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Type] == null)
{
throw new Exception(
ExcelConditionalFormattingConstants.Errors.MissingTypeAttribute);
}
// Check if @priority attribute exists
if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Priority] == null)
{
throw new Exception(
ExcelConditionalFormattingConstants.Errors.MissingPriorityAttribute);
}
// Get the main attributes
string typeAttribute = ExcelConditionalFormattingHelper.GetAttributeString(
cfRuleNode,
ExcelConditionalFormattingConstants.Attributes.Type);
int priority = ExcelConditionalFormattingHelper.GetAttributeInt(
cfRuleNode,
ExcelConditionalFormattingConstants.Attributes.Priority);
// Transform the @type attribute to EPPlus Rule Type (slighty diferente)
var type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute(
typeAttribute,
cfRuleNode,
_worksheet.NameSpaceManager);
// Create the Rule according to the correct type, address and priority
var cfRule = ExcelConditionalFormattingRuleFactory.Create(
type,
address,
priority,
_worksheet,
cfRuleNode);
// Add the new rule to the list
if(cfRule!=null)
_rules.Add(cfRule);
}
}
}
}
#endregion Constructors
/****************************************************************************************/
#region Methods
///
///
///
private void EnsureRootElementExists()
{
// Find the node
if (_worksheet.WorksheetXml.DocumentElement == null)
{
throw new Exception(
ExcelConditionalFormattingConstants.Errors.MissingWorksheetNode);
}
}
///
/// GetRootNode
///
///
private XmlNode GetRootNode()
{
EnsureRootElementExists();
return _worksheet.WorksheetXml.DocumentElement;
}
///
/// Validates address - not empty (collisions are allowded)
///
///
///
private ExcelAddress ValidateAddress(
ExcelAddress address)
{
Require.Argument(address).IsNotNull("address");
//TODO: Are there any other validation we need to do?
return address;
}
///
/// Get the next priority sequencial number
///
///
private int GetNextPriority()
{
// Consider zero as the last priority when we have no CF rules
int lastPriority = 0;
// Search for the last priority
foreach (var cfRule in _rules)
{
if (cfRule.Priority > lastPriority)
{
lastPriority = cfRule.Priority;
}
}
// Our next priority is the last plus one
return lastPriority + 1;
}
#endregion Methods
/****************************************************************************************/
#region IEnumerable
///
/// Number of validations
///
public int Count
{
get { return _rules.Count; }
}
///
/// Index operator, returns by 0-based index
///
///
///
public IExcelConditionalFormattingRule this[int index]
{
get { return _rules[index]; }
set { _rules[index] = value; }
}
///
/// Get the 'cfRule' enumerator
///
///
IEnumerator IEnumerable.GetEnumerator()
{
return _rules.GetEnumerator();
}
///
/// Get the 'cfRule' enumerator
///
///
IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _rules.GetEnumerator();
}
///
/// Removes all 'cfRule' from the collection and from the XML.
///
/// This is the same as removing all the 'conditionalFormatting' nodes.
///
///
public void RemoveAll()
{
// Look for all the nodes
var conditionalFormattingNodes = TopNode.SelectNodes(
"//" + ExcelConditionalFormattingConstants.Paths.ConditionalFormatting,
_worksheet.NameSpaceManager);
// Remove all the nodes one by one
foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes)
{
conditionalFormattingNode.ParentNode.RemoveChild(conditionalFormattingNode);
}
// Clear the item list
_rules.Clear();
}
///
/// Remove a Conditional Formatting Rule by its object
///
///
public void Remove(
IExcelConditionalFormattingRule item)
{
Require.Argument(item).IsNotNull("item");
try
{
// Point to the parent node
var oldParentNode = item.Node.ParentNode;
// Remove the from the old parent node
oldParentNode.RemoveChild(item.Node);
// Check if the old parent node has node inside it
if (!oldParentNode.HasChildNodes)
{
// Remove the old parent node
oldParentNode.ParentNode.RemoveChild(oldParentNode);
}
_rules.Remove(item);
}
catch
{
throw new Exception(
ExcelConditionalFormattingConstants.Errors.InvalidRemoveRuleOperation);
}
}
///
/// Remove a Conditional Formatting Rule by its 0-based index
///
///
public void RemoveAt(
int index)
{
Require.Argument(index).IsInRange(0, this.Count - 1, "index");
Remove(this[index]);
}
///
/// Remove a Conditional Formatting Rule by its priority
///
///
public void RemoveByPriority(
int priority)
{
try
{
Remove(RulesByPriority(priority));
}
catch
{
}
}
///
/// Get a rule by its priority
///
///
///
public IExcelConditionalFormattingRule RulesByPriority(
int priority)
{
return _rules.Find(x => x.Priority == priority);
}
#endregion IEnumerable
/****************************************************************************************/
#region Conditional Formatting Rules
///
/// Add rule (internal)
///
///
///
/// F
internal IExcelConditionalFormattingRule AddRule(
eExcelConditionalFormattingRuleType type,
ExcelAddress address)
{
Require.Argument(address).IsNotNull("address");
address = ValidateAddress(address);
EnsureRootElementExists();
// Create the Rule according to the correct type, address and priority
IExcelConditionalFormattingRule cfRule = ExcelConditionalFormattingRuleFactory.Create(
type,
address,
GetNextPriority(),
_worksheet,
null);
// Add the newly created rule to the list
_rules.Add(cfRule);
// Return the newly created rule
return cfRule;
}
///
/// Add AboveAverage Rule
///
///
///
public IExcelConditionalFormattingAverageGroup AddAboveAverage(
ExcelAddress address)
{
return (IExcelConditionalFormattingAverageGroup)AddRule(
eExcelConditionalFormattingRuleType.AboveAverage,
address);
}
///
/// Add AboveOrEqualAverage Rule
///
///
///
public IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage(
ExcelAddress address)
{
return (IExcelConditionalFormattingAverageGroup)AddRule(
eExcelConditionalFormattingRuleType.AboveOrEqualAverage,
address);
}
///
/// Add BelowAverage Rule
///
///
///
public IExcelConditionalFormattingAverageGroup AddBelowAverage(
ExcelAddress address)
{
return (IExcelConditionalFormattingAverageGroup)AddRule(
eExcelConditionalFormattingRuleType.BelowAverage,
address);
}
///
/// Add BelowOrEqualAverage Rule
///
///
///
public IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage(
ExcelAddress address)
{
return (IExcelConditionalFormattingAverageGroup)AddRule(
eExcelConditionalFormattingRuleType.BelowOrEqualAverage,
address);
}
///
/// Add AboveStdDev Rule
///
///
///
public IExcelConditionalFormattingStdDevGroup AddAboveStdDev(
ExcelAddress address)
{
return (IExcelConditionalFormattingStdDevGroup)AddRule(
eExcelConditionalFormattingRuleType.AboveStdDev,
address);
}
///
/// Add BelowStdDev Rule
///
///
///
public IExcelConditionalFormattingStdDevGroup AddBelowStdDev(
ExcelAddress address)
{
return (IExcelConditionalFormattingStdDevGroup)AddRule(
eExcelConditionalFormattingRuleType.BelowStdDev,
address);
}
///
/// Add Bottom Rule
///
///
///
public IExcelConditionalFormattingTopBottomGroup AddBottom(
ExcelAddress address)
{
return (IExcelConditionalFormattingTopBottomGroup)AddRule(
eExcelConditionalFormattingRuleType.Bottom,
address);
}
///
/// Add BottomPercent Rule
///
///
///
public IExcelConditionalFormattingTopBottomGroup AddBottomPercent(
ExcelAddress address)
{
return (IExcelConditionalFormattingTopBottomGroup)AddRule(
eExcelConditionalFormattingRuleType.BottomPercent,
address);
}
///
/// Add Top Rule
///
///
///
public IExcelConditionalFormattingTopBottomGroup AddTop(
ExcelAddress address)
{
return (IExcelConditionalFormattingTopBottomGroup)AddRule(
eExcelConditionalFormattingRuleType.Top,
address);
}
///
/// Add TopPercent Rule
///
///
///
public IExcelConditionalFormattingTopBottomGroup AddTopPercent(
ExcelAddress address)
{
return (IExcelConditionalFormattingTopBottomGroup)AddRule(
eExcelConditionalFormattingRuleType.TopPercent,
address);
}
///
/// Add Last7Days Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddLast7Days(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.Last7Days,
address);
}
///
/// Add LastMonth Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddLastMonth(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.LastMonth,
address);
}
///
/// Add LastWeek Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddLastWeek(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.LastWeek,
address);
}
///
/// Add NextMonth Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddNextMonth(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.NextMonth,
address);
}
///
/// Add NextWeek Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddNextWeek(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.NextWeek,
address);
}
///
/// Add ThisMonth Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddThisMonth(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.ThisMonth,
address);
}
///
/// Add ThisWeek Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddThisWeek(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.ThisWeek,
address);
}
///
/// Add Today Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddToday(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.Today,
address);
}
///
/// Add Tomorrow Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddTomorrow(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.Tomorrow,
address);
}
///
/// Add Yesterday Rule
///
///
///
public IExcelConditionalFormattingTimePeriodGroup AddYesterday(
ExcelAddress address)
{
return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
eExcelConditionalFormattingRuleType.Yesterday,
address);
}
///
/// Add BeginsWith Rule
///
///
///
public IExcelConditionalFormattingBeginsWith AddBeginsWith(
ExcelAddress address)
{
return (IExcelConditionalFormattingBeginsWith)AddRule(
eExcelConditionalFormattingRuleType.BeginsWith,
address);
}
///
/// Add Between Rule
///
///
///
public IExcelConditionalFormattingBetween AddBetween(
ExcelAddress address)
{
return (IExcelConditionalFormattingBetween)AddRule(
eExcelConditionalFormattingRuleType.Between,
address);
}
///
/// Add ContainsBlanks Rule
///
///
///
public IExcelConditionalFormattingContainsBlanks AddContainsBlanks(
ExcelAddress address)
{
return (IExcelConditionalFormattingContainsBlanks)AddRule(
eExcelConditionalFormattingRuleType.ContainsBlanks,
address);
}
///
/// Add ContainsErrors Rule
///
///
///
public IExcelConditionalFormattingContainsErrors AddContainsErrors(
ExcelAddress address)
{
return (IExcelConditionalFormattingContainsErrors)AddRule(
eExcelConditionalFormattingRuleType.ContainsErrors,
address);
}
///
/// Add ContainsText Rule
///
///
///
public IExcelConditionalFormattingContainsText AddContainsText(
ExcelAddress address)
{
return (IExcelConditionalFormattingContainsText)AddRule(
eExcelConditionalFormattingRuleType.ContainsText,
address);
}
///
/// Add DuplicateValues Rule
///
///
///
public IExcelConditionalFormattingDuplicateValues AddDuplicateValues(
ExcelAddress address)
{
return (IExcelConditionalFormattingDuplicateValues)AddRule(
eExcelConditionalFormattingRuleType.DuplicateValues,
address);
}
///
/// Add EndsWith Rule
///
///
///
public IExcelConditionalFormattingEndsWith AddEndsWith(
ExcelAddress address)
{
return (IExcelConditionalFormattingEndsWith)AddRule(
eExcelConditionalFormattingRuleType.EndsWith,
address);
}
///
/// Add Equal Rule
///
///
///
public IExcelConditionalFormattingEqual AddEqual(
ExcelAddress address)
{
return (IExcelConditionalFormattingEqual)AddRule(
eExcelConditionalFormattingRuleType.Equal,
address);
}
///
/// Add Expression Rule
///
///
///
public IExcelConditionalFormattingExpression AddExpression(
ExcelAddress address)
{
return (IExcelConditionalFormattingExpression)AddRule(
eExcelConditionalFormattingRuleType.Expression,
address);
}
///
/// Add GreaterThan Rule
///
///
///
public IExcelConditionalFormattingGreaterThan AddGreaterThan(
ExcelAddress address)
{
return (IExcelConditionalFormattingGreaterThan)AddRule(
eExcelConditionalFormattingRuleType.GreaterThan,
address);
}
///
/// Add GreaterThanOrEqual Rule
///
///
///
public IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual(
ExcelAddress address)
{
return (IExcelConditionalFormattingGreaterThanOrEqual)AddRule(
eExcelConditionalFormattingRuleType.GreaterThanOrEqual,
address);
}
///
/// Add LessThan Rule
///
///
///
public IExcelConditionalFormattingLessThan AddLessThan(
ExcelAddress address)
{
return (IExcelConditionalFormattingLessThan)AddRule(
eExcelConditionalFormattingRuleType.LessThan,
address);
}
///
/// Add LessThanOrEqual Rule
///
///
///
public IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual(
ExcelAddress address)
{
return (IExcelConditionalFormattingLessThanOrEqual)AddRule(
eExcelConditionalFormattingRuleType.LessThanOrEqual,
address);
}
///
/// Add NotBetween Rule
///
///
///
public IExcelConditionalFormattingNotBetween AddNotBetween(
ExcelAddress address)
{
return (IExcelConditionalFormattingNotBetween)AddRule(
eExcelConditionalFormattingRuleType.NotBetween,
address);
}
///
/// Add NotContainsBlanks Rule
///
///
///
public IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks(
ExcelAddress address)
{
return (IExcelConditionalFormattingNotContainsBlanks)AddRule(
eExcelConditionalFormattingRuleType.NotContainsBlanks,
address);
}
///
/// Add NotContainsErrors Rule
///
///
///
public IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors(
ExcelAddress address)
{
return (IExcelConditionalFormattingNotContainsErrors)AddRule(
eExcelConditionalFormattingRuleType.NotContainsErrors,
address);
}
///
/// Add NotContainsText Rule
///
///
///
public IExcelConditionalFormattingNotContainsText AddNotContainsText(
ExcelAddress address)
{
return (IExcelConditionalFormattingNotContainsText)AddRule(
eExcelConditionalFormattingRuleType.NotContainsText,
address);
}
///
/// Add NotEqual Rule
///
///
///
public IExcelConditionalFormattingNotEqual AddNotEqual(
ExcelAddress address)
{
return (IExcelConditionalFormattingNotEqual)AddRule(
eExcelConditionalFormattingRuleType.NotEqual,
address);
}
///
/// Add Unique Rule
///
///
///
public IExcelConditionalFormattingUniqueValues AddUniqueValues(
ExcelAddress address)
{
return (IExcelConditionalFormattingUniqueValues)AddRule(
eExcelConditionalFormattingRuleType.UniqueValues,
address);
}
///
/// Add ThreeColorScale Rule
///
///
///
public IExcelConditionalFormattingThreeColorScale AddThreeColorScale(
ExcelAddress address)
{
return (IExcelConditionalFormattingThreeColorScale)AddRule(
eExcelConditionalFormattingRuleType.ThreeColorScale,
address);
}
///
/// Add TwoColorScale Rule
///
///
///
public IExcelConditionalFormattingTwoColorScale AddTwoColorScale(
ExcelAddress address)
{
return (IExcelConditionalFormattingTwoColorScale)AddRule(
eExcelConditionalFormattingRuleType.TwoColorScale,
address);
}
///
/// Add ThreeIconSet Rule
///
/// The address
/// Type of iconset
///
public IExcelConditionalFormattingThreeIconSet AddThreeIconSet(ExcelAddress Address, eExcelconditionalFormatting3IconsSetType IconSet)
{
var icon = (IExcelConditionalFormattingThreeIconSet)AddRule(
eExcelConditionalFormattingRuleType.ThreeIconSet,
Address);
icon.IconSet = IconSet;
return icon;
}
///
/// Adds a FourIconSet rule
///
///
///
///
public IExcelConditionalFormattingFourIconSet AddFourIconSet(ExcelAddress Address, eExcelconditionalFormatting4IconsSetType IconSet)
{
var icon = (IExcelConditionalFormattingFourIconSet)AddRule(
eExcelConditionalFormattingRuleType.FourIconSet,
Address);
icon.IconSet = IconSet;
return icon;
}
///
/// Adds a FiveIconSet rule
///
///
///
///
public IExcelConditionalFormattingFiveIconSet AddFiveIconSet(ExcelAddress Address, eExcelconditionalFormatting5IconsSetType IconSet)
{
var icon = (IExcelConditionalFormattingFiveIconSet)AddRule(
eExcelConditionalFormattingRuleType.FiveIconSet,
Address);
icon.IconSet = IconSet;
return icon;
}
///
/// Adds a databar rule
///
///
///
///
public IExcelConditionalFormattingDataBarGroup AddDatabar(ExcelAddress Address, Color color)
{
var dataBar = (IExcelConditionalFormattingDataBarGroup)AddRule(
eExcelConditionalFormattingRuleType.DataBar,
Address);
dataBar.Color=color;
return dataBar;
}
#endregion Conditional Formatting Rules
}
}