Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3044_variableScaling/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs

Last change on this file was 12074, checked in by sraggl, 10 years ago

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 19.2 KB
Line 
1/*******************************************************************************
2 * You may amend and distribute as you like, but don't remove this header!
3 *
4 * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
5 * See http://www.codeplex.com/EPPlus for details.
6 *
7 * Copyright (C) 2011  Jan Källman
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
17 * See the GNU Lesser General Public License for more details.
18 *
19 * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
20 * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
21 *
22 * All code and executables are provided "as is" with no warranty either express or implied.
23 * The author accepts no liability for any damage or loss of business that this product may cause.
24 *
25 * Code change notes:
26 *
27 * Author             Change            Date
28 * ******************************************************************************
29 * Eyal Seagull        Added            2012-04-03
30 *******************************************************************************/
31using System;
32using System.Collections.Generic;
33using System.Linq;
34using System.Text;
35using System.Drawing;
36using System.Xml;
37using OfficeOpenXml.Utils;
38using System.Text.RegularExpressions;
39using OfficeOpenXml.ConditionalFormatting.Contracts;
40using OfficeOpenXml.Style.Dxf;
41
42namespace OfficeOpenXml.ConditionalFormatting
43{
44  /// <summary>
45  ///
46  /// </summary>
47  public abstract class ExcelConditionalFormattingRule
48    : XmlHelper,
49    IExcelConditionalFormattingRule
50  {
51    /****************************************************************************************/
52
53    #region Private Properties
54    private eExcelConditionalFormattingRuleType? _type;
55    private ExcelWorksheet _worksheet;
56
57    /// <summary>
58    /// Sinalize that we are in a Cnaging Priorities opeartion so that we won't enter
59    /// a recursive loop.
60    /// </summary>
61    private static bool _changingPriority = false;
62    #endregion Private Properties
63
64    /****************************************************************************************/
65
66    #region Constructors
67    /// <summary>
68    /// Initialize the <see cref="ExcelConditionalFormattingRule"/>
69    /// </summary>
70    /// <param name="type"></param>
71    /// <param name="address"></param>
72    /// <param name="priority">Used also as the cfRule unique key</param>
73    /// <param name="worksheet"></param>
74    /// <param name="itemElementNode"></param>
75    /// <param name="namespaceManager"></param>
76    internal ExcelConditionalFormattingRule(
77      eExcelConditionalFormattingRuleType type,
78      ExcelAddress address,
79      int priority,
80      ExcelWorksheet worksheet,
81      XmlNode itemElementNode,
82      XmlNamespaceManager namespaceManager)
83      : base(
84        namespaceManager,
85        itemElementNode)
86    {
87      Require.Argument(address).IsNotNull("address");
88      Require.Argument(priority).IsInRange(1, int.MaxValue, "priority");
89      Require.Argument(worksheet).IsNotNull("worksheet");
90
91      _type = type;
92      _worksheet = worksheet;
93      SchemaNodeOrder = _worksheet.SchemaNodeOrder;
94
95      if (itemElementNode == null)
96      {
97        // Create/Get the <cfRule> inside <conditionalFormatting>
98        itemElementNode = CreateComplexNode(
99          _worksheet.WorksheetXml.DocumentElement,
100          string.Format(
101            "{0}[{1}='{2}']/{1}='{2}'/{3}[{4}='{5}']/{4}='{5}'",
102          //{0}
103            ExcelConditionalFormattingConstants.Paths.ConditionalFormatting,
104          // {1}
105            ExcelConditionalFormattingConstants.Paths.SqrefAttribute,
106          // {2}
107            address.AddressSpaceSeparated,          //CF node don't what to have comma between multi addresses, use space instead.
108          // {3}
109            ExcelConditionalFormattingConstants.Paths.CfRule,
110          //{4}
111            ExcelConditionalFormattingConstants.Paths.PriorityAttribute,
112          //{5}
113            priority));
114      }
115
116      // Point to <cfRule>
117      TopNode = itemElementNode;
118
119      Address = address;
120      Priority = priority;
121      Type = type;
122      if (DxfId >= 0)
123      {
124          worksheet.Workbook.Styles.Dxfs[DxfId].AllowChange = true;  //This Id is referenced by CF, so we can use it when we save.
125          _style = worksheet.Workbook.Styles.Dxfs[DxfId].Clone();    //Clone, so it can be altered without effecting other dxf styles
126      }
127    }
128
129    /// <summary>
130    /// Initialize the <see cref="ExcelConditionalFormattingRule"/>
131    /// </summary>
132    /// <param name="type"></param>
133    /// <param name="address"></param>
134    /// <param name="priority"></param>
135    /// <param name="worksheet"></param>
136    /// <param name="namespaceManager"></param>
137    internal ExcelConditionalFormattingRule(
138      eExcelConditionalFormattingRuleType type,
139      ExcelAddress address,
140      int priority,
141      ExcelWorksheet worksheet,
142      XmlNamespaceManager namespaceManager)
143      : this(
144        type,
145        address,
146        priority,
147        worksheet,
148        null,
149        namespaceManager)
150    {
151    }
152    #endregion Constructors
153
154    /****************************************************************************************/
155
156    #region Methods
157    #endregion Methods
158
159    /****************************************************************************************/
160
161    #region Exposed Properties
162    /// <summary>
163    /// Get the &lt;cfRule&gt; node
164    /// </summary>
165    public XmlNode Node
166    {
167      get { return TopNode; }
168    }
169
170    /// <summary>
171    /// Address of the conditional formatting rule
172    /// </summary>
173    /// <remarks>
174    /// The address is stores in a parent node called &lt;conditionalFormatting&gt; in the
175    /// @sqref attribute. Excel groups rules that have the same address inside one node.
176    /// </remarks>
177    public ExcelAddress Address
178    {
179      get
180      {
181        return new ExcelAddress(
182          Node.ParentNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Sqref].Value);
183      }
184      set
185      {
186        // Check if the address is to be changed
187        if (Address.Address != value.Address)
188        {
189          // Save the old parente node
190          XmlNode oldNode = Node;
191          XmlNode oldParentNode = Node.ParentNode;
192
193          // Create/Get the new <conditionalFormatting> parent node
194          XmlNode newParentNode = CreateComplexNode(
195            _worksheet.WorksheetXml.DocumentElement,
196            string.Format(
197              "{0}[{1}='{2}']/{1}='{2}'",
198            //{0}
199              ExcelConditionalFormattingConstants.Paths.ConditionalFormatting,
200            // {1}
201              ExcelConditionalFormattingConstants.Paths.SqrefAttribute,
202            // {2}
203              value.AddressSpaceSeparated));
204
205          // Move the <cfRule> node to the new <conditionalFormatting> parent node
206          TopNode = newParentNode.AppendChild(Node);
207
208          // Check if the old <conditionalFormatting> parent node has <cfRule> node inside it
209          if (!oldParentNode.HasChildNodes)
210          {
211            // Remove the old parent node
212            oldParentNode.ParentNode.RemoveChild(oldParentNode);
213          }
214        }
215      }
216    }
217
218    /// <summary>
219    /// Type of conditional formatting rule. ST_CfType §18.18.12.
220    /// </summary>
221    public eExcelConditionalFormattingRuleType Type
222    {
223      get
224      {
225        // Transform the @type attribute to EPPlus Rule Type (slighty diferente)
226        if(_type==null)
227        {
228          _type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute(
229          GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.TypeAttribute),
230          TopNode,
231          _worksheet.NameSpaceManager);
232        }
233        return (eExcelConditionalFormattingRuleType)_type;
234      }
235      internal set
236      {
237          _type = value;
238          // Transform the EPPlus Rule Type to @type attribute (slighty diferente)
239        SetXmlNodeString(
240          ExcelConditionalFormattingConstants.Paths.TypeAttribute,
241          ExcelConditionalFormattingRuleType.GetAttributeByType(value),
242          true);
243      }
244    }
245
246    /// <summary>
247    /// The priority of this conditional formatting rule. This value is used to determine
248    /// which format should be evaluated and rendered. Lower numeric values are higher
249    /// priority than higher numeric values, where 1 is the highest priority.
250    /// </summary>
251    public int Priority
252    {
253      get
254      {
255        return GetXmlNodeInt(
256          ExcelConditionalFormattingConstants.Paths.PriorityAttribute);
257      }
258      set
259      {
260        // Save the current CF rule priority
261        int priority = Priority;
262
263        // Check if the @priority is to be changed
264        if (priority != value)
265        {
266          // Check if we are not already inside a "Change Priority" operation
267          if (!_changingPriority)
268          {
269            if (value < 1)
270            {
271              throw new IndexOutOfRangeException(
272                ExcelConditionalFormattingConstants.Errors.InvalidPriority);
273            }
274
275            // Sinalize that we are already changing cfRules priorities
276            _changingPriority = true;
277
278            // Check if we lowered the priority
279            if (priority > value)
280            {
281              for (int i = priority - 1; i >= value; i--)
282              {
283                var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i);
284
285                if (cfRule != null)
286                {
287                  cfRule.Priority++;
288                }
289              }
290            }
291            else
292            {
293              for (int i = priority + 1; i <= value; i++)
294              {
295                var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i);
296
297                if (cfRule != null)
298                {
299                  cfRule.Priority--;
300                }
301              }
302            }
303
304            // Sinalize that we are no longer changing cfRules priorities
305            _changingPriority = false;
306          }
307
308          // Change the priority in the XML
309          SetXmlNodeString(
310            ExcelConditionalFormattingConstants.Paths.PriorityAttribute,
311            value.ToString(),
312            true);
313        }
314      }
315    }
316
317    /// <summary>
318    /// If this flag is true, no rules with lower priority shall be applied over this rule,
319    /// when this rule evaluates to true.
320    /// </summary>
321    public bool StopIfTrue
322    {
323      get
324      {
325        return GetXmlNodeBool(
326          ExcelConditionalFormattingConstants.Paths.StopIfTrueAttribute);
327      }
328      set
329      {
330        SetXmlNodeString(
331          ExcelConditionalFormattingConstants.Paths.StopIfTrueAttribute,
332          (value == true) ? "1" : string.Empty,
333          true);
334      }
335    }
336
337    /// <summary>
338    /// DxfId Style Attribute
339    /// </summary>
340    internal int DxfId
341    {
342      get
343      {
344        return GetXmlNodeInt(
345          ExcelConditionalFormattingConstants.Paths.DxfIdAttribute);
346      }
347      set
348      {
349        SetXmlNodeString(
350          ExcelConditionalFormattingConstants.Paths.DxfIdAttribute,
351          (value == int.MinValue) ? string.Empty : value.ToString(),
352          true);
353      }
354    }
355    internal ExcelDxfStyleConditionalFormatting _style = null;
356    public ExcelDxfStyleConditionalFormatting Style
357    {
358        get
359        {
360            if (_style == null)
361            {
362                _style = new ExcelDxfStyleConditionalFormatting(NameSpaceManager, null, _worksheet.Workbook.Styles);
363            }
364            return _style;
365        }
366    }
367    /// <summary>
368    /// StdDev (zero is not allowed and will be converted to 1)
369    /// </summary>
370    public UInt16 StdDev
371    {
372      get
373      {
374        return Convert.ToUInt16(GetXmlNodeInt(
375          ExcelConditionalFormattingConstants.Paths.StdDevAttribute));
376      }
377      set
378      {
379        SetXmlNodeString(
380          ExcelConditionalFormattingConstants.Paths.StdDevAttribute,
381          (value == 0) ? "1" : value.ToString(),
382          true);
383      }
384    }
385
386    /// <summary>
387    /// Rank (zero is not allowed and will be converted to 1)
388    /// </summary>
389    public UInt16 Rank
390    {
391      get
392      {
393        return Convert.ToUInt16(GetXmlNodeInt(
394          ExcelConditionalFormattingConstants.Paths.RankAttribute));
395      }
396      set
397      {
398        SetXmlNodeString(
399          ExcelConditionalFormattingConstants.Paths.RankAttribute,
400          (value == 0) ? "1" : value.ToString(),
401          true);
402      }
403    }
404    #endregion Exposed Properties
405
406    /****************************************************************************************/
407
408    #region Internal Properties
409    /// <summary>
410    /// AboveAverage
411    /// </summary>
412    internal protected bool? AboveAverage
413    {
414      get
415      {
416        bool? aboveAverage = GetXmlNodeBoolNullable(
417          ExcelConditionalFormattingConstants.Paths.AboveAverageAttribute);
418
419        // Above Avarege if TRUE or if attribute does not exists
420        return (aboveAverage == true) || (aboveAverage == null);
421      }
422      set
423      {
424        string aboveAverageValue = string.Empty;
425
426        // Only the types that needs the @AboveAverage
427        if ((_type == eExcelConditionalFormattingRuleType.BelowAverage)
428          || (_type == eExcelConditionalFormattingRuleType.BelowOrEqualAverage)
429          || (_type == eExcelConditionalFormattingRuleType.BelowStdDev))
430        {
431          aboveAverageValue = "0";
432        }
433
434        SetXmlNodeString(
435          ExcelConditionalFormattingConstants.Paths.AboveAverageAttribute,
436          aboveAverageValue,
437          true);
438      }
439    }
440
441    /// <summary>
442    /// EqualAverage
443    /// </summary>
444    internal protected bool? EqualAverage
445    {
446      get
447      {
448        bool? equalAverage = GetXmlNodeBoolNullable(
449          ExcelConditionalFormattingConstants.Paths.EqualAverageAttribute);
450
451        // Equal Avarege only if TRUE
452        return (equalAverage == true);
453      }
454      set
455      {
456        string equalAverageValue = string.Empty;
457
458        // Only the types that needs the @EqualAverage
459        if ((_type == eExcelConditionalFormattingRuleType.AboveOrEqualAverage)
460          || (_type == eExcelConditionalFormattingRuleType.BelowOrEqualAverage))
461        {
462          equalAverageValue = "1";
463        }
464
465        SetXmlNodeString(
466          ExcelConditionalFormattingConstants.Paths.EqualAverageAttribute,
467          equalAverageValue,
468          true);
469      }
470    }
471
472    /// <summary>
473    /// Bottom attribute
474    /// </summary>
475    internal protected bool? Bottom
476    {
477      get
478      {
479        bool? bottom = GetXmlNodeBoolNullable(
480          ExcelConditionalFormattingConstants.Paths.BottomAttribute);
481
482        // Bottom if TRUE
483        return (bottom == true);
484      }
485      set
486      {
487        string bottomValue = string.Empty;
488
489        // Only the types that needs the @Bottom
490        if ((_type == eExcelConditionalFormattingRuleType.Bottom)
491          || (_type == eExcelConditionalFormattingRuleType.BottomPercent))
492        {
493          bottomValue = "1";
494        }
495
496        SetXmlNodeString(
497          ExcelConditionalFormattingConstants.Paths.BottomAttribute,
498          bottomValue,
499          true);
500      }
501    }
502
503    /// <summary>
504    /// Percent attribute
505    /// </summary>
506    internal protected bool? Percent
507    {
508      get
509      {
510        bool? percent = GetXmlNodeBoolNullable(
511          ExcelConditionalFormattingConstants.Paths.PercentAttribute);
512
513        // Bottom if TRUE
514        return (percent == true);
515      }
516      set
517      {
518        string percentValue = string.Empty;
519
520        // Only the types that needs the @Bottom
521        if ((_type == eExcelConditionalFormattingRuleType.BottomPercent)
522          || (_type == eExcelConditionalFormattingRuleType.TopPercent))
523        {
524          percentValue = "1";
525        }
526
527        SetXmlNodeString(
528          ExcelConditionalFormattingConstants.Paths.PercentAttribute,
529          percentValue,
530          true);
531      }
532    }
533
534    /// <summary>
535    /// TimePeriod
536    /// </summary>
537    internal protected eExcelConditionalFormattingTimePeriodType TimePeriod
538    {
539      get
540      {
541        return ExcelConditionalFormattingTimePeriodType.GetTypeByAttribute(
542          GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.TimePeriodAttribute));
543      }
544      set
545      {
546        SetXmlNodeString(
547          ExcelConditionalFormattingConstants.Paths.TimePeriodAttribute,
548          ExcelConditionalFormattingTimePeriodType.GetAttributeByType(value),
549          true);
550      }
551    }
552
553    /// <summary>
554    /// Operator
555    /// </summary>
556    internal protected eExcelConditionalFormattingOperatorType Operator
557    {
558      get
559      {
560        return ExcelConditionalFormattingOperatorType.GetTypeByAttribute(
561          GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.OperatorAttribute));
562      }
563      set
564      {
565        SetXmlNodeString(
566          ExcelConditionalFormattingConstants.Paths.OperatorAttribute,
567          ExcelConditionalFormattingOperatorType.GetAttributeByType(value),
568          true);
569      }
570    }
571
572    /// <summary>
573    /// Formula
574    /// </summary>
575    public string Formula
576    {
577      get
578      {
579        return GetXmlNodeString(
580          ExcelConditionalFormattingConstants.Paths.Formula);
581      }
582      set
583      {
584        SetXmlNodeString(
585          ExcelConditionalFormattingConstants.Paths.Formula,
586          value);
587      }
588    }
589
590    /// <summary>
591    /// Formula2
592    /// </summary>
593    public string Formula2
594    {
595      get
596      {
597        return GetXmlNodeString(
598          string.Format(
599            "{0}[position()=2]",
600          // {0}
601            ExcelConditionalFormattingConstants.Paths.Formula));
602      }
603      set
604      {
605        // Create/Get the first <formula> node (ensure that it exists)
606        var firstNode = CreateComplexNode(
607          TopNode,
608          string.Format(
609            "{0}[position()=1]",
610          // {0}
611            ExcelConditionalFormattingConstants.Paths.Formula));
612
613        // Create/Get the seconde <formula> node (ensure that it exists)
614        var secondNode = CreateComplexNode(
615          TopNode,
616          string.Format(
617            "{0}[position()=2]",
618          // {0}
619            ExcelConditionalFormattingConstants.Paths.Formula));
620
621        // Save the formula in the second <formula> node
622        secondNode.InnerText = value;
623      }
624    }
625    #endregion Internal Properties
626    /****************************************************************************************/
627  }
628}
Note: See TracBrowser for help on using the repository browser.