#region Disclaimer / License
// Copyright (C) 2009, Kenneth Skovhede
// http://www.hexad.dk, opensource@hexad.dk
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#endregion Disclaimer / License
using Maestro.Editors.Common.Expression;
using Maestro.Editors.LayerDefinition.Vector.Thematics;
using Maestro.Shared.UI;
using OSGeo.FDO.Expressions;
using OSGeo.MapGuide.MaestroAPI;
using OSGeo.MapGuide.MaestroAPI.Exceptions;
using OSGeo.MapGuide.MaestroAPI.Schema;
using OSGeo.MapGuide.MaestroAPI.Services;
using OSGeo.MapGuide.ObjectModels.Capabilities;
using OSGeo.MapGuide.ObjectModels.FeatureSource;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace Maestro.Editors.Common
{
/*
* Intellisense overview:
*
* The intellisense of this expression editor consists of the following parts:
* - An ImageListBox which is filled with auto-complete suggestions
* - A System.Windows.Forms.ToolTip which is shown when an auto-complete choice is highlighted (but not selected)
*
* In order to invoke intellisense, we listen for the KeyUp and KeyDown events
* on the textbox to determine what actions to take. Some actions include:
*
* Key Up:
* - Comma: Show auto-complete with all suggestions
* - Quotes (Single or Double): Insert an extra quote of that type
* - Up/Down: Move the auto-complete selection up/down one item if the auto-complete box is visible.
* - Backspace: Invoke auto-complete with suggestions if there is a context buffer, otherwise hide auto-complete.
* - Alt + Right: Invoke auto-complete with all suggestions
* - Alphanumeric (no modifiers): Invoke auto-complete with suggestions
*
* Key Down:
* - Escape: Hide auto-complete
* - Enter: Hide auto-complete
*
* As part of the loading process, a full list of auto-complete items (functions/properties) is constructed (sorted by name)
* Everytime intellisense is invoked, this list is queried for possible suggestions.
*
* In order to determine what items to suggest, the editor builds a context buffer from the current position of the caret
* in the textbox. The context buffer algorithm is as follows:
*
* 1 - Start from caret position
* 2 - Can we move back one char?
* 2.1 - Get this char.
* 2.2 - If alpha numeric, goto 2.
* 3 - Get the string that represents the uninterrupted alphanumeric string sequence that ends at the caret position
* 4 - Get the list of completable items that starts with this alphanumeric string
* 5 - Add these items to the auto-complete box.
* 6 - Show the auto-complete box
*/
///
/// An expression editor dialog
///
public partial class MonoCompatibleExpressionEditor : Form, IExpressionEditor, ITextInserter, IExpressionErrorSource
{
private ClassDefinition _cls;
private IFeatureService _featSvc;
private IEditorService _edSvc;
private string m_featureSource = null;
///
/// Initializes a new instance of the class.
///
internal MonoCompatibleExpressionEditor()
{
InitializeComponent();
InitAutoComplete();
}
///
/// Gets or sets the expression.
///
/// The expression.
public string Expression
{
get { return ExpressionText.Text; }
set { ExpressionText.Text = value; }
}
private IFdoProviderCapabilities _caps;
private ExpressionEditorMode _mode;
public void Initialize(IServerConnection conn, ClassDefinition cls, string featureSourceId, ExpressionEditorMode mode)
{
IFeatureSource fs = (IFeatureSource)conn.ResourceService.GetResource(featureSourceId);
IFdoProviderCapabilities caps = conn.FeatureService.GetProviderCapabilities(fs.Provider);
//This is normally set by the Editor Service, but we don't have that so do it here
_featSvc = conn.FeatureService;
this.Initialize(null, caps, cls, featureSourceId, mode, false);
}
///
/// Initializes the dialog.
///
/// The editor service.
/// The provider capabilities.
/// The class definition.
/// The features source id.
/// The editor mode
/// If true, Stylization FDO functions will be included
public void Initialize(IEditorService edSvc, IFdoProviderCapabilities caps, ClassDefinition cls, string featureSourceId, ExpressionEditorMode mode, bool attachStylizationFunctions)
{
try
{
_caps = caps;
_mode = mode;
_cls = cls;
_edSvc = edSvc;
if (_edSvc != null)
{
_featSvc = _edSvc.CurrentConnection.FeatureService;
insertThemeExpressionToolStripMenuItem.Enabled = true;
}
else
{
insertThemeExpressionToolStripMenuItem.Enabled = false;
}
m_featureSource = featureSourceId;
insertThemeExpressionToolStripMenuItem.Enabled = attachStylizationFunctions;
//TODO: Perhaps add column type and indication of primary key
SortedList sortedCols = new SortedList();
foreach (var col in _cls.Properties)
{
sortedCols.Add(col.Name, col);
}
ColumnName.Items.Clear();
ColumnName.Tag = sortedCols;
foreach (var col in sortedCols.Values)
{
string name = col.Name;
ToolStripButton btn = new ToolStripButton();
btn.Name = name;
btn.Text = name;
btn.Click += delegate
{
InsertText(name);
};
btnProperties.DropDown.Items.Add(btn);
ColumnName.Items.Add(name);
}
if (ColumnName.Items.Count > 0)
ColumnName.SelectedIndex = 0;
LoadCompletableProperties(_cls.Properties);
//TODO: Figure out how to translate the enums into something usefull
//Functions
var sortedFuncs = new SortedList();
foreach (var func in caps.Expression.SupportedFunctions)
{
sortedFuncs.Add(func.Name, func);
}
if (attachStylizationFunctions)
{
foreach (var func in Utility.GetStylizationFunctions())
{
sortedFuncs.Add(func.Name, func);
}
}
foreach (var func in sortedFuncs.Values)
{
string name = func.Name;
string desc = func.Description;
ToolStripItemCollection parent = btnFunctions.DropDown.Items;
var sigs = ExpressionEditor.MakeUniqueSignatures(func);
if (sigs.Length > 1)
{
ToolStripMenuItem btn = new ToolStripMenuItem();
btn.Name = string.Format(Strings.MultiSigFunction, name, sigs.Length);
btn.Text = string.Format(Strings.MultiSigFunction, name, sigs.Length);
btn.ToolTipText = desc;
btnFunctions.DropDown.Items.Add(btn);
parent = btn.DropDown.Items;
}
foreach (var sig in sigs)
{
ToolStripMenuItem btn = new ToolStripMenuItem();
btn.Name = name;
btn.ToolTipText = desc;
List args = new List();
foreach (var argDef in sig.Arguments)
{
args.Add(argDef.Name.Trim());
}
string expr = $"{name}({FdoExpressionCompletionDataProvider.StringifyFunctionArgs(args)})"; //NOXLATE
btn.Text = $"{expr} : {sig.ReturnType}"; //NOXLATE
btn.Click += (s, e) =>
{
InsertText(expr);
};
parent.Add(btn);
}
}
LoadCompletableFunctions(caps.Expression.SupportedFunctions);
if (attachStylizationFunctions)
LoadCompletableFunctions(Utility.GetStylizationFunctions());
//Spatial Operators
foreach (var op in caps.Filter.SpatialOperations)
{
string name = op.ToUpper();
ToolStripButton btn = new ToolStripButton();
btn.Name = btn.Text = btn.ToolTipText = op;
btn.Click += delegate
{
InsertFilter(name);
};
btnSpatial.DropDown.Items.Add(btn);
}
//Distance Operators
foreach (var op in caps.Filter.DistanceOperations)
{
string name = op.ToUpper();
ToolStripButton btn = new ToolStripButton();
btn.Name = btn.Text = btn.ToolTipText = op;
btn.Click += delegate
{
InsertFilter(name);
};
btnDistance.DropDown.Items.Add(btn);
}
//Conditional Operators
foreach (var op in caps.Filter.ConditionTypes)
{
string name = op.ToUpper();
ToolStripButton btn = new ToolStripButton();
btn.Name = btn.Text = btn.ToolTipText = op;
btn.Click += delegate
{
InsertFilter(name);
};
btnCondition.DropDown.Items.Add(btn);
}
/*try
{
/*FdoProviderCapabilities cap = m_connection.GetProviderCapabilities(m_providername);
foreach (FdoProviderCapabilitiesFilterType cmd in cap.Filter.Condition)
FunctionCombo.Items.Add(cmd.ToString());
FunctionLabel.Enabled = FunctionCombo.Enabled = true;
}
catch
{
FunctionLabel.Enabled = FunctionCombo.Enabled = false;
}*/
}
catch
{
}
}
private void InsertText(string exprText)
{
int index = ExpressionText.SelectionStart;
if (ExpressionText.SelectionLength > 0)
{
ExpressionText.SelectedText = exprText;
ExpressionText.SelectionStart = index;
}
else
{
if (index > 0)
{
string text = ExpressionText.Text;
ExpressionText.Text = text.Insert(index, exprText);
ExpressionText.SelectionStart = index;
}
else
{
ExpressionText.Text = exprText;
ExpressionText.SelectionStart = index;
}
}
}
private void InsertFilter(string op)
{
if (!string.IsNullOrEmpty(op))
{
string exprText = $" {op} GeomFromText('')"; //LOCALIZEME
InsertText(exprText);
}
}
private void OKBtn_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
private SortedList> _autoCompleteItems = new SortedList>();
private ImageListBox _autoBox;
private enum AutoCompleteItemType : int
{
Property = 0,
Function = 1,
}
///
/// Base auto-complete item
///
private abstract class AutoCompleteItem
{
public abstract AutoCompleteItemType Type { get; }
public abstract string Name { get; }
public abstract string ToolTipText { get; }
public abstract string AutoCompleteText { get; }
}
///
/// Property auto-complete item
///
private class PropertyItem : AutoCompleteItem
{
private PropertyDefinition _propDef;
public PropertyItem(PropertyDefinition pd)
{
_propDef = pd;
}
public override AutoCompleteItemType Type
{
get { return AutoCompleteItemType.Property; }
}
public override string Name
{
get { return _propDef.Name; }
}
private string _ttText;
public override string ToolTipText
{
get
{
if (string.IsNullOrEmpty(_ttText))
{
_ttText = string.Format(Strings.PropertyTooltip, _propDef.Name, _propDef.Type.ToString());
}
return _ttText;
}
}
public override string AutoCompleteText
{
get { return this.Name; }
}
}
///
/// Function auto-complete item
///
private class FunctionItem : AutoCompleteItem
{
private IFdoFunctionDefintion _func;
private IFdoFunctionDefintionSignature _sig;
private readonly string _insertExpr;
private FunctionItem(IFdoFunctionDefintion fd, IFdoFunctionDefintionSignature sig)
{
_func = fd;
_sig = sig;
}
public FunctionItem(IFdoFunctionDefintion fd, IFdoFunctionDefintionSignature sig, string insertExpr)
: this(fd, sig)
{
_insertExpr = insertExpr;
}
public override AutoCompleteItemType Type
{
get { return AutoCompleteItemType.Function; }
}
public override string Name
{
get { return _insertExpr; } // _func.Name; }
}
private string _ttText;
public override string ToolTipText
{
get
{
if (string.IsNullOrEmpty(_ttText))
{
string argDesc = FdoExpressionCompletionDataProvider.DescribeSignature(_sig);
_ttText = string.Format(Strings.ExprEditorFunctionDesc, _insertExpr, _func.Description, argDesc, _sig.ReturnType, Environment.NewLine);
}
//_ttText = string.Format(Strings.FunctionTooltip, GetReturnTypeString(), _func.Name, GetArgumentString(), _func.Description);
return _ttText;
}
}
private string _argStr;
private string GetArgumentString()
{
if (string.IsNullOrEmpty(_argStr))
{
List tokens = new List();
foreach (var argDef in _sig.Arguments)
{
tokens.Add("[" + argDef.Name.Trim() + "]");
}
_argStr = string.Join(", ", tokens.ToArray());
}
return _argStr;
}
private string GetReturnTypeString()
{
return _sig.ReturnType;
}
public override string AutoCompleteText
{
get
{
return _insertExpr; //return this.Name + "(" + GetArgumentString() + ")";
}
}
}
private void InitAutoComplete()
{
_autoBox = new ImageListBox();
_autoBox.Visible = false;
_autoBox.ImageList = new ImageList();
_autoBox.ImageList.Images.Add(Properties.Resources.property); //Property
_autoBox.ImageList.Images.Add(Properties.Resources.block); //Function
_autoBox.DoubleClick += new EventHandler(OnAutoCompleteDoubleClick);
_autoBox.SelectedIndexChanged += new EventHandler(OnAutoCompleteSelectedIndexChanged);
_autoBox.KeyDown += new KeyEventHandler(OnAutoCompleteKeyDown);
_autoBox.KeyUp += new KeyEventHandler(OnAutoCompleteKeyUp);
_autoBox.ValueMember = "Name";
_autoBox.Font = new Font(FontFamily.GenericMonospace, 10.0f);
ExpressionText.Controls.Add(_autoBox);
}
private void OnAutoCompleteKeyDown(object sender, KeyEventArgs e)
{
ExpressionText.Focus();
}
private void OnAutoCompleteKeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter)
{
PutAutoCompleteSuggestion();
_autoBox.Hide();
_autoCompleteTooltip.Hide(this);
}
}
private void OnAutoCompleteSelectedIndexChanged(object sender, EventArgs e)
{
ExpressionText.Focus();
if (_autoBox.Visible && _autoBox.SelectedIndex >= 0 && _autoBox.Items.Count > 0)
{
string tt = ((_autoBox.SelectedItem as ImageListBoxItem).Tag as AutoCompleteItem).ToolTipText;
Point pt = GetCaretPoint();
pt.X += _autoBox.Width + 10;
pt.Y += 65;
_autoCompleteTooltip.Show(tt, this, pt.X, pt.Y);
}
}
private void OnAutoCompleteDoubleClick(object sender, EventArgs e)
{
PutAutoCompleteSuggestion();
_autoBox.Hide();
_autoCompleteTooltip.Hide(this);
}
private void MoveAutoCompleteSelectionDown()
{
if (_autoBox.SelectedIndex < 0)
{
_autoBox.SelectedIndex = 0;
}
else
{
int idx = _autoBox.SelectedIndex;
if ((idx + 1) <= _autoBox.Items.Count - 1)
{
_autoBox.SelectedIndex = idx + 1;
}
}
}
private void MoveAutoCompleteSelectionUp()
{
if (_autoBox.SelectedIndex < 0)
{
_autoBox.SelectedIndex = 0;
}
else
{
int idx = _autoBox.SelectedIndex;
if ((idx - 1) >= 0)
{
_autoBox.SelectedIndex = idx - 1;
}
}
}
private void LoadCompletableProperties(IEnumerable cols)
{
foreach (var col in cols)
{
if (!_autoCompleteItems.ContainsKey(col.Name))
_autoCompleteItems[col.Name] = new List();
_autoCompleteItems[col.Name].Add(new PropertyItem(col));
}
}
private void LoadCompletableFunctions(IEnumerable funcs)
{
foreach (var func in funcs)
{
var sigs = ExpressionEditor.MakeUniqueSignatures(func);
foreach (var sig in sigs)
{
var args = new List();
foreach (var argDef in sig.Arguments)
{
args.Add(argDef.Name.Trim());
}
string expr = $"{func.Name}({FdoExpressionCompletionDataProvider.StringifyFunctionArgs(args)})"; //NOXLATE
if (!_autoCompleteItems.ContainsKey(func.Name))
_autoCompleteItems[func.Name] = new List();
_autoCompleteItems[func.Name].Add(new FunctionItem(func, sig, expr));
}
}
}
private void PutAutoCompleteSuggestion()
{
if (_autoBox.SelectedItems.Count == 1)
{
int pos = ExpressionText.SelectionStart;
string context;
char? c = GetContextBuffer(out context);
AutoCompleteItem aci = (_autoBox.SelectedItem as ImageListBoxItem).Tag as AutoCompleteItem;
string fullText = aci.AutoCompleteText;
int start = pos - context.Length;
int newPos = start + fullText.Length;
int selLength = -1;
//if it's a function, highlight the parameter (or the first parameter if there is multiple arguments
if (aci.Type == AutoCompleteItemType.Function)
{
newPos = start + aci.Name.Length + 1; //Position the caret just after the opening bracket
//Has at least two arguments
int idx = fullText.IndexOf(",");
if (idx > 0)
selLength = idx - aci.Name.Length - 1;
else
selLength = fullText.IndexOf(")") - fullText.IndexOf("(") - 1;
}
string prefix = ExpressionText.Text.Substring(0, start);
string suffix = ExpressionText.Text.Substring(pos, ExpressionText.Text.Length - pos);
ExpressionText.Text = prefix + fullText + suffix;
ExpressionText.SelectionStart = newPos;
if (selLength > 0)
{
ExpressionText.SelectionLength = selLength;
}
ExpressionText.ScrollToCaret();
}
}
private Point GetCaretPoint()
{
Point pt = ExpressionText.GetPositionFromCharIndex(ExpressionText.SelectionStart);
pt.Y += (int)Math.Ceiling(ExpressionText.Font.GetHeight()) + 2;
pt.X += 2; // for Courier, may need a better method
return pt;
}
private char? GetContextBuffer(out string buffer)
{
buffer = string.Empty;
int caretPos = ExpressionText.SelectionStart;
int currentPos = caretPos;
char? res = null;
if (caretPos > 0)
{
//Walk backwards
caretPos--;
char c = ExpressionText.Text[caretPos];
while (Char.IsLetterOrDigit(c))
{
caretPos--;
if (caretPos < 0)
break;
c = ExpressionText.Text[caretPos];
}
if (caretPos > 0)
{
res = ExpressionText.Text[caretPos];
}
buffer = ExpressionText.Text.Substring(caretPos + 1, currentPos - caretPos - 1);
}
return res;
}
private void HandleKeyDown(KeyEventArgs e)
{
Keys code = e.KeyCode;
switch (code)
{
case Keys.Escape:
if (_autoBox.Visible)
{
e.SuppressKeyPress = true;
_autoBox.Hide();
_autoCompleteTooltip.Hide(this);
}
break;
case Keys.Up:
case Keys.Down:
if (_autoBox.Visible)
{
e.SuppressKeyPress = true;
}
break;
case Keys.Enter: // || Keys.Return
if (_autoBox.Visible && _autoBox.SelectedItems.Count == 1)
{
e.SuppressKeyPress = true;
PutAutoCompleteSuggestion();
_autoBox.Hide();
_autoCompleteTooltip.Hide(this);
}
break;
}
}
private void HandleKeyUp(KeyEventArgs e)
{
Keys code = e.KeyCode;
if (code == Keys.Oemcomma || code == Keys.OemOpenBrackets)
{
Complete(string.Empty);
}
else if (code == Keys.OemQuotes)
{
if (e.Modifiers == Keys.Shift) // "
InsertText("\"");
else // '
InsertText("'");
}
else if (code == Keys.D9 && e.Modifiers == Keys.Shift) // (
{
InsertText(")");
}
else if (code == Keys.Up || code == Keys.Down)
{
if (_autoBox.Visible)
{
if (code == Keys.Up)
{
MoveAutoCompleteSelectionUp();
}
else
{
MoveAutoCompleteSelectionDown();
}
}
}
else if (code == Keys.Back)
{
string context;
char? c = GetContextBuffer(out context);
if (!string.IsNullOrEmpty(context))
{
Complete(context);
}
else
{
if (_autoBox.Visible)
{
_autoBox.Hide();
_autoCompleteTooltip.Hide(this);
}
}
}
else if (e.Modifiers == Keys.Alt && e.KeyCode == Keys.Right)
{
string context;
char? c = GetContextBuffer(out context);
Complete(context);
}
else
{
if (e.Modifiers == Keys.None)
{
bool alpha = (code >= Keys.A && code <= Keys.Z);
bool numeric = (code >= Keys.D0 && code <= Keys.D9) || (code >= Keys.NumPad0 && code <= Keys.NumPad9);
if (alpha || numeric || e.KeyData == Keys.ShiftKey)
{
string context;
char? c = GetContextBuffer(out context);
Complete(context);
}
}
}
}
private List GetItemsStartingWith(string text)
{
List ati = new List();
foreach (string key in _autoCompleteItems.Keys)
{
if (key.ToLower().StartsWith(text.Trim().ToLower()))
{
ati.AddRange(_autoCompleteItems[key]);
}
}
return ati;
}
private void Complete(string text)
{
List items = GetItemsStartingWith(text);
_autoBox.Items.Clear();
int width = 0;
foreach (AutoCompleteItem it in items)
{
ImageListBoxItem litem = new ImageListBoxItem();
litem.Text = it.Name;
litem.ImageIndex = (int)it.Type;
litem.Tag = it;
_autoBox.Items.Add(litem);
int length = TextRenderer.MeasureText(it.Name, _autoBox.Font).Width + 30; //For icon size
if (length > width)
width = length;
}
_autoBox.Width = width;
if (!_autoBox.Visible)
{
if (_autoBox.Items.Count > 0)
{
_autoBox.BringToFront();
_autoBox.Show();
}
}
Point pt = GetCaretPoint();
_autoBox.Location = pt;
}
private void ExpressionText_KeyDown(object sender, KeyEventArgs e)
{
HandleKeyDown(e);
}
private void ExpressionText_KeyUp(object sender, KeyEventArgs e)
{
HandleKeyUp(e);
}
private void ColumnName_Click(object sender, EventArgs e)
{
}
private void ColumnName_SelectedIndexChanged(object sender, EventArgs e)
{
ColumnValue.Enabled = false;
LookupValues.Enabled = ColumnName.SelectedIndex >= 0;
}
private void LookupValues_Click(object sender, EventArgs e)
{
//Use UNIQUE() method first. This should work in most cases
using (new WaitCursor(this))
{
string filter = null;
var expr = $"UNIQUE({ColumnName.Text})";
bool bFallback = false;
ColumnValue.Items.Clear();
ColumnValue.Tag = null;
try
{
using (var rdr = _featSvc.AggregateQueryFeatureSource(m_featureSource, _cls.QualifiedName, filter, new System.Collections.Specialized.NameValueCollection() {
{ "UNIQ_VALS", expr }
}))
{
for (int i = 0; i < rdr.FieldCount; i++)
{
if (rdr.GetName(i) == "UNIQ_VALS")
{
ColumnName.Tag = rdr.GetFieldType(i);
}
}
while (rdr.ReadNext())
{
if (!rdr.IsNull("UNIQ_VALS"))
{
object value = rdr["UNIQ_VALS"];
ColumnValue.Items.Add(value);
}
}
rdr.Close();
}
}
catch
{
ColumnValue.Items.Clear();
bFallback = true;
}
if (!bFallback)
{
ColumnValue.Enabled = true;
ColumnValue.SelectedIndex = -1;
ColumnValue.DroppedDown = true;
return;
}
try
{
SortedList cols = (SortedList)ColumnName.Tag;
PropertyDefinition col = cols[ColumnName.Text];
bool retry = true;
Exception rawEx = null;
SortedList values = new SortedList();
bool hasNull = false;
while (retry)
{
try
{
retry = false;
using (var rd = _featSvc.QueryFeatureSource(m_featureSource, _cls.QualifiedName, filter, new string[] { ColumnName.Text }))
{
while (rd.ReadNext())
{
if (rd.IsNull(ColumnName.Text))
hasNull = true;
else
values[Convert.ToString(rd[ColumnName.Text], System.Globalization.CultureInfo.InvariantCulture)] = null;
}
rd.Close();
}
}
catch (Exception ex)
{
if (filter == null && ex.Message.IndexOf("MgNullPropertyValueException") >= 0)
{
hasNull = true;
rawEx = ex;
retry = true;
filter = ColumnName.Text + " != NULL";
}
else if (rawEx != null)
throw rawEx;
else
throw;
}
}
ColumnValue.Items.Clear();
if (hasNull)
ColumnValue.Items.Add("NULL");
foreach (string s in values.Keys)
ColumnValue.Items.Add(s);
ColumnValue.Tag = col.Type;
if (ColumnValue.Items.Count == 0)
MessageBox.Show(this, Strings.NoColumnValuesError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
else
{
ColumnValue.Enabled = true;
ColumnValue.SelectedIndex = -1;
ColumnValue.DroppedDown = true;
}
}
catch (Exception ex)
{
string msg = NestedExceptionMessageProcessor.GetFullMessage(ex);
MessageBox.Show(this, string.Format(Strings.ColumnValueError, msg), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
private void ColumnValue_SelectedIndexChanged(object sender, EventArgs e)
{
if (ColumnValue.SelectedIndex >= 0)
{
var tag = ColumnValue.Tag;
if (tag != null)
{
if (ColumnValue.Tag as Type == typeof(string) && (ColumnValue.SelectedIndex != 0 || ColumnValue.Text != "NULL"))
{
InsertText($"'{ColumnValue.Text}'"); //NOXLATE
}
else
{
if (tag is PropertyValueType && (PropertyValueType)tag == PropertyValueType.String)
InsertText($"'{ColumnValue.Text}'"); //NOXLATE
else
InsertText(ColumnValue.Text);
}
}
else
{
InsertText(ColumnValue.Text);
}
}
}
private void insertThemeExpressionToolStripMenuItem_Click(object sender, EventArgs e)
{
using (var theme = new ThemeCreator(_edSvc, _cls, this))
{
theme.ShowDialog();
}
}
void ITextInserter.InsertText(string text)
{
this.InsertText(text);
}
private void insertARGBColorExpressionToolStripMenuItem_Click(object sender, EventArgs e)
{
using (var picker = new ColorDialog())
{
if (picker.ShowDialog() == DialogResult.OK)
{
var c = picker.Color;
this.InsertText($"ARGB({c.A}, {c.R}, {c.G}, {c.B})"); //NOXLATE
}
}
}
private void insertHTMLCOLORExpressionToolStripMenuItem_Click(object sender, EventArgs e)
{
using (var picker = new ColorDialog())
{
if (picker.ShowDialog() == DialogResult.OK)
{
var c = picker.Color;
this.InsertText($"HTMLCOLOR({c.R}, {c.G}, {c.B})"); //NOXLATE
}
}
}
private void buildAndInsertLOOKUPExpressionToolStripMenuItem_Click(object sender, EventArgs e)
{
List propNames = new List();
foreach (var prop in _cls.Properties)
{
propNames.Add(prop.Name);
}
using (var picker = new LookupExpressionBuilder(propNames.ToArray()))
{
if (picker.ShowDialog() == DialogResult.OK)
{
this.InsertText(picker.GetExpression());
}
}
}
private void buildAndInsertRANGEExpressionToolStripMenuItem_Click(object sender, EventArgs e)
{
List propNames = new List();
foreach (var prop in _cls.Properties)
{
propNames.Add(prop.Name);
}
using (var picker = new RangeExpressionBuilder(propNames.ToArray()))
{
if (picker.ShowDialog() == DialogResult.OK)
{
this.InsertText(picker.GetExpression());
}
}
}
void IExpressionErrorSource.SetCursor(int line, int col)
{
string text = ExpressionText.Text;
int start = -1;
for (int i = 0; i <= line; i++)
{
start++;
start = text.IndexOf(Environment.NewLine, start);
}
ExpressionText.SelectionStart = start + col + 2; //1 to offset col, 1 to offset start
ExpressionText.SelectionLength = 0;
}
void IExpressionErrorSource.HighlightToken(string token)
{
int idx = ExpressionText.Text.IndexOf(token, StringComparison.InvariantCultureIgnoreCase);
ExpressionText.SelectionStart = idx;
ExpressionText.SelectionLength = token.Length;
}
private FdoExpressionValidator _validator = new FdoExpressionValidator();
private void btnValidate_Click(object sender, EventArgs e)
{
try
{
if (_mode == ExpressionEditorMode.Filter)
{
FdoFilter filter = FdoFilter.Parse(ExpressionText.Text);
_validator.ValidateFilter(filter, _cls, _caps);
MessageBox.Show(Strings.FilterIsValid);
}
else //Expression
{
FdoExpression expr = FdoExpression.Parse(ExpressionText.Text);
_validator.ValidateExpression(expr, _cls, _caps);
MessageBox.Show(Strings.ExprIsValid);
}
}
catch (FdoExpressionValidationException ex)
{
new ExpressionParseErrorDialog(ex, this).ShowDialog();
}
catch (FdoMalformedExpressionException ex)
{
new MalformedExpressionDialog(ex, this).ShowDialog();
}
}
private void viewParsedExpressionFilterToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
if (_mode == ExpressionEditorMode.Filter)
{
FdoFilter filter = FdoFilter.Parse(ExpressionText.Text);
new ExpressionDisplayDialog(filter).ShowDialog();
}
else //Expression
{
FdoExpression expr = FdoExpression.Parse(ExpressionText.Text);
new ExpressionDisplayDialog(expr).ShowDialog();
}
}
catch (FdoParseException ex)
{
MessageBox.Show(ex.Message);
}
}
}
// ImageListBoxItem class
internal class ImageListBoxItem
{
private string _myText;
private int _myImageIndex;
// properties
public string Text
{
get { return _myText; }
set { _myText = value; }
}
public int ImageIndex
{
get { return _myImageIndex; }
set { _myImageIndex = value; }
}
//constructor
public ImageListBoxItem(string text, int index)
{
_myText = text;
_myImageIndex = index;
}
public ImageListBoxItem(string text)
: this(text, -1)
{
}
public ImageListBoxItem()
: this("")
{
}
private object _tag;
public object Tag
{
get { return _tag; }
set { _tag = value; }
}
public override string ToString()
{
return _myText;
}
}//End of ImageListBoxItem class
// ImageListBox class
//
// Based on GListBox
//
// http://www.codeproject.com/KB/combobox/glistbox.aspx
internal class ImageListBox : ListBox
{
private ImageList _myImageList;
public ImageList ImageList
{
get { return _myImageList; }
set { _myImageList = value; }
}
public ImageListBox()
{
// Set owner draw mode
this.DrawMode = DrawMode.OwnerDrawFixed;
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
e.DrawBackground();
e.DrawFocusRectangle();
ImageListBoxItem item;
Rectangle bounds = e.Bounds;
Size imageSize = _myImageList.ImageSize;
try
{
item = (ImageListBoxItem)Items[e.Index];
if (item.ImageIndex != -1)
{
_myImageList.Draw(e.Graphics, bounds.Left, bounds.Top, item.ImageIndex);
e.Graphics.DrawString(item.Text, e.Font, new SolidBrush(e.ForeColor),
bounds.Left + imageSize.Width, bounds.Top);
}
else
{
e.Graphics.DrawString(item.Text, e.Font, new SolidBrush(e.ForeColor),
bounds.Left, bounds.Top);
}
}
catch
{
if (e.Index != -1)
{
e.Graphics.DrawString(Items[e.Index].ToString(), e.Font,
new SolidBrush(e.ForeColor), bounds.Left, bounds.Top);
}
else
{
e.Graphics.DrawString(Text, e.Font, new SolidBrush(e.ForeColor),
bounds.Left, bounds.Top);
}
}
base.OnDrawItem(e);
}
}//End of ImageListBox class
}