Example #1
0
 public static Variable GetItem(VariableProperty attribute, string value)
 {
     switch ( attribute )
     {
         case VariableProperty.Name:
             return GetItemByName(value);
         case VariableProperty.ShortName:
             return GetItemByShortName(value);
         case VariableProperty.Url:
             return GetItemByUrl(value);
         default:
             return null;
     }
 }
        /// <summary>
        /// User has changed the value of a cell. Validate the change
        /// apply the change.
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="args">Event parameters</param>
        private void OnCellsChanged(object sender, GridCellsChangedArgs args)
        {
            List <ChangeProperty.Property> changes = new List <ChangeProperty.Property>();

            // If all cells are being set to null, and the number of changed
            // cells is a multiple of the number of properties, we could be
            // deleting an entire row (or rows). In this case, we need
            // different logic, to resize all of the arrays.
            bool deletedRow = false;

            if (args.ChangedCells.All(c => c.NewValue == null) &&
                args.ChangedCells.Count % properties.Where(p => !p.IsReadOnly).Count() == 0)
            {
                // Get list of distinct rows which have been changed.
                int[]      changedRows  = args.ChangedCells.Select(c => c.RowIndex).Distinct().ToArray();
                List <int> rowsToDelete = new List <int>();
                foreach (int row in changedRows)
                {
                    // Get columns which have been changed in this row.
                    var   changesInRow = args.ChangedCells.Where(c => c.RowIndex == row);
                    int[] columns      = changesInRow.Select(c => c.ColIndex).ToArray();

                    // If all non-readonly properties have been set to null in this row,
                    // delete the row.
                    bool deleteRow = true;
                    for (int i = 0; i < properties.Count; i++)
                    {
                        if (!properties[i].IsReadOnly && !columns.Contains(i))
                        {
                            deleteRow = false;
                        }
                    }

                    if (deleteRow)
                    {
                        // We can't delete the row now - what if the user has deleted
                        // multiple rows at once (this is possible via shift-clicking).
                        // We need one change property command per property. Otherwise,
                        // only the last command will have an effect.
                        deletedRow = true;
                        rowsToDelete.Add(row);
                    }
                }

                if (rowsToDelete.Count > 0)
                {
                    // This assumes that only consecutive rows can be deleted together.
                    // ie the user can shift click multiple rows and hit delete to delete
                    // more than 1 row. They cannot ctrl click to select non-adjacent rows.
                    int from = rowsToDelete.Min();
                    int to   = rowsToDelete.Max();
                    changes.AddRange(DeleteRows(from, to));

                    // Remove cells in deleted rows from list of changed cells,
                    // as we've already dealt with them.
                    args.ChangedCells = args.ChangedCells.Where(c => !rowsToDelete.Contains(c.RowIndex)).ToList();
                }
            }

            foreach (var column in args.ChangedCells.GroupBy(c => c.ColIndex))
            {
                VariableProperty property = properties[column.Key];
                if (property == null || property.IsReadOnly)
                {
                    continue;
                }

                // Get a deep copy of the property value.
                Array newArray = property.Value as Array;
                if (newArray == null && property.Value != null)
                {
                    continue;
                }
                newArray = Clone(newArray, property.DataType.GetElementType());

                // It's possible to change multiple values in the same column
                // simultaneously via multi-selection. If we just add a change
                // property command for each individual change, later changes
                // would overwrite the earlier changes. We need to merge all
                // changes to a single column into a single command then move
                // onto the next column.
                foreach (GridCellChangedArgs change in column)
                {
                    if (change.NewValue == change.OldValue)
                    {
                        continue; // silently fail
                    }
                    // If the user has entered data into a new row, we will need to
                    // resize all of the array properties.
                    changes.AddRange(CheckArrayLengths(change));

                    object element = ReflectionUtilities.StringToObject(property.DataType.GetElementType(), change.NewValue);
                    if (newArray.Length <= change.RowIndex)
                    {
                        Resize(ref newArray, change.RowIndex + 1);
                    }

                    newArray.SetValue(element, change.RowIndex);
                }
                changes.Add(new ChangeProperty.Property(property.Object, property.Name, newArray));
            }

            // Apply all changes to the model in a single undoable command.
            SetPropertyValue(new ChangeProperty(changes));

            // Update the value shown in the grid. This needs to happen after
            // we have applied changes to the model for obvious reasons.
            foreach (GridCellChangedArgs cell in args.ChangedCells)
            {
                // Add new rows to the view's grid if necessary.
                while (grid.RowCount <= cell.RowIndex + 1)
                {
                    grid.RowCount++;
                }
                grid.DataSource.Rows[cell.RowIndex][cell.ColIndex] = GetCellValue(cell.RowIndex, cell.ColIndex);
            }

            // If the user deleted an entire row, do a full refresh of the
            // grid. Otherwise, only refresh read-only columns (PAWC).
            if (deletedRow)
            {
                PopulateGrid(model);
            }
            else
            {
                UpdateReadOnlyProperties();
            }
        }
        /// <summary>
        /// The view is asking for variable names for its intellisense.
        /// </summary>
        /// <param name="atype">Data type for which we want completion options.</param>
        /// <param name="properties">If true, property suggestions will be generated.</param>
        /// <param name="methods">If true, method suggestions will be generated.</param>
        /// <param name="events">If true, event suggestions will be generated.</param>
        /// <returns>List of completion options.</returns>
        public static List <ContextItem> ExamineTypeForContextItems(Type atype, bool properties, bool methods, bool events)
        {
            List <ContextItem> allItems = new List <ContextItem>();

            // find the properties and methods
            if (atype != null)
            {
                if (properties)
                {
                    foreach (PropertyInfo property in atype.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                    {
                        VariableProperty var = new VariableProperty(atype, property);
                        NeedContextItemsArgs.ContextItem item = new NeedContextItemsArgs.ContextItem();
                        item.Name        = var.Name;
                        item.IsProperty  = true;
                        item.IsEvent     = false;
                        item.IsWriteable = !var.IsReadOnly;
                        item.TypeName    = var.DataType.Name;
                        item.Descr       = var.Description;
                        item.Units       = var.Units;
                        allItems.Add(item);
                    }
                }

                if (methods)
                {
                    foreach (MethodInfo method in atype.GetMethods(BindingFlags.Instance | BindingFlags.Public))
                    {
                        if (!method.Name.StartsWith("get_") && !method.Name.StartsWith("set_"))
                        {
                            DescriptionAttribute             descriptionAttribute = ReflectionUtilities.GetAttribute(atype, typeof(DescriptionAttribute), false) as DescriptionAttribute;
                            NeedContextItemsArgs.ContextItem item = new NeedContextItemsArgs.ContextItem();
                            item.Name        = method.Name;
                            item.IsProperty  = false;
                            item.IsEvent     = true;
                            item.IsWriteable = false;
                            item.TypeName    = method.ReturnType.Name;
                            if (descriptionAttribute != null)
                            {
                                item.Descr = descriptionAttribute.ToString();
                            }
                            item.Units = string.Empty;

                            // build a parameter string representation
                            ParameterInfo[] allparams = method.GetParameters();
                            StringBuilder   paramText = new StringBuilder("( ");
                            if (allparams.Count() > 0)
                            {
                                for (int p = 0; p < allparams.Count(); p++)
                                {
                                    ParameterInfo parameter = allparams[p];
                                    paramText.Append(parameter.ParameterType.Name + " " + parameter.Name);
                                    if (p < allparams.Count() - 1)
                                    {
                                        paramText.Append(", ");
                                    }
                                }
                            }
                            paramText.Append(" )");
                            item.ParamString = paramText.ToString();

                            allItems.Add(item);
                        }
                    }
                }

                if (events)
                {
                    foreach (EventInfo evnt in atype.GetEvents(BindingFlags.Instance | BindingFlags.Public))
                    {
                        NeedContextItemsArgs.ContextItem item = new NeedContextItemsArgs.ContextItem();
                        item.Name        = evnt.Name;
                        item.IsProperty  = true;
                        item.IsEvent     = true;
                        item.IsWriteable = false;
                        item.TypeName    = evnt.ReflectedType.Name;
                        item.Descr       = "";
                        item.Units       = "";
                        allItems.Add(item);
                    }
                }
            }

            allItems.Sort(delegate(ContextItem c1, ContextItem c2) { return(c1.Name.CompareTo(c2.Name)); });
            return(allItems);
        }
Example #4
0
        /// <summary>
        /// The view is asking for variable names for its intellisense.
        /// </summary>
        /// <param name="atype">Data type for which we want completion options.</param>
        /// <param name="properties">If true, property suggestions will be generated.</param>
        /// <param name="methods">If true, method suggestions will be generated.</param>
        /// <param name="publishedEvents">If true, published events will be returned.</param>
        /// <param name="subscribedEvents">If true, subscribed events will be returned.</param>
        /// <returns>List of completion options.</returns>
        public static List <ContextItem> ExamineTypeForContextItems(Type atype, bool properties, bool methods, bool publishedEvents, bool subscribedEvents)
        {
            List <ContextItem> allItems = new List <ContextItem>();

            // find the properties and methods
            if (atype != null)
            {
                if (properties)
                {
                    foreach (PropertyInfo property in atype.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                    {
                        VariableProperty var  = new VariableProperty(atype, property);
                        ContextItem      item = new ContextItem
                        {
                            Name        = var.Name,
                            IsProperty  = true,
                            IsEvent     = false,
                            IsWriteable = !var.IsReadOnly,
                            TypeName    = GetTypeName(var.DataType),
                            Descr       = GetDescription(property),
                            Units       = var.Units
                        };
                        allItems.Add(item);
                    }
                }

                if (methods)
                {
                    foreach (MethodInfo method in atype.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy))
                    {
                        if (!method.Name.StartsWith("get_") && !method.Name.StartsWith("set_") &&
                            !method.Name.StartsWith("add_") && !method.Name.StartsWith("remove_"))
                        {
                            ContextItem item = new ContextItem
                            {
                                Name        = method.Name,
                                IsProperty  = false,
                                IsEvent     = false,
                                IsMethod    = true,
                                IsWriteable = false,
                                TypeName    = method.ReturnType.Name,
                                Descr       = GetDescription(method),
                                Units       = string.Empty
                            };

                            // build a parameter string representation
                            ParameterInfo[] allparams = method.GetParameters();
                            StringBuilder   paramText = new StringBuilder("( ");
                            if (allparams.Count() > 0)
                            {
                                for (int p = 0; p < allparams.Count(); p++)
                                {
                                    ParameterInfo parameter = allparams[p];
                                    paramText.Append(parameter.ParameterType.Name + " " + parameter.Name);
                                    if (parameter.DefaultValue != DBNull.Value)
                                    {
                                        paramText.Append(" = " + parameter.DefaultValue?.ToString() ?? "null");
                                    }
                                    if (p < allparams.Count() - 1)
                                    {
                                        paramText.Append(", ");
                                    }
                                }
                            }
                            paramText.Append(" )");
                            item.ParamString = paramText.ToString();

                            allItems.Add(item);
                        }
                    }
                }

                if (publishedEvents)
                {
                    foreach (EventInfo evnt in atype.GetEvents(BindingFlags.Instance | BindingFlags.Public))
                    {
                        NeedContextItemsArgs.ContextItem item = new NeedContextItemsArgs.ContextItem();
                        item.Name        = evnt.Name;
                        item.IsProperty  = true;
                        item.IsEvent     = true;
                        item.IsMethod    = false;
                        item.IsWriteable = false;
                        item.TypeName    = evnt.ReflectedType.Name;
                        item.Descr       = GetDescription(evnt);
                        item.Units       = "";
                        allItems.Add(item);
                    }
                }

                if (subscribedEvents)
                {
                    foreach (MethodInfo method in atype.GetMethods(/*BindingFlags.Instance |*/ BindingFlags.NonPublic | BindingFlags.FlattenHierarchy))
                    {
                        EventSubscribeAttribute subscriberAttribute = (EventSubscribeAttribute)ReflectionUtilities.GetAttribute(method, typeof(EventSubscribeAttribute), false);
                        if (subscriberAttribute != null)
                        {
                            NeedContextItemsArgs.ContextItem item = new NeedContextItemsArgs.ContextItem();
                            item.Name        = subscriberAttribute.ToString();
                            item.IsProperty  = false;
                            item.IsEvent     = false;
                            item.IsMethod    = true;
                            item.IsWriteable = false;
                            item.TypeName    = atype.Name;
                            item.Descr       = GetDescription(atype);
                            item.Units       = "";
                            allItems.Add(item);
                        }
                    }
                }
            }

            allItems.Sort(delegate(ContextItem c1, ContextItem c2) { return(c1.Name.CompareTo(c2.Name)); });
            return(allItems);
        }
Example #5
0
        /// <summary>
        /// Format the grid.
        /// </summary>
        protected virtual void FormatGrid()
        {
            for (int i = 0; i < properties.Count; i++)
            {
                IGridCell cell = grid.GetCell(1, i);

                if (properties[i] is VariableObject)
                {
                    cell.EditorType = EditorTypeEnum.TextBox;

                    grid.SetRowAsSeparator(i, true);
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.TableName)
                {
                    cell.EditorType      = EditorTypeEnum.DropDown;
                    cell.DropDownStrings = storage.Reader.TableNames.ToArray();
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.CultivarName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    IPlant crop;
                    if (properties[i].Display.PlantName != null)
                    {
                        crop = Apsim.FindAll(model, typeof(IPlant)).FirstOrDefault(p => p.Name == properties[i].Display.PlantName) as IPlant;
                    }
                    else
                    {
                        crop = GetCrop(properties);
                    }
                    if (crop != null)
                    {
                        cell.DropDownStrings = GetCultivarNames(crop);
                    }
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.FileName)
                {
                    cell.EditorType = EditorTypeEnum.Button;
                }
                else if (properties[i].Display != null && properties[i].Display.Type == DisplayType.FileNames)
                {
                    cell.EditorType = EditorTypeEnum.MultiFiles;
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.FieldName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    List <string> fieldNames = GetFieldNames();
                    if (fieldNames != null)
                    {
                        fieldNames.Insert(0, string.Empty);
                        cell.DropDownStrings = fieldNames.ToArray();
                    }
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.ResidueName &&
                         model is SurfaceOrganicMatter)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    string[] fieldNames = GetResidueNames();
                    if (fieldNames != null)
                    {
                        cell.DropDownStrings = fieldNames;
                    }
                }
                else if (properties[i].Display != null &&
                         (properties[i].Display.Type == DisplayType.CLEMResourceName))
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    List <string> fieldNames = new List <string>();
                    fieldNames.AddRange(this.GetCLEMResourceNames(this.properties[i].Display.CLEMResourceNameResourceGroups));

                    // add any extras elements provided to the list.
                    if (this.properties[i].Display.CLEMExtraEntries != null)
                    {
                        fieldNames.AddRange(this.properties[i].Display.CLEMExtraEntries);
                    }

                    if (fieldNames.Count != 0)
                    {
                        cell.DropDownStrings = fieldNames.ToArray();
                    }
                }
                else if (properties[i].Display != null &&
                         (properties[i].Display.Type == DisplayType.CLEMCropFileName))
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    List <string> fieldNames = new List <string>();
                    Simulation    clemParent = Apsim.Parent(this.model, typeof(Simulation)) as Simulation;
                    // get crop file names
                    fieldNames.AddRange(Apsim.ChildrenRecursively(clemParent, typeof(FileCrop)).Select(a => a.Name).ToList());
                    fieldNames.AddRange(Apsim.ChildrenRecursively(clemParent, typeof(FileSQLiteCrop)).Select(a => a.Name).ToList());
                    if (fieldNames.Count != 0)
                    {
                        cell.DropDownStrings = fieldNames.ToArray();
                    }
                }
                else if (properties[i].Display != null &&
                         (properties[i].Display.Type == DisplayType.CLEMGraspFileName))
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    List <string> fieldNames = new List <string>();
                    Simulation    clemParent = Apsim.Parent(this.model, typeof(Simulation)) as Simulation;
                    // get GRASP file names
                    fieldNames.AddRange(Apsim.ChildrenRecursively(clemParent, typeof(FileGRASP)).Select(a => a.Name).ToList());
                    fieldNames.AddRange(Apsim.ChildrenRecursively(clemParent, typeof(FileSQLiteGRASP)).Select(a => a.Name).ToList());
                    if (fieldNames.Count != 0)
                    {
                        cell.DropDownStrings = fieldNames.ToArray();
                    }
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.Model)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;

                    string[] modelNames = GetModelNames(properties[i].Display.ModelType);
                    if (modelNames != null)
                    {
                        cell.DropDownStrings = modelNames;
                    }
                }
                else
                {
                    object cellValue = properties[i].ValueWithArrayHandling;
                    if (cellValue is DateTime)
                    {
                        cell.EditorType = EditorTypeEnum.DateTime;
                    }
                    else if (cellValue is bool)
                    {
                        cell.EditorType = EditorTypeEnum.Boolean;
                    }
                    else if (cellValue.GetType().IsEnum)
                    {
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = VariableProperty.EnumToStrings(cellValue);
                        Enum cellValueAsEnum = cellValue as Enum;
                        if (cellValueAsEnum != null)
                        {
                            cell.Value = VariableProperty.GetEnumDescription(cellValueAsEnum);
                        }
                    }
                    else if (cellValue.GetType() == typeof(IPlant))
                    {
                        cell.EditorType = EditorTypeEnum.DropDown;
                        List <string> cropNames = new List <string>();
                        foreach (Model crop in Apsim.FindAll(model, typeof(IPlant)))
                        {
                            cropNames.Add(crop.Name);
                        }

                        cell.DropDownStrings = cropNames.ToArray();
                    }
                    else if (properties[i].DataType == typeof(IPlant))
                    {
                        List <string> plantNames = Apsim.FindAll(model, typeof(IPlant)).Select(m => m.Name).ToList();
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = plantNames.ToArray();
                    }
                    else if (!string.IsNullOrWhiteSpace(properties[i].Display?.Values))
                    {
                        explorerPresenter.ApsimXFile.Links.Resolve(model, allLinks: true, throwOnFail: false);
                        MethodInfo method = model.GetType().GetMethod(properties[i].Display.Values);
                        string[]   values = ((IEnumerable <object>)method.Invoke(model, null))?.Select(v => v?.ToString())?.ToArray();
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = values;
                    }
                    else
                    {
                        cell.EditorType = EditorTypeEnum.TextBox;
                    }
                }
                cell.IsRowReadonly = !IsPropertyEnabled(i);
            }

            IGridColumn descriptionColumn = grid.GetColumn(0);

            descriptionColumn.Width    = -1;
            descriptionColumn.ReadOnly = true;

            IGridColumn valueColumn = grid.GetColumn(1);

            valueColumn.Width = -1;
        }
