/******************************************************************************* Copyright (c) 2011, Perforce Software, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ /******************************************************************************* * Name : FormSpec.cs * * Author : dbb * * Description : Class used to abstract a form specification in Perforce. * ******************************************************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Perforce.P4 { /// /// Field Data Type for a field in a form specification. /// [Flags] public enum SpecFieldDataType { /// /// No value. /// None = 0x000, /// /// Word: a single word (any value). /// Word = 0x001, /// /// Date: a date/time field. /// Date = 0x002, /// /// Select: one of a set of words. /// Select = 0x004, /// /// Line: a one-liner. /// Line = 0x008, /// /// Text: a block of text. /// Text = 0x010, /// /// Bulk: text not indexed for 'p4 jobs -e' /// Bulk = 0x020 } /// /// Field Type for a field in a form specification. /// [Flags] public enum SpecFieldFieldType { /// /// The unique identifier for the field. /// Key = 0x000, /// /// Required: default provided, value must be present. /// Required = 0x001, /// /// Always: always set to the default when saving the form. /// Always = 0x002, /// /// Optional: no default, and not required to be present. /// Optional = 0x004, /// /// Default: default provided, still not required. /// Default =0x008, /// /// Once: set once to the default and never changed. /// Once = 0x010 } /// /// Specifies structural and semantic metadata for form types. /// public class FormSpec { /// /// Create an empty FormSpec /// public FormSpec() { Fields = new List(); FieldMap = new Dictionary(); Words = new List(); Formats = new List(); Values = new Dictionary(); Presets = new Dictionary(); Comments = null; } /// /// Create a FormSpec /// public FormSpec(List fields, Dictionary fieldmap, List words, List formats, Dictionary values, Dictionary presets, string comments) { Fields = fields; FieldMap = fieldmap; Words = words; Formats = formats; Values = values; Presets = presets; Comments = comments; } /// /// List of all SpecField objects for all fields defined for this Form type. /// public IList Fields { get; set; } /// /// Map, keyed by SpecField name, containing suitable allowed values for specific form fields. /// public Dictionary FieldMap { get; set; } /// /// List of "words" for this form type. /// public IList Words { get; set; } /// /// List of "formats" for this form type. /// public IList Formats { get; set; } /// /// Map, keyed by SpecField name, containing suitable allowed values for specific form fields. /// /// /// See the main Perforce documentation for formats used here. /// public Dictionary Values { get; set; } /// /// Map, keyed by SpecField name, containing preset (default) values for specific form fields. /// /// /// See the main Perforce documentation for formats used here. /// public Dictionary Presets { get; set; } /// /// a single (possibly rather long) string (which may contain embedded /// newlines) containing comments to be optionally used in GUI or /// other representations of the form type. /// public string Comments { get; set; } public SpecFieldDataType GetSpecFieldDataType(FormSpec formspec, string key) { string line; formspec.FieldMap.TryGetValue(key, out line); if (line==null) { return SpecFieldDataType.None; } string[] parts = line.Split(new char[] { ' ' }, 4); StringEnum data = parts[2]; return data; } /// /// Create a FormSpec from the tagged output of the 'spec' command /// /// Tagged object returned by the 'spec' command /// public static FormSpec FromSpecCmdTaggedOutput(TaggedObject obj) { FormSpec val = new FormSpec(); int idx = 0; // Check for each property in the tagged data, and use it to set the // appropriate filed in the object string key = String.Format("Fields{0}", idx); while (obj.ContainsKey(key)) { string fieldDef = obj[key]; val.Fields.Add(SpecField.FromSpecCmdTaggedData(fieldDef)); key = String.Format("Fields{0}", ++idx); } idx = 0; key = String.Format("Fields{0}", idx); while (obj.ContainsKey(key)) { string line = obj[key]; string[] parts = line.Split(new char[] { ' ' }, 3); val.FieldMap[parts[1]] = line; key = String.Format("Fields{0}", ++idx); } idx = 0; key = String.Format("Words{0}", idx); while (obj.ContainsKey(key)) { string word = obj[key]; val.Words.Add(word); key = String.Format("Words{0}", ++idx); } idx = 0; key = String.Format("Formats{0}", idx); while (obj.ContainsKey(key)) { string word = obj[key]; val.Formats.Add(word); key = String.Format("Formats{0}", ++idx); } idx = 0; key = String.Format("Values{0}", idx); while (obj.ContainsKey(key)) { string line = obj[key]; string[] parts = line.Split(new char[] { ' ' }, 2); val.Values[parts[0]] = parts[1]; key = String.Format("Values{0}", ++idx); } idx = 0; key = String.Format("Presets{0}", idx); while (obj.ContainsKey(key)) { string line = obj[key]; string[] parts = line.Split(new char[] { ' ' }, 2); val.Presets[parts[0]] = parts[1]; key = String.Format("Presets{0}", ++idx); } if (obj.ContainsKey("Comments")) { val.Comments = obj["Comments"]; } return val; } } /// /// Class representing a field in a FormSpec. /// public class SpecField { /// /// Create a default FormSpec /// public SpecField() { Code = -1; Name = null; DataType = SpecFieldDataType.Word; ; Length = 0; FieldType = SpecFieldFieldType.Optional; } /// /// Create a FormSpec /// public SpecField(int code, string name, SpecFieldDataType datatype, int length, SpecFieldFieldType fieldtype) { Code = code; Name = name; DataType = datatype; Length = length; FieldType = fieldtype; } /// /// Numeric code identifying this form field. /// public int Code { get; set;} /// /// Name of this form field. /// public string Name { get; set; } private StringEnum _dataType; /// /// A field's type, i.e. whether it's a single word, a date, a selection, or a text field /// public SpecFieldDataType DataType { get { return _dataType; } set { _dataType = value; } } /// /// The maximum length in characters (?) of this field. /// int Length { get; set; } private StringEnum _fieldType; /// /// Specifies whether the field is optional, required, a key, or set by the server. /// public SpecFieldFieldType FieldType { get { return _fieldType; } set { _fieldType = value; } } /// /// Create a SpecField from a 'Fields' entry in the tagged data from the 'spec' command. /// /// /// public static SpecField FromSpecCmdTaggedData(string def) { SpecField val = new SpecField(); string[] parts = def.Split(' '); int v =-1; int.TryParse(parts[0], out v); val.Code = v; val.Name = parts[1]; val._dataType = parts[2]; v =-1; int.TryParse(parts[3], out v); val.Length = v; val._fieldType = parts[4]; return val; } } }