#region Disclaimer / License
// Copyright (C) 2010, Jackie Ng
// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie@gmail.com
//
// 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.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Xml.Schema;
using System.Xml;
using System.IO;
using OSGeo.MapGuide.ObjectModels;
using OSGeo.MapGuide.MaestroAPI.Resource;
using OSGeo.MapGuide.MaestroAPI.Exceptions;
using OSGeo.MapGuide.MaestroAPI;
namespace Maestro.Editors.Generic
{
///
///
///
public delegate void XmlValidationCallback(out string[] errors, out string[] warnings);
///
/// A generic XML content editor
///
public partial class XmlEditorCtrl : EditorBase, INotifyResourceChanged
{
private bool _ready = false;
///
/// Initializes a new instance of the class.
///
public XmlEditorCtrl()
{
InitializeComponent();
txtXmlContent.MaxLength = int.MaxValue;
}
///
/// Gets or sets the validator.
///
/// The validator.
public XmlValidationCallback Validator { get; set; }
///
/// Gets or sets the color of the text.
///
/// The color of the text.
public Color TextColor
{
get { return txtXmlContent.ForeColor; }
set { txtXmlContent.ForeColor = value; }
}
///
/// Gets or sets the color of the background.
///
/// The color of the background.
public Color BackgroundColor
{
get { return txtXmlContent.BackColor; }
set { txtXmlContent.BackColor = value; }
}
///
/// Gets or sets the text font.
///
/// The text font.
public Font TextFont
{
get { return txtXmlContent.Font; }
set { txtXmlContent.Font = value; }
}
///
/// Readies for editing.
///
public void ReadyForEditing()
{
_ready = true;
}
///
/// Raises the event.
///
/// An that contains the event data.
protected override void OnLoad(EventArgs e)
{
EvaluateCommands();
}
private void EvaluateCommands()
{
btnUndo.Enabled = txtXmlContent.CanUndo;
btnCut.Enabled = txtXmlContent.SelectionLength > 0;
btnCopy.Enabled = txtXmlContent.SelectionLength > 0;
btnPaste.Enabled = Clipboard.ContainsText();
btnValidate.Enabled = (this.Validator != null);
}
///
/// Gets or sets the content of the XML.
///
/// The content of the XML.
public string XmlContent
{
get { return txtXmlContent.Text; }
set { txtXmlContent.Text = value; FormatText(); }
}
private void btnUndo_Click(object sender, EventArgs e)
{
txtXmlContent.Undo();
}
private void btnFindNext_Click(object sender, EventArgs e)
{
String szFind = txtFind.Text;
if (String.IsNullOrEmpty(szFind))
{
MessageBox.Show(this, Properties.Resources.FindEmptyString, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
txtFind.Focus();
return;
}
FindAndReplace(szFind, null);
}
private void btnReplaceAll_Click(object sender, EventArgs e)
{
if (txtFind.Text.Length == 0)
MessageBox.Show(Properties.Resources.FindReplaceNothing);
FindAndReplace(txtFind.Text, txtReplace.Text);
}
///
/// Finds and replaces the specified search string with the specified replacement string
///
/// The search string.
/// The replacement string.
public void FindAndReplace(string szFind, string szReplace)
{
var textEditor = txtXmlContent;
// find start
int iStartSearching = textEditor.SelectionStart;
if (textEditor.SelectionLength > 0)
iStartSearching++;
System.Text.RegularExpressions.Regex regexThis = new System.Text.RegularExpressions.Regex(szFind, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Match matchThis = regexThis.Match(textEditor.Text, iStartSearching);
// look by regex, then simple find
String szFindInstance = "";
if (matchThis.Success)
{
int iRegExStart = matchThis.Index;
int iRegExLength = matchThis.Length;
// TODO: this is a rubbish hack for single occurrance - there is probably a better RegEx way to find/replace
szFindInstance = matchThis.ToString();
}
else
{
if (textEditor.Text.IndexOf(szFind, iStartSearching, StringComparison.OrdinalIgnoreCase) < 0)
{
MessageBox.Show(this, Properties.Resources.FindNothing, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
szFindInstance = szFind;
}
String szHighlight;
if (String.IsNullOrEmpty(szReplace))
szHighlight = szFindInstance;
else
{
textEditor.Text = textEditor.Text.Replace(szFindInstance, szReplace);
szHighlight = szReplace;
}
int iFound = textEditor.Text.IndexOf(szHighlight, iStartSearching);
if (iFound > -1)
{
textEditor.Focus();
textEditor.Select(iFound, szHighlight.Length);
UpdateTextPosition();
textEditor.ScrollToCaret();
if (!String.IsNullOrEmpty(szReplace) && _ready)
OnResourceChanged();
}
}
private void UpdateTextPosition()
{
var textEditor = txtXmlContent;
int line = textEditor.GetLineFromCharIndex(textEditor.SelectionStart + textEditor.SelectionLength);
int col = (textEditor.SelectionStart + textEditor.SelectionLength) - textEditor.GetFirstCharIndexFromLine(line);
lblCursorPos.Text = String.Format(Properties.Resources.XmlEditorCursorTemplate, line + 1, col + 1);
}
private void txtXmlContent_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyData == (Keys.Control | Keys.A))
{
txtXmlContent.SelectAll();
e.SuppressKeyPress = true;
e.Handled = true;
}/*
else if (e.KeyData == (Keys.Control | Keys.C))
{
txtXmlContent.Copy();
e.SuppressKeyPress = true;
e.Handled = true;
}
else if (e.KeyData == (Keys.Control | Keys.V))
{
txtXmlContent.Paste();
e.SuppressKeyPress = true;
e.Handled = true;
}
else if (e.KeyData == (Keys.Control | Keys.X))
{
txtXmlContent.Cut();
e.SuppressKeyPress = true;
e.Handled = true;
}
*/
UpdateTextPosition();
EvaluateCommands();
}
private void txtXmlContent_TextChanged(object sender, EventArgs e)
{
UpdateTextPosition();
EvaluateCommands();
if (_ready)
OnResourceChanged();
}
private void txtXmlContent_MouseClick(object sender, MouseEventArgs e)
{
UpdateTextPosition();
EvaluateCommands();
}
private void btnValidate_Click(object sender, EventArgs e)
{
PerformValidation(false, false);
}
///
/// Performs validation of the XML content
///
/// If true will not show a success dialog on successful validation
/// if set to true displays only errors in validation, otherwise it shows both errors and warnings.
///
/// true if validation was successful, false otherwise
///
public bool PerformValidation(bool silentSuccess, bool errorsOnly)
{
if (this.Validator != null)
{
string[] errors = new string[0];
string[] warnings = new string[0];
try
{
this.Validator(out errors, out warnings);
}
catch (XmlException ex)
{
var err = new List(errors);
err.Add(ex.Message);
errors = err.ToArray();
}
if (errors.Length > 0 || warnings.Length > 0)
{
if (errorsOnly)
{
if (errors.Length > 0)
{
new XmlValidationResult(errors, new string[0]).Show();
return false;
}
return true;
}
else
{
new XmlValidationResult(errors, warnings).Show();
}
return false;
}
else
{
if (!silentSuccess)
MessageBox.Show(Properties.Resources.XmlDocIsValid);
return true;
}
}
return true;
}
private void btnFormat_Click(object sender, EventArgs e)
{
FormatText();
}
private void FormatText()
{
string content = null;
if (string.IsNullOrEmpty(txtXmlContent.Text.Trim()))
return;
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(txtXmlContent.Text);
using (var ms = new MemoryStream())
{
using (var sw = new StreamWriter(ms))
{
var writer = XmlWriter.Create(sw, new XmlWriterSettings() { Encoding = Encoding.UTF8, Indent = true });
doc.Save(writer);
content = Encoding.UTF8.GetString(ms.GetBuffer());
}
}
}
catch (Exception ex)
{
MessageBox.Show(NestedExceptionMessageProcessor.GetFullMessage(ex), Properties.Resources.TitleError, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
if (!string.IsNullOrEmpty(content))
{
txtXmlContent.Text = content;
}
}
///
/// Binds the specified service.
///
/// The service.
public override void Bind(IEditorService service)
{
var res = service.GetEditedResource();
this.XmlContent = ResourceTypeRegistry.SerializeAsString(res);
InitResourceData(service);
}
///
/// Inits the resource data.
///
/// The service.
public void InitResourceData(IEditorService service)
{
resDataCtrl.Init(service);
}
private void resDataCtrl_DataListChanged(object sender, EventArgs e)
{
if (_ready)
OnResourceChanged();
}
private void btnCut_Click(object sender, EventArgs e)
{
txtXmlContent.Cut();
}
private void btnCopy_Click(object sender, EventArgs e)
{
txtXmlContent.Copy();
}
private void btnPaste_Click(object sender, EventArgs e)
{
txtXmlContent.Paste();
}
}
}