Example #6
0
        /// <summary>
        /// Find all properties from the model and fill this.properties.
        /// </summary>
        /// <param name="model">The mode object</param>
        protected virtual void FindAllProperties(IModel model)
        {
            this.model = model;
            bool filterByCategory    = !((this.CategoryFilter == "") || (this.CategoryFilter == null));
            bool filterBySubcategory = !((this.SubcategoryFilter == "") || (this.SubcategoryFilter == null));

            if (this.model != null)
            {
                var orderedMembers = GetMembers(model);
                properties.Clear();
                foreach (MemberInfo member in orderedMembers)
                {
                    IVariable property = null;
                    if (member is PropertyInfo)
                    {
                        property = new VariableProperty(this.model, member as PropertyInfo);
                    }
                    else if (member is FieldInfo)
                    {
                        property = new VariableField(this.model, member as FieldInfo);
                    }

                    if (property != null && property.Description != null && property.Writable)
                    {
                        // Only allow lists that are double[], int[], string[] or DateTime[]
                        bool includeProperty = true;
                        if (property.DataType.GetInterface("IList") != null)
                        {
                            includeProperty = true;
                        }

                        if (Attribute.IsDefined(member, typeof(SeparatorAttribute)))
                        {
                            SeparatorAttribute[] separators = Attribute.GetCustomAttributes(member, typeof(SeparatorAttribute)) as SeparatorAttribute[];
                            foreach (SeparatorAttribute separator in separators)
                            {
                                properties.Add(new VariableObject(separator.ToString()));  // use a VariableObject for separators
                            }
                        }

                        //If the above conditions have been met and,
                        //If a CategoryFilter has been specified.
                        //filter only those properties with a [Catagory] attribute that matches the filter.

                        if (includeProperty && filterByCategory)
                        {
                            bool hasCategory = Attribute.IsDefined(member, typeof(CategoryAttribute), false);
                            if (hasCategory)
                            {
                                CategoryAttribute catAtt = (CategoryAttribute)Attribute.GetCustomAttribute(member, typeof(CategoryAttribute));
                                if (catAtt.Category == this.CategoryFilter)
                                {
                                    if (filterBySubcategory)
                                    {
                                        //the catAtt.Subcategory is by default given a value of
                                        //"Unspecified" if the Subcategory is not assigned in the Category Attribute.
                                        //so this line below will also handle "Unspecified" subcategories.
                                        includeProperty = (catAtt.Subcategory == this.SubcategoryFilter);
                                    }
                                    else
                                    {
                                        includeProperty = true;
                                    }
                                }
                                else
                                {
                                    includeProperty = false;
                                }
                            }
                            else
                            {
                                //if we are filtering on "Unspecified" category then there is no Category Attribute
                                // just a Description Attribute on the property in the model.
                                //So we still may need to include it in this case.
                                if (this.CategoryFilter == "Unspecified")
                                {
                                    includeProperty = true;
                                }
                                else
                                {
                                    includeProperty = false;
                                }
                            }
                        }

                        if (includeProperty)
                        {
                            properties.Add(property);
                        }

                        if (property.DataType == typeof(DataTable))
                        {
                            grid.DataSource = property.Value as DataTable;
                        }
                    }
                }
            }
        }
