Range Selection
This topic illustrates how to adds the Range Select and Inline Range Select options to the OptionsForm in scripting.
Note that the Scripts panel provides tools that are only applicable to developers, consultants or power users familiar with scripting in C#.
RangeSelectionOption & InlineRangeSelectionOption
Copy
using System;
using System.Text;
using System.Windows.Forms;
using PrecisionMining.Spry;
using PrecisionMining.Spry.Data;
using PrecisionMining.Spry.Util.OptionsForm;
/// <summary>
/// Examples for the Inline Range Select option on the scripting Options Form.
///
/// An InlineRangeSelectOption lets the user pick a range from a table, or type an ad hoc
/// "inline" range as text (node paths, optionally inverted and/or filtered by an expression).
/// The option's Value is an ICompositeRange that combines both: its Mode says whether the
/// table range or the inline range is in effect.
/// </summary>
public partial class OptionsFormExamples
{
/// <summary>
/// A complete walkthrough of the InlineRangeSelectOption API.
/// </summary>
public static void InlineRangeSelectExample()
{
// The table whose ranges are offered for selection. Replace "Table Name" with a
// table from your project.
var table = Project.ActiveProject.Data.GetTable("Table Name");
if (table == null)
{
MessageBox.Show("Table not found - edit the script and set your table name.");
return;
}
var form = OptionsForm.Create("Inline Range Select Example");
// ---------------------------------------------------------------------------------
// Creating the option
// ---------------------------------------------------------------------------------
// AddInlineRangeSelect adds the option to the form. A table must be assigned before
// the option is used - either fluently with SetTable, or via the Table property.
var rangeOption = form.Options.AddInlineRangeSelect("Range")
.SetTable(table);
// An optional second argument adds a Deselect button to the popup so the user can
// clear the selected table range:
// var rangeOption = form.Options.AddInlineRangeSelect("Range", true).SetTable(table);
// The assigned table can be read back or changed at any time. Changing the table
// remaps the selected range to the same-named range on the new table where possible.
// rangeOption.Table = anotherTable;
// ---------------------------------------------------------------------------------
// Setting an initial value
// ---------------------------------------------------------------------------------
// The option's Value is never null. It is a live ICompositeRange owned by the
// option: read or change its properties and the editor updates immediately.
// 1. Select the generated "< All >" table range:
rangeOption.AllTableRangeSelected = true;
// 2. Or select a specific range from the table by name:
// rangeOption.Value.TableRange = table.Ranges.GetRange("My Range");
// 3. Or start on the inline range. Set gives full control in one call:
// (mode, table range, inline text, invert inline range, filter expression)
// rangeOption.Value.Set(RangeMode.Inline, null, "*", false, "");
// inlineRangeSelect.SetInlineRangeToAll(true,true) is shorthand for setting the inline text to the match-everything wildcard "*"
// AllInlineRangeSelected = true is shorthand for setting the inline text to the
// match-everything wildcard "*":
// Assigning another ICompositeRange to Value copies its settings into the option
// (the option keeps its own instance):
// rangeOption.Value = someOtherCompositeRange;
// ---------------------------------------------------------------------------------
// Hiding generated ranges
// ---------------------------------------------------------------------------------
// By default the popup's range tree includes generated ranges such as "< All >".
// Hide them if the user must pick a real range. Hiding the All range while it is
// selected clears the selection. The setting is kept when the table changes.
// rangeOption.SetAllRangeVisible(false);
// ---------------------------------------------------------------------------------
// Reacting to changes
// ---------------------------------------------------------------------------------
// ValueChanged is raised whenever the selection changes, either from the popup or
// from script. args.Value is the option's ICompositeRange.
rangeOption.ValueChanged += (sender, args) =>
{
// For example, enable another option only when a range is selected:
// otherOption.Enabled = !args.Value.IsNullTableRange();
};
// ---------------------------------------------------------------------------------
// Remembering the value between runs
// ---------------------------------------------------------------------------------
// RestoreValue restores the last saved value now, and saves the current value when
// the form is closed with OK. Use a key unique to your script. The table must be
// assigned before RestoreValue is called.
rangeOption.RestoreValue("MyScript.Range");
// ---------------------------------------------------------------------------------
// How to tell if the "*" match-everything wildcard is selected.
// ---------------------------------------------------------------------------------
// The InlineRangeSelect differs from the RangeSelect, in that it doesn't have a "AllInlineRangeSelected" accessor.
// This is because there is a filter expression and a inverse checkbox that play a factor in whether the "*" range is truly selected.
// If the "*" text is the inline text, but the inverse checkbox is set to true, would a "AllInlineRangeSelected" property return true (because the "*" text is set) or false (because the "inverse" checkbox is set) ?
// Because of this, we have decided to leave it to you to decide what this mean
// Using a method like the following might help cover this intentional gap in API
//
//private static bool IsInlineRangeSetToAll(ICompositeRange compositeRange){
// if(compositeRange.InlineRange.Text.Trim().Equals("*") && compositeRange.InlineRange.Inverse == false && String.IsNullOrEmpty(compositeRange.InlineRange.FilterExpression))
// return true;
// return false;
//}
// ---------------------------------------------------------------------------------
// Showing the form and using the result
// ---------------------------------------------------------------------------------
if (form.ShowDialog() != DialogResult.OK)
return;
var range = rangeOption.Value;
// Mode tells you which part of the composite range is in effect.
var description = new StringBuilder();
if (range.Mode == RangeMode.Table)
{
// TableRange is null when nothing is selected.
if (range.TableRange == null)
description.AppendLine("No table range selected.");
else
description.AppendLine("Table range: " + range.TableRange.FullName);
}
else
{
// The inline range: the text entered, whether it is inverted, and any filter
// expression applied to it.
description.AppendLine("Inline range text: " + range.InlineRange.Text);
description.AppendLine("Inverted: " + range.InlineRange.Inverse);
description.AppendLine("Filter expression: " + range.InlineRange.FilterExpression);
}
// ToEditableString gives a single-line description of the whole selection,
// e.g. "My Range" or "[Inline] [Inverse] SomeNode*".
description.AppendLine("Editable string: " + range.ToEditableString());
// The composite range is itself an IRange: initialise its cache, then use Count,
// CachedNodes or IsInRange to work with the nodes it resolves to.
range.EnsureCacheInitialised();
description.AppendLine("Nodes in range: " + range.Count);
foreach (var node in range.CachedNodes)
{
description.AppendLine("First node: " + node.FullName);
break;
}
MessageBox.Show(description.ToString(), "Inline Range Select Example");
}
/// <summary>
/// A common pattern: let the user pick the table on the same form, and point the
/// range option at whichever table they choose.
/// </summary>
public static void InlineRangeSelectWithTableSelectExample()
{
var form = OptionsForm.Create("Ranges Driven By Table Select");
var tableOption = form.Options.AddTableSelect("Table");
var rangeOption = form.Options.AddInlineRangeSelect("Range");
// When the chosen table changes, retarget the range option. Ranges with the same
// name on the new table stay selected; anything else is cleared.
tableOption.ValueChanged += (sender, args) => rangeOption.SetTable(args.Value);
if (form.ShowDialog() != DialogResult.OK)
return;
var range = rangeOption.Value;
MessageBox.Show("Selected: " + range.ToEditableString(), "Ranges Driven By Table Select");
}
}
A script showing how to add a Range Selection or an Inline Range Selection as a Custom Design Action (CDA):
Copy
public partial class ClassName
{
private static RangeSelectOption _rangeOption;
private static InlineRangeSelectOption _inlineRangeSelect;
[CustomDesignAction]
internal static CustomDesignAction Create()
{
var t = Project.ActiveProject.Data.Tables.GetOrThrow("Deposit");
var cda = new CustomDesignAction("Range Testing", "This should test the Inline Range Select", "Utils");
cda.SelectionPanelEnabled = true;
cda.SetupAction += (s,e) => {cda.SetSelectMode(SelectMode.SelectAll);};
cda.OptionsForm += (s,e) =>{
var form = OptionsForm.Create("This is an options form");
_rangeOption = form.Options.AddRangeSelect("Range Select");
_rangeOption.SetTable(t);
_inlineRangeSelect = form.Options.AddInlineRangeSelect("Inline RangeSelect", true);
_inlineRangeSelect.SetTable(t);
e.OptionsForm = form;
};
cda.ApplyAction += (s,e) => {
var allRangeVisible = _inlineRangeSelect.AllRangeVisible;
Console.WriteLine($"All Range Visible == {allRangeVisible}");
var allRangeSelected = _inlineRangeSelect.AllRangeSelected;
Console.WriteLine($"All Range Selected == {allRangeSelected}");
var table = _inlineRangeSelect.Table;
Console.WriteLine($"Table name is:{_inlineRangeSelect.Table.Name}");
var output = _inlineRangeSelect.Value;
if(output == null){
Console.WriteLine("!!!!The output is null. Is this expected?");
}else{
//======== Validate Inline Range =====\\
var inlineRange = output.InlineRange;
if(inlineRange == null)
Console.WriteLine($"!!!Inline Range == null. Is this expected?");
else{
Console.WriteLine($"Inline Range Text: {inlineRange.Text}");
Console.WriteLine($"Nodes in the Inline Range:");
foreach(var n in inlineRange.CachedNodes)
Console.WriteLine($"{n}");
Console.WriteLine($"Inline Range Inverse?: {inlineRange.Inverse}");
}
//========= Validate Table Rangte ========\\
var tableRange = output.TableRange;
if(tableRange == null){
Console.WriteLine("!!!Table Range == null. Is this expected?");
}else{
Console.WriteLine($"Table Range Name: {tableRange.Name}");
if(!_inlineRangeSelect.AllRangeSelected){
Console.WriteLine($"Nodes in the Table Range:");
foreach(var n in tableRange.CachedNodes)
Console.WriteLine($"{n}");
}
}
}
};
return cda;
}
}