/Spss/SpssVariablesCollection.cs
C# | 346 lines | 186 code | 51 blank | 109 comment | 43 complexity | f93fa8f492fa53133c3403ab12f6b2ac MD5 | raw file
Possible License(s): LGPL-2.1
- namespace Spss {
- using System;
- using System.IO;
- using System.Data;
- using System.Collections;
- using System.Diagnostics;
- using System.Globalization;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
-
- /// <summary>
- /// Class to manage the metadata of variables in an <see cref="SpssDataDocument">SPSS data document</see>.
- /// </summary>
- public sealed class SpssVariablesCollection : IList<SpssVariable> {
- /// <summary>
- /// The list of variables in the file, or that will shortly be committed to the file.
- /// </summary>
- private List<SpssVariable> variables;
-
- private KeyedCollection<string, SpssVariable> variablesLookup;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="SpssVariablesCollection"/> class.
- /// </summary>
- /// <param name="document">The hosting SPSS data document whose variables will be managed by
- /// this instance.</param>
- internal SpssVariablesCollection(SpssDataDocument document) {
- if (document == null) {
- throw new ArgumentNullException("document");
- }
-
- this.Document = document;
-
- InitializeVariablesList();
- }
-
- /// <summary>
- /// Gets the variable with a given name.
- /// </summary>
- public SpssVariable this[string varName] {
- get { return variablesLookup[varName]; }
- }
-
- /// <summary>
- /// The SPSS data document whose variables are being managed.
- /// </summary>
- public SpssDataDocument Document { get; private set; }
-
- /// <summary>
- /// The file handle of the SPSS data document whose variables are being managed.
- /// </summary>
- private Int32 FileHandle {
- get { return this.Document.Handle; }
- }
-
- /// <summary>
- /// Gets a value indicating whether a variable has been added to this document.
- /// </summary>
- public bool Contains(SpssVariable variable) {
- if (variable == null) throw new ArgumentNullException("variable");
-
- return variables.Contains(variable);
- }
-
- /// <summary>
- /// Gets a value indicating whether a variable exists in this document.
- /// </summary>
- /// <param name="varName">
- /// The name of the variable in question.
- /// </param>
- /// <returns>
- /// True if the variable already exists in the document. False otherwise.
- /// </returns>
- public bool Contains(string varName) {
- if (varName == null || varName.Length == 0)
- throw new ArgumentNullException("varName");
-
- return variablesLookup.Contains(varName);
- }
-
- /// <summary>
- /// Gets the position of a variable.
- /// </summary>
- /// <returns>
- /// The index of the variable, or -1 if not found.
- /// </returns>
- public int IndexOf(SpssVariable variable) {
- if (variable == null) throw new ArgumentNullException("variable");
- return variables.IndexOf(variable);
- }
-
- /// <summary>
- /// Gets the position of the variable with a given name.
- /// </summary>
- /// <returns>
- /// The index of the variable, or -1 if not found.
- /// </returns>
- public int IndexOf(string varName) {
- if (varName == null || varName.Length == 0) throw new ArgumentNullException("varName");
- return IndexOf(variablesLookup[varName]);
- }
-
- /// <summary>
- /// Adds a variable to the document at a specific index.
- /// </summary>
- public void Insert(int index, SpssVariable variable) {
- if (variable == null) throw new ArgumentNullException("variable");
- EnsureAuthoringDictionary();
- variable.AddToCollection(this);
- variablesLookup.Add(variable);
- variables.Insert(index, variable);
- }
-
- /// <summary>
- /// Adds a variable to the document.
- /// </summary>
- /// <returns>
- /// The index of the newly added variable.
- /// </returns>
- public void Add(SpssVariable variable) {
- if (variable == null) {
- throw new ArgumentNullException("variable");
- }
- EnsureAuthoringDictionary();
- variable.AddToCollection(this);
- variablesLookup.Add(variable);
- variables.Add(variable);
- }
-
- /// <summary>
- /// Removes a variable from the document.
- /// </summary>
- public bool Remove(SpssVariable variable) {
- if (variable == null) throw new ArgumentNullException("variable");
- EnsureAuthoringDictionary();
- try {
- variable.RemoveFromCollection(this);
- } catch (ArgumentException) {
- return false;
- }
- variables.Remove(variable);
- variablesLookup.Remove(variable.Name);
- return true;
- }
-
- /// <summary>
- /// Copies the definition of variables from this file to another.
- /// </summary>
- public void CopyTo(SpssVariablesCollection other, int index) {
- if (other == null) throw new ArgumentNullException("other");
- if (other == this) throw new ArgumentException("Must be a different variables collection.", "other");
-
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Defines the variables in the SPSS data file so that they mirror
- /// those defined in a <see cref="DataTable"/>.
- /// </summary>
- /// <param name="table">
- /// The DataTable whose list of columns are the ones we want to copy.
- /// </param>
- /// <param name="fillInMetadataCallback">
- /// The callback method to use to retrieve the additional metadata
- /// to put into the SPSS data document, that is not included in a DataTable.
- /// Optional.
- /// </param>
- public void ImportSchema(DataTable table, Action<SpssVariable> fillInMetadataCallback) {
- foreach (DataColumn column in table.Columns) {
- try {
- SpssVariable var;
- if (column.DataType == typeof(string)) {
- var = new SpssStringVariable();
- ((SpssStringVariable)var).Length = (column.MaxLength < 0 || column.MaxLength > SpssSafeWrapper.SPSS_MAX_LONGSTRING) ? SpssSafeWrapper.SPSS_MAX_LONGSTRING : column.MaxLength;
- } else if (column.DataType == typeof(DateTime))
- var = new SpssDateVariable();
- else {
- var = new SpssNumericVariable();
- if (column.DataType == typeof(float) || column.DataType == typeof(double)) {
- ((SpssNumericVariable)var).PrintDecimal = 2;
- ((SpssNumericVariable)var).WriteDecimal = 2;
- }
- }
-
- var.Name = GenerateColumnName(column.ColumnName);
- Add(var);
-
- // Provide opportunity for callback function to fill in variable-specific metadata
- if (fillInMetadataCallback != null) {
- try {
- fillInMetadataCallback(var);
- } catch (Exception ex) {
- throw new ApplicationException("Exception in metadata filler callback function on column " + column.ColumnName + ".", ex);
- }
- }
- } catch (Exception ex) {
- throw new ApplicationException("Error adding column " + column.ColumnName + " schema information to the SPSS .SAV data file.", ex);
- }
- }
- }
-
- /// <summary>
- /// Defines the variables in the SPSS data file so that they mirror
- /// those defined in a <see cref="DataTable"/>.
- /// </summary>
- /// <param name="table">
- /// The DataTable whose list of columns are the ones we want to copy.
- /// </param>
- public void ImportSchema(DataTable table) {
- ImportSchema(table, null);
- }
-
- /// <summary>
- /// Writes the variables to the dictionary.
- /// </summary>
- internal void Commit() {
- EnsureAuthoringDictionary();
-
- // Write the variables we have been caching into the data file.
- foreach (SpssVariable var in this) {
- var.CommitToDictionary();
- }
- }
-
- /// <summary>
- /// Comes up with a variable name guaranteed to be short enough
- /// to fit within the limits of SPSS.
- /// </summary>
- /// <param name="colName">
- /// The initially suggested name for a variable.
- /// </param>
- /// <returns>
- /// The original variable name, if it was within SPSS limits.
- /// Otherwise, it applies a string shortening algorithm and returns
- /// the shorter variable name.
- /// </returns>
- /// <remarks>
- /// The shortening algorithm takes the first and last several characters of the
- /// variable name and concatenates them together such that the resulting
- /// string is exactly the allowed length for a variable name.
- /// The process is not guaranteed to produce a unique variable name.
- /// </remarks>
- internal string GenerateColumnName(string colName) {
- if (colName.Length > SpssThinWrapper.SPSS_MAX_VARNAME)
- colName = colName.Substring(0, SpssThinWrapper.SPSS_MAX_VARNAME / 2) + colName.Substring(colName.Length - SpssThinWrapper.SPSS_MAX_VARNAME / 2);
- return colName;
- }
-
- /// <summary>
- /// Called when a <see cref="SpssVariable.Name"/> changes so that the lookup
- /// table can be updated.
- /// </summary>
- internal void ColumnNameUpdated(SpssVariable variable, string oldName) {
- variablesLookup.Remove(oldName);
- variablesLookup.Add(variable);
- }
-
- private void EnsureAuthoringDictionary() {
- Document.EnsureAuthoringDictionary();
- }
-
- private void InitializeVariablesList() {
- Debug.Assert(FileHandle >= 0, "Must be working with an open file.");
- int initialSize;
- SpssException.ThrowOnFailure(SpssSafeWrapper.spssGetNumberofVariables(FileHandle, out initialSize), "spssGetNumberofVariables");
- variables = new List<SpssVariable>(initialSize);
- variablesLookup = new SpssVariableKeyedCollection();
-
- string[] varNames;
- int[] varTypes;
- ReturnCode result = SpssException.ThrowOnFailure(SpssSafeWrapper.spssGetVarNames(FileHandle, out varNames, out varTypes), "spssGetVarNames", ReturnCode.SPSS_INVALID_FILE);
- if (result == ReturnCode.SPSS_INVALID_FILE) {
- // brand new file
- return;
- }
- Debug.Assert(varNames.Length == varTypes.Length);
- for (int i = 0; i < varNames.Length; i++) {
- this.Add(SpssVariable.LoadVariable(this, varNames[i], varTypes[i]));
- }
- }
-
- #region IList<SpssVariable> Members
-
- /// <summary>
- /// Gets the variable at some 0-based index.
- /// </summary>
- public SpssVariable this[int index] {
- get { return variables[index]; }
- set { variables[index] = value; }
- }
-
- #endregion
-
- #region ICollection<SpssVariable> Members
-
- public void CopyTo(SpssVariable[] array, int arrayIndex) {
- throw new NotImplementedException();
- }
-
- #endregion
-
- #region IEnumerable<SpssVariable> Members
-
- IEnumerator<SpssVariable> IEnumerable<SpssVariable>.GetEnumerator() {
- return this.variables.GetEnumerator();
- }
-
- #endregion
-
- #region IList<SpssVariable> Members
-
-
- public void RemoveAt(int index) {
- throw new NotImplementedException();
- }
-
- #endregion
-
- #region ICollection<SpssVariable> Members
-
- public void Clear() {
- EnsureAuthoringDictionary();
- while (this.variables.Count > 0) {
- this.Remove(this.variables[0]);
- }
- }
-
- public int Count {
- get { return this.variables.Count; }
- }
-
- public bool IsReadOnly {
- get { return !this.Document.IsAuthoringDictionary; }
- }
-
- #endregion
-
- #region IEnumerable Members
-
- IEnumerator IEnumerable.GetEnumerator() {
- return this.variables.GetEnumerator();
- }
-
- #endregion
- }
- }