Example #7
0
        protected override void DrawVariableSpecificInspector()
        {
            SerializedProperty defaultValueProperty = VariableProperty.FindPropertyRelative("DefaultValue");

            EditorGUILayout.PropertyField(defaultValueProperty);
        }
Example #8
0
 set => SetValue(VariableProperty, value);
 /// <summary>
 /// Set the value of the specified property
 /// </summary>
 /// <param name="property">The property to set the value of</param>
 /// <param name="value">The value to set the property to</param>
 private void SetPropertyValue(Model childmodel, VariableProperty property, object value)
 {
     Commands.ChangeProperty cmd = new Commands.ChangeProperty(childmodel, property.Name, value);
     this.explorerPresenter.CommandHistory.Add(cmd, true);
 }
Example #10
0
        /// <summary>
        /// Format the grid.
        /// </summary>
        protected virtual void FormatGrid()
        {
            for (int i = 0; i < properties.Count; i++)
            {
                IGridCell cell = grid.GetCell(1, i);

                if (properties[i] is VariableObject)
                {
                    cell.EditorType = EditorTypeEnum.TextBox;

                    grid.SetRowAsSeparator(i, true);
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.TableName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    if (storage == null)
                    {
                        storage = model.FindInScope <IDataStore>();
                    }
                    cell.DropDownStrings = storage.Reader.TableNames.ToArray();
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.CultivarName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    IPlant crop;
                    if (properties[i].Display.PlantName != null)
                    {
                        crop = model.FindInScope <IPlant>(properties[i].Display.PlantName);
                    }
                    else
                    {
                        crop = GetCrop(properties);
                    }
                    if (crop != null)
                    {
                        cell.DropDownStrings = PropertyPresenterHelpers.GetCultivarNames(crop);
                    }
                }

                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.LifeCycleName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    Zone zone = model.FindInScope <Zone>();
                    if (zone != null)
                    {
                        cell.DropDownStrings = PropertyPresenterHelpers.GetLifeCycleNames(zone);
                    }
                }

                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.LifePhaseName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    LifeCycle lifeCycle = GetLifeCycle(properties);
                    if (lifeCycle != null)
                    {
                        cell.DropDownStrings = PropertyPresenterHelpers.GetPhaseNames(lifeCycle);
                    }
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.FileName)
                {
                    cell.EditorType = EditorTypeEnum.Button;
                }
                else if (properties[i].Display != null && properties[i].Display.Type == DisplayType.FileNames)
                {
                    cell.EditorType = EditorTypeEnum.MultiFiles;
                }
                else if (properties[i].Display != null && properties[i].Display.Type == DisplayType.DirectoryName)
                {
                    cell.EditorType = EditorTypeEnum.DirectoryChooser;
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.FieldName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    List <string> fieldNames = GetFieldNames();
                    if (fieldNames != null)
                    {
                        fieldNames.Insert(0, string.Empty);
                        cell.DropDownStrings = fieldNames.ToArray();
                    }
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.ResidueName &&
                         model is SurfaceOrganicMatter)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    string[] fieldNames = GetResidueNames();
                    if (fieldNames != null)
                    {
                        cell.DropDownStrings = fieldNames;
                    }
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.Model)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;

                    string[] modelNames = GetModelNames(properties[i].Display.ModelType);
                    if (modelNames != null)
                    {
                        cell.DropDownStrings = modelNames;
                    }
                }
                else
                {
                    object cellValue = properties[i].ValueWithArrayHandling;
                    if (cellValue is DateTime)
                    {
                        cell.EditorType = EditorTypeEnum.DateTime;
                    }
                    else if (cellValue is bool)
                    {
                        cell.EditorType = EditorTypeEnum.Boolean;
                    }
                    else if (cellValue.GetType().IsEnum)
                    {
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = VariableProperty.EnumToStrings(cellValue);
                        Enum cellValueAsEnum = cellValue as Enum;
                        if (cellValueAsEnum != null)
                        {
                            cell.Value = VariableProperty.GetEnumDescription(cellValueAsEnum);
                        }
                    }
                    else if (cellValue.GetType() == typeof(IPlant))
                    {
                        cell.EditorType = EditorTypeEnum.DropDown;
                        List <string> cropNames = new List <string>();
                        foreach (Model crop in model.FindAllInScope <IPlant>())
                        {
                            cropNames.Add(crop.Name);
                        }

                        cell.DropDownStrings = cropNames.ToArray();
                    }
                    else if (properties[i].DataType == typeof(IPlant))
                    {
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = model.FindAllInScope <IPlant>().OfType <IModel>().Select(m => m.Name).ToArray();
                    }
                    else if (!string.IsNullOrWhiteSpace(properties[i].Display?.Values))
                    {
                        explorerPresenter.ApsimXFile.Links.Resolve(model, allLinks: true, throwOnFail: false);
                        BindingFlags flags  = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy;
                        MethodInfo   method = model.GetType().GetMethod(properties[i].Display.Values, flags);
                        string[]     values = ((IEnumerable <object>)method.Invoke(model, properties[i].Display.ValuesArgs))?.Select(v => v?.ToString())?.ToArray();
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = values;
                    }
                    else
                    {
                        cell.EditorType = EditorTypeEnum.TextBox;
                    }
                }
                cell.IsRowReadonly = !IsPropertyEnabled(i);
            }

            IGridColumn descriptionColumn = grid.GetColumn(0);

            descriptionColumn.Width    = -1;
            descriptionColumn.ReadOnly = true;

            IGridColumn valueColumn = grid.GetColumn(1);

            valueColumn.Width = -1;
        }
