#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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OSGeo.MapGuide.MaestroAPI;
using OSGeo.MapGuide.MaestroAPI.Services;
using OSGeo.MapGuide.ObjectModels.Capabilities;
using OSGeo.MapGuide.MaestroAPI.Exceptions;
using Maestro.Shared.UI;
using OSGeo.MapGuide.MaestroAPI.Schema;
using Maestro.Editors.Common.Expression;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
namespace Maestro.Editors.Common
{
///
/// An expression editor dialog
///
public partial class ExpressionEditor : Form, IExpressionEditor
{
private ClassDefinition _cls;
private IFeatureService _featSvc;
private string m_featureSource = null;
private FdoProviderCapabilities _caps;
private ITextEditor _editor;
///
/// Initializes a new instance of the class.
///
internal ExpressionEditor()
{
InitializeComponent();
ExpressionText.SetHighlighting("FDO");
_editor = TextEditorFactory.CreateEditor(ExpressionText);
_editor.KeyPress += OnEditorKeyPress;
_editor.DialogKeyPress += OnEditorDialogKeyPress;
_contextualBuffer = new StringBuilder();
}
protected override void OnLoad(EventArgs e)
{
_editor.SetParent(ExpressionText);
base.OnLoad(e);
}
///
/// Gets or sets the expression.
///
/// The expression.
public string Expression
{
get { return ExpressionText.Text; }
set { ExpressionText.Text = value; }
}
///
/// Initializes the dialog.
///
/// The feature service.
/// The provider capabilities.
/// The class definition.
/// The features source id.
/// if set to true stylization functions are also attached
public void Initialize(IFeatureService featSvc, FdoProviderCapabilities caps, ClassDefinition cls, string featuresSourceId, bool attachStylizationFunctions)
{
try
{
_cls = cls;
_featSvc = featSvc;
m_featureSource = featuresSourceId;
_caps = caps;
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;
//Functions
SortedList sortedFuncs = new SortedList();
foreach (FdoProviderCapabilitiesExpressionFunctionDefinition func in caps.Expression.FunctionDefinitionList)
{
sortedFuncs.Add(func.Name, func);
}
if (attachStylizationFunctions)
{
foreach (var func in Utility.GetStylizationFunctions())
{
sortedFuncs.Add(func.Name, func);
}
}
foreach (FdoProviderCapabilitiesExpressionFunctionDefinition func in sortedFuncs.Values)
{
string name = func.Name;
ToolStripButton btn = new ToolStripButton();
btn.Name = name;
btn.Text = name;
btn.ToolTipText = func.Description;
string fmt = "{0}({1})"; //NOXLATE
List args = new List();
foreach (FdoProviderCapabilitiesExpressionFunctionDefinitionArgumentDefinition argDef in func.ArgumentDefinitionList)
{
args.Add(argDef.Name.Trim());
}
string expr = string.Format(fmt, name, FdoExpressionCompletionDataProvider.StringifyFunctionArgs(args));
btn.Click += delegate
{
InsertText(expr);
};
btnFunctions.DropDown.Items.Add(btn);
}
//Spatial Operators
foreach (FdoProviderCapabilitiesFilterOperation op in caps.Filter.Spatial)
{
string name = op.ToString().ToUpper();
ToolStripButton btn = new ToolStripButton();
btn.Name = btn.Text = btn.ToolTipText = op.ToString();
btn.Click += delegate
{
InsertSpatialFilter(name);
};
btnSpatial.DropDown.Items.Add(btn);
}
//Distance Operators
foreach (FdoProviderCapabilitiesFilterOperation1 op in caps.Filter.Distance)
{
string name = op.ToString().ToUpper();
ToolStripButton btn = new ToolStripButton();
btn.Name = btn.Text = btn.ToolTipText = op.ToString();
btn.Click += delegate
{
InsertSpatialFilter(name);
};
btnDistance.DropDown.Items.Add(btn);
}
//Conditional Operators
foreach (FdoProviderCapabilitiesFilterOperation op in caps.Filter.Condition)
{
string name = op.ToString().ToUpper();
ToolStripButton btn = new ToolStripButton();
btn.Name = btn.Text = btn.ToolTipText = op.ToString();
btn.Click += delegate
{
InsertSpatialFilter(name);
};
btnCondition.DropDown.Items.Add(btn);
}
}
catch
{
}
}
private void OKBtn_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
bool OnEditorDialogKeyPress(Keys keyData)
{
if (_editor.ProcessKeyPress(keyData))
return true;
if (keyData == Keys.Back)
StripKey();
return false;
}
bool OnEditorKeyPress(char ch)
{
if (Char.IsLetter(ch))
{
ShowAutoComplete(ch);
}
return false;
}
private StringBuilder _contextualBuffer;
private void StripKey()
{
if (_contextualBuffer.Length == 0)
{
//this.HideBox();
}
else
{
_contextualBuffer.Remove(_contextualBuffer.Length - 1, 1);
System.Diagnostics.Debug.WriteLine("Contextual buffer: " + _contextualBuffer);
//if (_contextualBuffer.Length == 0)
//this.HideBox();
}
}
internal void AppendKey(Keys keyData)
{
_contextualBuffer.Append(Convert.ToChar((int)keyData));
System.Diagnostics.Debug.WriteLine("Contextual buffer: " + _contextualBuffer);
}
private void ShowAutoComplete(char ch)
{
var provider = new FdoExpressionCompletionDataProvider(_cls, _caps);
_editor.ShowCompletionWindow(provider, ch);
}
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 + ")"; //NOXLATE
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 } //NOXLATE
}))
{
ColumnValue.Tag = rdr.GetPropertyType("UNIQ_VALS"); //NOXLATE
while (rdr.ReadNext())
{
if (!rdr.IsNull("UNIQ_VALS")) //NOXLATE
{
object value = rdr["UNIQ_VALS"]; //NOXLATE
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) //NOXLATE
{
hasNull = true;
rawEx = ex;
retry = true;
filter = ColumnName.Text + " != NULL"; //NOXLATE
}
else if (rawEx != null)
throw rawEx;
else
throw;
}
}
ColumnValue.Items.Clear();
if (hasNull)
ColumnValue.Items.Add("NULL"); //NOXLATE
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 == typeof(string) && (ColumnValue.SelectedIndex != 0 || ColumnValue.Text != "NULL")) //NOXLATE
{
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 InsertSpatialFilter(string text)
{
InsertText("[geometry] " + text + " GeomFromText('geometry wkt')");
}
private void InsertText(string text)
{
ExpressionText.ActiveTextAreaControl.TextArea.InsertString(text);
}
}
}