/******************************************************************************* * 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 * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using OfficeOpenXml.Utils; using System.Xml; using System.Text.RegularExpressions; using OfficeOpenXml.DataValidation.Formulas.Contracts; using OfficeOpenXml.DataValidation.Contracts; namespace OfficeOpenXml.DataValidation { /// /// Excel datavalidation /// public abstract class ExcelDataValidation : XmlHelper, IExcelDataValidation { private const string _itemElementNodeName = "d:dataValidation"; private readonly string _errorStylePath = "@errorStyle"; private readonly string _errorTitlePath = "@errorTitle"; private readonly string _errorPath = "@error"; private readonly string _promptTitlePath = "@promptTitle"; private readonly string _promptPath = "@prompt"; private readonly string _operatorPath = "@operator"; private readonly string _showErrorMessagePath = "@showErrorMessage"; private readonly string _showInputMessagePath = "@showInputMessage"; private readonly string _typeMessagePath = "@type"; private readonly string _sqrefPath = "@sqref"; private readonly string _allowBlankPath = "@allowBlank"; protected readonly string _formula1Path = "d:formula1"; protected readonly string _formula2Path = "d:formula2"; internal ExcelDataValidation(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) : this(worksheet, address, validationType, null) { } /// /// Constructor /// /// worksheet that owns the validation /// Xml top node (dataValidations) /// Data validation type /// address for data validation internal ExcelDataValidation(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) : this(worksheet, address, validationType, itemElementNode, null) { } /// /// Constructor /// /// worksheet that owns the validation /// Xml top node (dataValidations) when importing xml /// Data validation type /// address for data validation /// Xml Namespace manager internal ExcelDataValidation(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base(namespaceManager != null ? namespaceManager : worksheet.NameSpaceManager) { Require.Argument(address).IsNotNullOrEmpty("address"); address = CheckAndFixRangeAddress(address); if (itemElementNode == null) { //var xmlDoc = worksheet.WorksheetXml; TopNode = worksheet.WorksheetXml.SelectSingleNode("//d:dataValidations", worksheet.NameSpaceManager); // did not succeed using the XmlHelper methods here... so I'm creating the new node using XmlDocument... var nsUri = NameSpaceManager.LookupNamespace("d"); //itemElementNode = TopNode.OwnerDocument.CreateElement(_itemElementNodeName, nsUri); itemElementNode = TopNode.OwnerDocument.CreateElement(_itemElementNodeName.Split(':')[1], nsUri); TopNode.AppendChild(itemElementNode); } TopNode = itemElementNode; ValidationType = validationType; Address = new ExcelAddress(address); Init(); } private void Init() { // set schema node order SchemaNodeOrder = new string[]{ "type", "errorStyle", "operator", "allowBlank", "showInputMessage", "showErrorMessage", "errorTitle", "error", "promptTitle", "prompt", "sqref", "formula1", "formula2" }; } private string CheckAndFixRangeAddress(string address) { if (address.Contains(',')) { throw new FormatException("Multiple addresses may not be commaseparated, use space instead"); } address = address.ToUpper(CultureInfo.InvariantCulture); if (Regex.IsMatch(address, @"[A-Z]+:[A-Z]+")) { address = AddressUtility.ParseEntireColumnSelections(address); } return address; } private void SetNullableBoolValue(string path, bool? val) { if (val.HasValue) { SetXmlNodeBool(path, val.Value); } else { DeleteNode(path); } } /// /// This method will validate the state of the validation /// /// If the state breaks the rules of the validation public virtual void Validate() { var address = Address.Address; // validate Formula1 if (string.IsNullOrEmpty(Formula1Internal)) { throw new InvalidOperationException("Validation of " + address + " failed: Formula1 cannot be empty"); } } #region Public properties /// /// True if the validation type allows operator to be set. /// public bool AllowsOperator { get { return ValidationType.AllowOperator; } } /// /// Address of data validation /// public ExcelAddress Address { get { return new ExcelAddress(GetXmlNodeString(_sqrefPath)); } private set { var address = AddressUtility.ParseEntireColumnSelections(value.Address); SetXmlNodeString(_sqrefPath, address); } } /// /// Validation type /// public ExcelDataValidationType ValidationType { get { var typeString = GetXmlNodeString(_typeMessagePath); return ExcelDataValidationType.GetBySchemaName(typeString); } private set { SetXmlNodeString(_typeMessagePath, value.SchemaName, true); } } /// /// Operator for comparison between the entered value and Formula/Formulas. /// public ExcelDataValidationOperator Operator { get { var operatorString = GetXmlNodeString(_operatorPath); if (!string.IsNullOrEmpty(operatorString)) { return (ExcelDataValidationOperator)Enum.Parse(typeof(ExcelDataValidationOperator), operatorString); } return default(ExcelDataValidationOperator); } set { if (!ValidationType.AllowOperator) { throw new InvalidOperationException("The current validation type does not allow operator to be set"); } SetXmlNodeString(_operatorPath, value.ToString()); } } /// /// Warning style /// public ExcelDataValidationWarningStyle ErrorStyle { get { var errorStyleString = GetXmlNodeString(_errorStylePath); if (!string.IsNullOrEmpty(errorStyleString)) { return (ExcelDataValidationWarningStyle)Enum.Parse(typeof(ExcelDataValidationWarningStyle), errorStyleString); } return ExcelDataValidationWarningStyle.undefined; } set { if (value == ExcelDataValidationWarningStyle.undefined) { DeleteNode(_errorStylePath); } SetXmlNodeString(_errorStylePath, value.ToString()); } } /// /// True if blanks should be allowed /// public bool? AllowBlank { get { return GetXmlNodeBoolNullable(_allowBlankPath); } set { SetNullableBoolValue(_allowBlankPath, value); } } /// /// True if input message should be shown /// public bool? ShowInputMessage { get { return GetXmlNodeBoolNullable(_showInputMessagePath); } set { SetNullableBoolValue(_showInputMessagePath, value); } } /// /// True if error message should be shown /// public bool? ShowErrorMessage { get { return GetXmlNodeBoolNullable(_showErrorMessagePath); } set { SetNullableBoolValue(_showErrorMessagePath, value); } } /// /// Title of error message box /// public string ErrorTitle { get { return GetXmlNodeString(_errorTitlePath); } set { SetXmlNodeString(_errorTitlePath, value); } } /// /// Error message box text /// public string Error { get { return GetXmlNodeString(_errorPath); } set { SetXmlNodeString(_errorPath, value); } } public string PromptTitle { get { return GetXmlNodeString(_promptTitlePath); } set { SetXmlNodeString(_promptTitlePath, value); } } public string Prompt { get { return GetXmlNodeString(_promptPath); } set { SetXmlNodeString(_promptPath, value); } } /// /// Formula 1 /// protected string Formula1Internal { get { return GetXmlNodeString(_formula1Path); } } /// /// Formula 2 /// protected string Formula2Internal { get { return GetXmlNodeString(_formula2Path); } } #endregion protected void SetValue(Nullable val, string path) where T : struct { if (!val.HasValue) { DeleteNode(path); } var stringValue = val.Value.ToString().Replace(',', '.'); SetXmlNodeString(path, stringValue); } } }