Example #11
0
        /// <summary>
        /// Instantiates a Property object by reading metadata about
        /// the given property.
        /// </summary>
        /// <param name="obj">The object reference used to fetch the current value of the property.</param>
        /// <param name="metadata">Property metadata.</param>
        public Property(object obj, PropertyInfo metadata)
        {
            IModel model = obj as IModel;

            ID   = Guid.NewGuid();
            Name = metadata.GetCustomAttribute <DescriptionAttribute>()?.ToString();
            if (string.IsNullOrEmpty(Name))
            {
                Name = metadata.Name;
            }

            Tooltip    = metadata.GetCustomAttribute <TooltipAttribute>()?.Tooltip;
            Separators = metadata.GetCustomAttributes <SeparatorAttribute>()?.Select(s => s.ToString())?.ToList();

            Value = metadata.GetValue(obj);
            if (metadata.PropertyType == typeof(DateTime) || (metadata.PropertyType == typeof(DateTime?) && Value != null))
            {
                // Note: ToShortDateString() uses the current culture, which is what we want in this case.
                Value = ((DateTime)Value).ToShortDateString();
            }
            // ?else if property type isn't a struct?
            else if (Value != null && typeof(IModel).IsAssignableFrom(Value.GetType()))
            {
                Value = ((IModel)Value).Name;
            }
            else if (metadata.PropertyType.IsEnum)
            {
                Value = VariableProperty.GetEnumDescription((Enum)Enum.Parse(metadata.PropertyType, Value?.ToString()));
            }
            else if (metadata.PropertyType != typeof(bool) && metadata.PropertyType != typeof(System.Drawing.Color))
            {
                Value = ReflectionUtilities.ObjectToString(Value, CultureInfo.CurrentCulture);
            }

            // fixme - need to fix this unmaintainable mess brought across from the old PropertyPresenter
            DisplayAttribute attrib      = metadata.GetCustomAttribute <DisplayAttribute>();
            DisplayType      displayType = attrib?.Type ?? DisplayType.None;

            // For compatibility with the old PropertyPresenter, assume a default of
            // DisplayType.DropDown if the Values property is specified.
            if (displayType == DisplayType.None && !string.IsNullOrEmpty(attrib?.Values))
            {
                displayType = DisplayType.DropDown;
            }

            switch (displayType)
            {
            case DisplayType.None:
                if (metadata.PropertyType.IsEnum)
                {
                    // Enums use dropdown
                    DropDownOptions = Enum.GetValues(metadata.PropertyType).Cast <Enum>()
                                      .Select(e => VariableProperty.GetEnumDescription(e))
                                      .ToArray();
                    DisplayMethod = PropertyType.DropDown;
                }
                else if (typeof(IModel).IsAssignableFrom(metadata.PropertyType))
                {
                    // Model selector - use a dropdown containing names of all models in scope.
                    DisplayMethod   = PropertyType.DropDown;
                    DropDownOptions = model.FindAllInScope()
                                      .Where(m => metadata.PropertyType.IsAssignableFrom(m.GetType()))
                                      .Select(m => m.Name)
                                      .ToArray();
                }
                else if (metadata.PropertyType == typeof(bool))
                {
                    DisplayMethod = PropertyType.Checkbox;
                }
                else if (metadata.PropertyType == typeof(System.Drawing.Color))
                {
                    DisplayMethod = PropertyType.Colour;
                }
                else
                {
                    DisplayMethod = PropertyType.SingleLineText;
                }
                break;

            case DisplayType.FileName:
                DisplayMethod = PropertyType.File;
                break;

            case DisplayType.FileNames:
                DisplayMethod = PropertyType.Files;
                break;

            case DisplayType.DirectoryName:
                DisplayMethod = PropertyType.Directory;
                break;

            case DisplayType.DropDown:
                string methodName = metadata.GetCustomAttribute <DisplayAttribute>().Values;
                if (methodName == null)
                {
                    throw new ArgumentNullException($"When using DisplayType.DropDown, the Values property must be specified.");
                }
                BindingFlags flags  = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy;
                MethodInfo   method = model.GetType().GetMethod(methodName, flags);

                object[] args = metadata.GetCustomAttribute <DisplayAttribute>().ValuesArgs;

                // Attempt to resolve links - populating the dropdown may
                // require access to linked models.
                Simulations sims = model.FindAncestor <Simulations>();
                if (sims != null)
                {
                    sims.Links.Resolve(model, allLinks: true, throwOnFail: false);
                }

                DropDownOptions = ((IEnumerable <object>)method.Invoke(model, args))?.Select(v => v?.ToString())?.ToArray();
                DisplayMethod   = PropertyType.DropDown;
                break;

            case DisplayType.CultivarName:
                DisplayMethod = PropertyType.DropDown;
                IPlant       plant         = null;
                PropertyInfo plantProperty = model.GetType().GetProperties().FirstOrDefault(p => typeof(IPlant).IsAssignableFrom(p.PropertyType));
                if (plantProperty != null)
                {
                    plant = plantProperty.GetValue(model) as IPlant;
                }
                else
                {
                    plant = model.FindInScope <IPlant>();
                }
                if (plant != null)
                {
                    DropDownOptions = PropertyPresenterHelpers.GetCultivarNames(plant);
                }
                break;

            case DisplayType.TableName:
                DisplayMethod   = PropertyType.DropDown;
                DropDownOptions = model.FindInScope <IDataStore>()?.Reader?.TableNames?.ToArray();
                break;

            case DisplayType.FieldName:
                DisplayMethod = PropertyType.DropDown;
                IDataStore   storage           = model.FindInScope <IDataStore>();
                PropertyInfo tableNameProperty = model.GetType().GetProperties().FirstOrDefault(p => p.GetCustomAttribute <DisplayAttribute>()?.Type == DisplayType.TableName);
                string       tableName         = tableNameProperty?.GetValue(model) as string;
                if (storage != null && storage.Reader.TableNames.Contains(tableName))
                {
                    DropDownOptions = storage.Reader.ColumnNames(tableName).ToArray();
                }
                break;

            case DisplayType.LifeCycleName:
                DisplayMethod = PropertyType.DropDown;
                Zone zone = model.FindInScope <Zone>();
                if (zone != null)
                {
                    DropDownOptions = PropertyPresenterHelpers.GetLifeCycleNames(zone);
                }
                break;

            case DisplayType.LifePhaseName:
                DisplayMethod = PropertyType.DropDown;
                LifeCycle lifeCycle = null;
                if (attrib.LifeCycleName != null)
                {
                    lifeCycle = model.FindInScope <LifeCycle>(attrib.LifeCycleName);
                }
                else
                {
                    foreach (PropertyInfo property in model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
                    {
                        if (property.PropertyType == typeof(string))
                        {
                            string    value = property.GetValue(model) as string;
                            LifeCycle match = model.FindInScope <LifeCycle>(value);
                            if (match != null)
                            {
                                lifeCycle = match;
                                break;
                            }
                        }
                    }
                }
                if (lifeCycle != null)
                {
                    DropDownOptions = PropertyPresenterHelpers.GetPhaseNames(lifeCycle).ToArray();
                }
                break;

            case DisplayType.Model:
                DisplayMethod   = PropertyType.DropDown;
                DropDownOptions = model.FindAllInScope().Where(m => metadata.PropertyType.IsAssignableFrom(m.GetType()))
                                  .Select(m => m.Name)
                                  .ToArray();
                break;

            case DisplayType.ResidueName:
                if (model is SurfaceOrganicMatter surfaceOM)
                {
                    DisplayMethod   = PropertyType.DropDown;
                    DropDownOptions = surfaceOM.ResidueTypeNames().ToArray();
                    break;
                }
                else
                {
                    throw new NotImplementedException($"Display type {displayType} is only supported on models of type {typeof(SurfaceOrganicMatter).Name}, but model is of type {model.GetType().Name}.");
                }

            case DisplayType.MultiLineText:
                DisplayMethod = PropertyType.MultiLineText;
                if (Value is IEnumerable enumerable && metadata.PropertyType != typeof(string))
                {
                    Value = string.Join(Environment.NewLine, ((IEnumerable)metadata.GetValue(obj)).ToGenericEnumerable());
                }
                break;

            // Should never happen - presenter should handle this(?)
            //case DisplayType.SubModel:
            default:
                throw new NotImplementedException($"Unknown display type {displayType}");
            }

            // If the list of dropdown options doesn't contain the actual value of the
            // property, add that value to the list of valid options.
            if (DisplayMethod == PropertyType.DropDown && Value != null)
            {
                if (DropDownOptions == null)
                {
                    DropDownOptions = new string[1] {
                        Value.ToString()
                    }
                }
                ;
                else if (!DropDownOptions.Contains(Value.ToString()))
                {
                    List <string> values = DropDownOptions.ToList();
                    values.Add(Value.ToString());
                    DropDownOptions = values.ToArray();
                }
            }
        }
Example #12
0
        /// <summary>
        /// Format the grid.
        /// </summary>
        private void FormatGrid()
        {
            for (int i = 0; i < this.properties.Count; i++)
            {
                IGridCell cell = this.grid.GetCell(1, i);

                if (this.properties[i] is VariableObject)
                {
                    cell.EditorType = EditorTypeEnum.TextBox;

                    grid.SetRowAsSeparator(i, true);
                }
                else if (this.properties[i].Display != null &&
                         this.properties[i].Display.Type == DisplayType.TableName)
                {
                    cell.EditorType      = EditorTypeEnum.DropDown;
                    cell.DropDownStrings = this.storage.TableNames.ToArray();
                }
                else if (this.properties[i].Display != null &&
                         this.properties[i].Display.Type == DisplayType.CultivarName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    IPlant crop = this.GetCrop(this.properties);
                    if (crop != null)
                    {
                        cell.DropDownStrings = this.GetCultivarNames(crop);
                    }
                }
                else if (this.properties[i].Display != null &&
                         this.properties[i].Display.Type == DisplayType.FileName)
                {
                    cell.EditorType = EditorTypeEnum.Button;
                }
                else if (this.properties[i].Display != null &&
                         this.properties[i].Display.Type == DisplayType.FieldName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    string[] fieldNames = this.GetFieldNames();
                    if (fieldNames != null)
                    {
                        cell.DropDownStrings = fieldNames;
                    }
                }
                else if (this.properties[i].Display != null &&
                         this.properties[i].Display.Type == DisplayType.ResidueName &&
                         this.model is Models.Surface.SurfaceOrganicMatter)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    string[] fieldNames = GetResidueNames();
                    if (fieldNames != null)
                    {
                        cell.DropDownStrings = fieldNames;
                    }
                }
                else if (this.properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.Model)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;

                    string[] modelNames = GetModelNames(properties[i].Display.ModelType);
                    if (modelNames != null)
                    {
                        cell.DropDownStrings = modelNames;
                    }
                }
                else
                {
                    object cellValue = this.properties[i].ValueWithArrayHandling;
                    if (cellValue is DateTime)
                    {
                        cell.EditorType = EditorTypeEnum.DateTime;
                    }
                    else if (cellValue is bool)
                    {
                        cell.EditorType = EditorTypeEnum.Boolean;
                    }
                    else if (cellValue.GetType().IsEnum)
                    {
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = VariableProperty.EnumToStrings(cellValue);
                        Enum cellValueAsEnum = cellValue as Enum;
                        if (cellValueAsEnum != null)
                        {
                            cell.Value = VariableProperty.GetEnumDescription(cellValueAsEnum);
                        }
                    }
                    else if (cellValue.GetType() == typeof(IPlant))
                    {
                        cell.EditorType = EditorTypeEnum.DropDown;
                        List <string> cropNames = new List <string>();
                        foreach (Model crop in Apsim.FindAll(this.model, typeof(IPlant)))
                        {
                            cropNames.Add(crop.Name);
                        }

                        cell.DropDownStrings = cropNames.ToArray();
                    }
                    else if (this.properties[i].DataType == typeof(IPlant))
                    {
                        List <string> plantNames = Apsim.FindAll(this.model, typeof(IPlant)).Select(m => m.Name).ToList();
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = plantNames.ToArray();
                    }
                    else
                    {
                        cell.EditorType = EditorTypeEnum.TextBox;
                    }
                }
            }

            IGridColumn descriptionColumn = this.grid.GetColumn(0);

            descriptionColumn.Width    = -1;
            descriptionColumn.ReadOnly = true;

            IGridColumn valueColumn = this.grid.GetColumn(1);

            valueColumn.Width = -1;
        }
Example #13
0
        /// <summary>
        /// User has changed the value of a cell. Validate the change
        /// apply the change.
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="args">Event parameters</param>
        private void OnCellsChanged(object sender, GridCellsChangedArgs args)
        {
            List <ChangeProperty.Property> changes = new List <ChangeProperty.Property>();

            foreach (var column in args.ChangedCells.GroupBy(c => c.ColIndex))
            {
                VariableProperty property = properties[column.Key];
                if (property == null || property.IsReadOnly)
                {
                    continue;
                }

                // Get a deep copy of the property value.
                Array newArray = property.Value as Array;
                if (newArray == null && property.Value != null)
                {
                    continue;
                }
                newArray = Clone(newArray, property.DataType.GetElementType());

                // It's possible to change multiple values in the same column
                // simultaneously via multi-selection. If we just add a change
                // property command for each individual change, later changes
                // would overwrite the earlier changes. We need to merge all
                // changes to a single column into a single command then move
                // onto the next column.
                foreach (GridCellChangedArgs change in column)
                {
                    if (change.NewValue == change.OldValue)
                    {
                        continue; // silently fail
                    }
                    if (change.RowIndex >= newArray.Length && string.IsNullOrEmpty(change.NewValue))
                    {
                        continue;
                    }

                    // If the user has entered data into a new row, we will need to
                    // resize all of the array properties.
                    changes.AddRange(CheckArrayLengths(change));

                    // Need to convert user input to a string using the current
                    // culture.
                    object element = ReflectionUtilities.StringToObject(property.DataType.GetElementType(), change.NewValue, CultureInfo.CurrentCulture);
                    if (newArray.Length <= change.RowIndex)
                    {
                        Resize(ref newArray, change.RowIndex + 1);
                    }

                    newArray.SetValue(element, change.RowIndex);
                }
                changes.Add(new ChangeProperty.Property(property.Object, property.Name, newArray));
            }

            // Apply all changes to the model in a single undoable command.
            SetPropertyValue(new ChangeProperty(changes));

            // Update the value shown in the grid. This needs to happen after
            // we have applied changes to the model for obvious reasons.
            foreach (GridCellChangedArgs cell in args.ChangedCells)
            {
                // Add new rows to the view's grid if necessary.
                while (grid.RowCount <= cell.RowIndex + 1)
                {
                    grid.RowCount++;
                }
                grid.DataSource.Rows[cell.RowIndex][cell.ColIndex] = GetCellValue(cell.RowIndex, cell.ColIndex);
            }

            // If the user deleted an entire row, do a full refresh of the
            // grid. Otherwise, only refresh read-only columns (PAWC).
            if (RemoveEmptyRows())
            {
                PopulateGrid(model);
            }
            else
            {
                UpdateReadOnlyProperties();
            }
        }
        /// <summary>
        /// Format the grid based on the data in the specified table.
        /// </summary>
        /// <param name="table">The table to use to format the grid.</param>
        private void FormatGrid(DataTable table)
        {
            Color[] cropColors          = { Color.FromArgb(173, 221, 142), Color.FromArgb(247, 252, 185) };
            Color[] predictedCropColors = { Color.FromArgb(233, 191, 255), Color.FromArgb(244, 226, 255) };

            int cropIndex          = 0;
            int predictedCropIndex = 0;

            Color foregroundColour = Color.Black;
            Color backgroundColour = Color.White;

            for (int col = 0; col < this.propertiesInGrid.Count; col++)
            {
                VariableProperty property = this.propertiesInGrid[col];

                string columnName = property.Description;

                // crop colours
                if (property.CropName != null)
                {
                    if (property.Metadata.Contains("Estimated"))
                    {
                        backgroundColour = predictedCropColors[predictedCropIndex];
                        foregroundColour = Color.Gray;
                        if (columnName.Contains("XF"))
                        {
                            predictedCropIndex++;
                        }

                        if (predictedCropIndex >= predictedCropColors.Length)
                        {
                            predictedCropIndex = 0;
                        }
                    }
                    else
                    {
                        backgroundColour = cropColors[cropIndex];
                        if (columnName.Contains("XF"))
                        {
                            cropIndex++;
                        }

                        if (cropIndex >= cropColors.Length)
                        {
                            cropIndex = 0;
                        }
                    }
                }

                // tool tips
                string[] toolTips = null;
                if (property.IsReadOnly)
                {
                    foregroundColour = Color.Gray;
                    toolTips         = StringUtilities.CreateStringArray("Calculated", this.view.ProfileGrid.RowCount);
                }
                else
                {
                    foregroundColour = Color.Black;
                    toolTips         = property.Metadata;
                }

                string format = property.Format;
                if (format == null || format == string.Empty)
                {
                    format = "N3";
                }

                IGridColumn gridColumn = this.view.ProfileGrid.GetColumn(col);
                gridColumn.Format           = format;
                gridColumn.BackgroundColour = backgroundColour;
                gridColumn.ForegroundColour = foregroundColour;
                gridColumn.ReadOnly         = property.IsReadOnly;
                for (int rowIndex = 0; rowIndex < toolTips.Length; rowIndex++)
                {
                    IGridCell cell = this.view.ProfileGrid.GetCell(col, rowIndex);
                    cell.ToolTip = toolTips[rowIndex];
                }

                // colour the column headers of total columns.
                try
                {
                    if (!double.IsNaN(property.Total))
                    {
                        gridColumn.HeaderForegroundColour = Color.Red;
                    }
                }
                catch (Exception err)
                {
                    explorerPresenter.MainPresenter.ShowError(err);
                }
            }

            this.view.ProfileGrid.RowCount = 100;
        }
        /// <summary>
        /// Format the grid.
        /// </summary>
        private void FormatGrid()
        {
            for (int i = 0; i < properties.Count; i++)
            {
                IGridCell cell = grid.GetCell(1, i);

                if (properties[i] is VariableObject)
                {
                    cell.EditorType = EditorTypeEnum.TextBox;

                    grid.SetRowAsSeparator(i, true);
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.TableName)
                {
                    cell.EditorType      = EditorTypeEnum.DropDown;
                    cell.DropDownStrings = storage.TableNames.ToArray();
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.CultivarName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    IPlant crop = GetCrop(properties);
                    if (crop != null)
                    {
                        cell.DropDownStrings = GetCultivarNames(crop);
                    }
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.FileName)
                {
                    cell.EditorType = EditorTypeEnum.Button;
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.FieldName)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    List <string> fieldNames = GetFieldNames();
                    if (fieldNames != null)
                    {
                        fieldNames.Insert(0, string.Empty);
                        cell.DropDownStrings = fieldNames.ToArray();
                    }
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.ResidueName &&
                         model is SurfaceOrganicMatter)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    string[] fieldNames = GetResidueNames();
                    if (fieldNames != null)
                    {
                        cell.DropDownStrings = fieldNames;
                    }
                }
                else if (properties[i].Display != null &&
                         (properties[i].Display.Type == DisplayType.CLEMResourceName))
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    List <string> fieldNames = new List <string>();
                    fieldNames.AddRange(this.GetCLEMResourceNames(this.properties[i].Display.CLEMResourceNameResourceGroups));

                    // add any extras elements provided to the list.
                    if (this.properties[i].Display.CLEMExtraEntries != null)
                    {
                        fieldNames.AddRange(this.properties[i].Display.CLEMExtraEntries);
                    }

                    if (fieldNames.Count != 0)
                    {
                        cell.DropDownStrings = fieldNames.ToArray();
                    }
                }
                else if (properties[i].Display != null &&
                         (properties[i].Display.Type == DisplayType.CLEMCropFileName))
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    List <string> fieldNames = new List <string>();
                    Simulation    clemParent = Apsim.Parent(this.model, typeof(Simulation)) as Simulation;
                    // get crop file names
                    fieldNames.AddRange(Apsim.ChildrenRecursively(clemParent, typeof(FileCrop)).Select(a => a.Name).ToList());
                    if (fieldNames.Count != 0)
                    {
                        cell.DropDownStrings = fieldNames.ToArray();
                    }
                }
                else if (properties[i].Display != null &&
                         (properties[i].Display.Type == DisplayType.CLEMGraspFileName))
                {
                    cell.EditorType = EditorTypeEnum.DropDown;
                    List <string> fieldNames = new List <string>();
                    Simulation    clemParent = Apsim.Parent(this.model, typeof(Simulation)) as Simulation;
                    // get GRASP file names
                    fieldNames.AddRange(Apsim.Children(clemParent, typeof(FileGRASP)).Select(a => a.Name).ToList());
                    fieldNames.AddRange(Apsim.Children(clemParent, typeof(FileSQLiteGRASP)).Select(a => a.Name).ToList());
                    if (fieldNames.Count != 0)
                    {
                        cell.DropDownStrings = fieldNames.ToArray();
                    }
                }
                else if (properties[i].Display != null &&
                         properties[i].Display.Type == DisplayType.Model)
                {
                    cell.EditorType = EditorTypeEnum.DropDown;

                    string[] modelNames = GetModelNames(properties[i].Display.ModelType);
                    if (modelNames != null)
                    {
                        cell.DropDownStrings = modelNames;
                    }
                }
                else
                {
                    object cellValue = properties[i].ValueWithArrayHandling;
                    if (cellValue is DateTime)
                    {
                        cell.EditorType = EditorTypeEnum.DateTime;
                    }
                    else if (cellValue is bool)
                    {
                        cell.EditorType = EditorTypeEnum.Boolean;
                    }
                    else if (cellValue.GetType().IsEnum)
                    {
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = VariableProperty.EnumToStrings(cellValue);
                        Enum cellValueAsEnum = cellValue as Enum;
                        if (cellValueAsEnum != null)
                        {
                            cell.Value = VariableProperty.GetEnumDescription(cellValueAsEnum);
                        }
                    }
                    else if (cellValue.GetType() == typeof(IPlant))
                    {
                        cell.EditorType = EditorTypeEnum.DropDown;
                        List <string> cropNames = new List <string>();
                        foreach (Model crop in Apsim.FindAll(model, typeof(IPlant)))
                        {
                            cropNames.Add(crop.Name);
                        }

                        cell.DropDownStrings = cropNames.ToArray();
                    }
                    else if (properties[i].DataType == typeof(IPlant))
                    {
                        List <string> plantNames = Apsim.FindAll(model, typeof(IPlant)).Select(m => m.Name).ToList();
                        cell.EditorType      = EditorTypeEnum.DropDown;
                        cell.DropDownStrings = plantNames.ToArray();
                    }
                    else
                    {
                        cell.EditorType = EditorTypeEnum.TextBox;
                    }
                }
            }

            IGridColumn descriptionColumn = grid.GetColumn(0);

            descriptionColumn.Width    = -1;
            descriptionColumn.ReadOnly = true;

            IGridColumn valueColumn = grid.GetColumn(1);

            valueColumn.Width = -1;
        }
        /// <summary>
        /// Attach the model to the view.
        /// </summary>
        /// <param name="model">The underlying model we are to use</param>
        /// <param name="view">The underlying view we are to attach to</param>
        /// <param name="explorerPresenter">Our parent explorerPresenter</param>
        public void Attach(object model, object view, ExplorerPresenter explorerPresenter)
        {
            this.model = model as Model;
            this.view  = view as IProfileView;
            profileGrid.Attach(model, this.view.ProfileGrid, explorerPresenter);
            this.explorerPresenter = explorerPresenter;

            this.view.ShowView(false);

            // Setup the property presenter and view. Hide the view if there are no properties to show.
            this.propertyPresenter = new PropertyPresenter();
            this.propertyPresenter.Attach(this.model, this.view.PropertyGrid, this.explorerPresenter);

            // Create a list of profile (array) properties. Create a table from them and
            // hand the table to the profile grid.
            this.FindAllProperties(this.model);

            // Populate the grid
            this.PopulateGrid();

            // Populate the graph.
            this.graph = Utility.Graph.CreateGraphFromResource(model.GetType().Name + "Graph");

            if (this.graph == null)
            {
                this.view.ShowGraph(false);
            }
            else
            {
                this.parentForGraph = this.model.Parent as IModel;
                if (this.parentForGraph != null)
                {
                    this.parentForGraph.Children.Add(this.graph);
                    this.graph.Parent = this.parentForGraph;
                    this.view.ShowGraph(true);
                    int padding = (this.view as ProfileView).MainWidget.Allocation.Width / 2 / 2;
                    this.view.Graph.LeftRightPadding = padding;
                    this.graphPresenter = new GraphPresenter();
                    for (int col = 0; col < this.propertiesInGrid.Count; col++)
                    {
                        VariableProperty property   = this.propertiesInGrid[col];
                        string           columnName = property.Description;

                        // crop colours
                        if (property.CropName != null && columnName.Contains("LL"))
                        {
                            Series cropLLSeries = new Series();
                            cropLLSeries.Name         = columnName;
                            cropLLSeries.Colour       = ColourUtilities.ChooseColour(this.graph.Children.Count);
                            cropLLSeries.Line         = LineType.Solid;
                            cropLLSeries.Marker       = MarkerType.None;
                            cropLLSeries.Type         = SeriesType.Scatter;
                            cropLLSeries.ShowInLegend = true;
                            cropLLSeries.XAxis        = Axis.AxisType.Top;
                            cropLLSeries.YAxis        = Axis.AxisType.Left;
                            cropLLSeries.YFieldName   = "[Soil].DepthMidPoints";
                            cropLLSeries.XFieldName   = "[" + (property.Object as Model).Name + "]." + property.Name;
                            cropLLSeries.Parent       = this.graph;

                            this.graph.Children.Add(cropLLSeries);
                        }
                    }

                    this.graphPresenter.Attach(this.graph, this.view.Graph, this.explorerPresenter);
                }
            }

            // Trap the invoking of the ProfileGrid 'CellValueChanged' event so that
            // we can save the contents.
            this.view.ProfileGrid.CellsChanged += this.OnProfileGridCellValueChanged;

            // Trap the right click on column header so that we can potentially put
            // units on the context menu.
            this.view.ProfileGrid.GridColumnClicked += this.OnGridColumnClicked;

            // Trap the model changed event so that we can handle undo.
            this.explorerPresenter.CommandHistory.ModelChanged += this.OnModelChanged;

            this.view.ShowView(true);
        }
Example #17
0
        /// <summary>
        /// Instantiates a Property object by reading metadata about
        /// the given property.
        /// </summary>
        /// <param name="obj">The object reference used to fetch the current value of the property.</param>
        /// <param name="metadata">Property metadata.</param>
        public Property(object obj, PropertyInfo metadata)
        {
            IModel model = obj as IModel;

            ID   = Guid.NewGuid();
            Name = metadata.GetCustomAttribute <DescriptionAttribute>()?.ToString();
            if (string.IsNullOrEmpty(Name))
            {
                Name = metadata.Name;
            }

            Tooltip    = metadata.GetCustomAttribute <TooltipAttribute>()?.Tooltip;
            Separators = metadata.GetCustomAttributes <SeparatorAttribute>()?.Select(s => s.ToString())?.ToList();

            Value = metadata.GetValue(obj);
            if (metadata.PropertyType == typeof(DateTime) || (metadata.PropertyType == typeof(DateTime?) && Value != null))
            {
                // Note: ToShortDateString() uses the current culture, which is what we want in this case.
                Value = ((DateTime)Value).ToShortDateString();
            }
            // ?else if property type isn't a struct?
            else if (Value != null && typeof(IModel).IsAssignableFrom(Value.GetType()))
            {
                Value = ((IModel)Value).Name;
            }
            else if (metadata.PropertyType != typeof(bool) && metadata.PropertyType != typeof(System.Drawing.Color))
            {
                Value = ReflectionUtilities.ObjectToString(Value, CultureInfo.CurrentCulture);
            }

            // fixme - need to fix this unmaintainable mess brought across from the old PropertyPresenter
            DisplayAttribute attrib      = metadata.GetCustomAttribute <DisplayAttribute>();
            DisplayType      displayType = attrib?.Type ?? DisplayType.None;

            switch (displayType)
            {
            case DisplayType.None:
                if (metadata.PropertyType.IsEnum)
                {
                    // Enums use dropdown
                    DropDownOptions = Enum.GetValues(metadata.PropertyType).Cast <Enum>()
                                      .Select(e => VariableProperty.GetEnumDescription(e))
                                      .ToArray();
                    DisplayMethod = PropertyType.DropDown;
                }
                else if (typeof(IModel).IsAssignableFrom(metadata.PropertyType))
                {
                    // Model selector - use a dropdown containing names of all models in scope.
                    DisplayMethod   = PropertyType.DropDown;
                    DropDownOptions = model.FindAllInScope()
                                      .Where(m => metadata.PropertyType.IsAssignableFrom(m.GetType()))
                                      .Select(m => m.Name)
                                      .ToArray();
                }
                else if (metadata.PropertyType == typeof(bool))
                {
                    DisplayMethod = PropertyType.Checkbox;
                }
                else if (metadata.PropertyType == typeof(System.Drawing.Color))
                {
                    DisplayMethod = PropertyType.Colour;
                }
                else
                {
                    DisplayMethod = PropertyType.SingleLineText;
                }
                break;

            case DisplayType.FileName:
                DisplayMethod = PropertyType.File;
                break;

            case DisplayType.FileNames:
                DisplayMethod = PropertyType.Files;
                break;

            case DisplayType.DirectoryName:
                DisplayMethod = PropertyType.Directory;
                break;

            case DisplayType.DropDown:
                string     methodName = metadata.GetCustomAttribute <DisplayAttribute>().Values;
                MethodInfo method     = model.GetType().GetMethod(methodName);
                DropDownOptions = ((IEnumerable <object>)method.Invoke(model, null))?.Select(v => v?.ToString())?.ToArray();
                DisplayMethod   = PropertyType.DropDown;
                break;

            case DisplayType.CultivarName:
                DisplayMethod = PropertyType.DropDown;
                IPlant       plant         = null;
                PropertyInfo plantProperty = model.GetType().GetProperties().FirstOrDefault(p => typeof(IPlant).IsAssignableFrom(p.PropertyType));
                if (plantProperty != null)
                {
                    plant = plantProperty.GetValue(model) as IPlant;
                }
                else
                {
                    plant = model.FindInScope <IPlant>();
                }
                DropDownOptions = PropertyPresenterHelpers.GetCultivarNames(plant);
                break;

            case DisplayType.TableName:
                DisplayMethod   = PropertyType.DropDown;
                DropDownOptions = model.FindInScope <IDataStore>()?.Reader?.TableNames?.ToArray();
                break;

            case DisplayType.FieldName:
                DisplayMethod = PropertyType.DropDown;
                IDataStore   storage           = model.FindInScope <IDataStore>();
                PropertyInfo tableNameProperty = model.GetType().GetProperties().FirstOrDefault(p => p.GetCustomAttribute <DisplayAttribute>()?.Type == DisplayType.TableName);
                string       tableName         = tableNameProperty?.GetValue(model) as string;
                if (storage != null && storage.Reader.TableNames.Contains(tableName))
                {
                    DropDownOptions = storage.Reader.ColumnNames(tableName).ToArray();
                }
                break;

            case DisplayType.LifeCycleName:
                DisplayMethod = PropertyType.DropDown;
                Zone zone = model.FindInScope <Zone>();
                if (zone != null)
                {
                    DropDownOptions = PropertyPresenterHelpers.GetLifeCycleNames(zone);
                }
                break;

            case DisplayType.LifePhaseName:
                DisplayMethod = PropertyType.DropDown;
                LifeCycle lifeCycle = null;
                if (attrib.LifeCycleName != null)
                {
                    lifeCycle = model.FindInScope <LifeCycle>(attrib.LifeCycleName);
                }
                else
                {
                    foreach (PropertyInfo property in model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
                    {
                        if (property.PropertyType == typeof(string))
                        {
                            string    value = property.GetValue(model) as string;
                            LifeCycle match = model.FindInScope <LifeCycle>(value);
                            if (match != null)
                            {
                                lifeCycle = match;
                                break;
                            }
                        }
                    }
                }
                if (lifeCycle != null)
                {
                    DropDownOptions = PropertyPresenterHelpers.GetPhaseNames(lifeCycle).ToArray();
                }
                break;

            case DisplayType.Model:
                DisplayMethod   = PropertyType.DropDown;
                DropDownOptions = model.FindAllInScope().Where(m => metadata.PropertyType.IsAssignableFrom(m.GetType()))
                                  .Select(m => m.Name)
                                  .ToArray();
                break;

            case DisplayType.ResidueName:
                if (model is SurfaceOrganicMatter surfaceOM)
                {
                    DisplayMethod   = PropertyType.DropDown;
                    DropDownOptions = surfaceOM.ResidueTypeNames().ToArray();
                    break;
                }
                else
                {
                    throw new NotImplementedException($"Display type {displayType} is only supported on models of type {typeof(SurfaceOrganicMatter).Name}, but model is of type {model.GetType().Name}.");
                }

            // Should never happen - presenter should handle this(?)
            //case DisplayType.SubModel:
            default:
                throw new NotImplementedException($"Unknown display type {displayType}");
            }
        }