#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 OSGeo.MapGuide.MaestroAPI.Resource;
using OSGeo.MapGuide.MaestroAPI;
using Maestro.Editors;
using ICSharpCode.Core;
using OSGeo.MapGuide.MaestroAPI.Resource.Validation;
using Maestro.Base.UI;
using Maestro.Base.UI.Preferences;
using Maestro.Shared.UI;
using OSGeo.MapGuide.MaestroAPI.Resource.Conversion;
using System.IO;
using Maestro.Base.Services;
using Maestro.Editors.Preview;
namespace Maestro.Base.Editor
{
///
/// The base class of all editor views
///
public partial class EditorContentBase : ViewContentBase, IEditorViewContent
{
public EditorContentBase()
{
InitializeComponent();
}
///
/// Gets whether the edited resource can be upgraded
///
public bool CanUpgrade
{
get { return upgradePanel.Visible; }
private set { upgradePanel.Visible = value; }
}
///
/// Gets whether the editor requires to be reloaded. Usually triggered if the session of the underlying connection has expired
///
[DefaultValue(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool RequiresReload
{
get { return sessionRestartPanel.Visible; }
set { sessionRestartPanel.Visible = value; }
}
private IEditorService _svc;
///
/// Gets or sets the editor service instance
///
public IEditorService EditorService
{
get
{
return _svc;
}
set
{
if (_svc != null)
{
//Just being responsible
_svc.DirtyStateChanged -= OnDirtyStateChanged;
_svc.Saved -= OnSaved;
_svc.BeforeSave -= OnBeforeSave;
var res = _svc.GetEditedResource();
res.CurrentConnection.SessionIDChanged -= OnSessionIdChanged;
}
_svc = value;
_svc.PreviewLocale = PropertyService.Get(ConfigProperties.PreviewLocale, ConfigProperties.DefaultPreviewLocale);
_svc.DirtyStateChanged += OnDirtyStateChanged;
_svc.Saved += OnSaved;
_svc.BeforeSave += OnBeforeSave;
{
var res = _svc.GetEditedResource();
res.CurrentConnection.SessionIDChanged += OnSessionIdChanged;
}
UpdateTitle();
this.CanUpgrade = _svc.IsUpgradeAvailable;
Bind(_svc);
//Do dirty state check
OnDirtyStateChanged(this, EventArgs.Empty);
//This is to ensure that save works when returning from
//XML edit mode
this.Focus();
}
}
void OnSessionIdChanged(object sender, EventArgs e)
{
this.RequiresReload = true;
}
///
/// Gets the XML content of the edited resource
///
///
public virtual string GetXmlContent()
{
using (var sr = new System.IO.StreamReader(ResourceTypeRegistry.Serialize(this.Resource)))
{
return sr.ReadToEnd();
}
}
///
/// Gets the edited resource
///
public IResource Resource { get { return this.EditorService.GetEditedResource(); } }
private void OpenAffectedResource(IResource res)
{
_svc.OpenResource(res.ResourceID);
}
///
/// Performs any pre-save validation logic. The base implementation performs
/// a validation (non-casccading) on the
/// edited resource before attempting a save into the session repository
/// (triggering any errors relating to invalid XML content). Override this
/// method if the base implementation just described does not cover your
/// validation needs.
///
///
///
protected virtual void OnBeforeSave(object sender, CancelEventArgs e)
{
//We've been editing an in-memory model of the session copy
//so we need to save this model back to the session copy before Save()
//commits the changes back to the original resource
_svc.UpdateResourceContent(GetXmlContent());
try
{
var validate = PropertyService.Get(ConfigProperties.ValidateOnSave, true);
if (this.IsDirty && validate)
{
BusyWaitDelegate del = () =>
{
var errors = new List(ValidateEditedResource()).ToArray();
return errors;
};
BusyWaitDialog.Run(Strings.PrgPreSaveValidation, del, (result, ex) => {
if (ex != null)
throw ex;
ValidationIssue[] errors = result as ValidationIssue[];
if (errors.Length > 0)
{
MessageService.ShowError(Strings.FixErrorsBeforeSaving);
ValidationResultsDialog diag = new ValidationResultsDialog(this.Resource.ResourceID, errors, OpenAffectedResource);
diag.ShowDialog(Workbench.Instance);
e.Cancel = true;
}
else
{
e.Cancel = false;
}
});
}
else
{
LoggingService.Info("Skipping validation on save"); //NOXLATE
e.Cancel = false;
}
}
catch (Exception ex)
{
ErrorDialog.Show(ex);
e.Cancel = true;
}
}
///
/// Gets whether this view can only be housed within the document region
///
public override bool IsExclusiveToDocumentRegion
{
get
{
return true;
}
}
///
/// Performs any pre-save validation on the currently edited resource, by default
/// this returns the results of a non-cascading
/// validation run. Override this if you have a custom method of validation.
///
protected virtual ICollection ValidateEditedResource()
{
var context = new ResourceValidationContext(_svc.ResourceService, _svc.FeatureService);
//Don't recurse as we only want to validate the current resource
var issues = ResourceValidatorSet.Validate(context, this.Resource, false);
var set = new ValidationResultSet(issues);
var errors = set.GetIssuesForResource(this.Resource.ResourceID, ValidationStatus.Error);
return errors;
}
void OnSaved(object sender, EventArgs e)
{
UpdateTitle();
}
private string GetTooltip(string item)
{
return string.Format(Strings.EditorTitleTemplate, item, Environment.NewLine, this.Resource.CurrentConnection.DisplayName, this.Resource.ResourceVersion);
}
private void UpdateTitle()
{
this.Title = this.IsNew ? Strings.NewResource : ResourceIdentifier.GetName(_svc.ResourceID);
this.Description = GetTooltip(this.IsNew ? Strings.NewResource : _svc.ResourceID);
}
const string DIRTY_PREFIX = "* "; //NOXLATE
void OnDirtyStateChanged(object sender, EventArgs e)
{
this.IsDirty = _svc.IsDirty; //Sync states
if (_svc.IsDirty)
{
if (!this.Title.StartsWith(DIRTY_PREFIX))
this.Title = DIRTY_PREFIX + this.Title;
}
else
{
if (this.Title.StartsWith(DIRTY_PREFIX))
this.Title = this.Title.Substring(1);
}
}
///
/// Binds the specified resource to this control. This effectively initializes
/// all the fields in this control and sets up databinding on all fields. All
/// subclasses *must* override this method.
///
/// Also note that this method may be called more than once (e.g. Returning from
/// and XML edit of this resource). Thus subclasses must take this scenario into
/// account when implementing
///
///
protected virtual void Bind(IEditorService service)
{
throw new NotImplementedException();
}
///
/// Gets whether this resource can be previewed
///
public virtual bool CanBePreviewed
{
get
{
var res = this.Resource;
if (res != null)
{
var type = res.CurrentConnection.ProviderName;
return ResourcePreviewerFactory.IsPreviewable(type, res);
}
return false;
}
}
///
/// Raised when the resource's dirty state has changed
///
public event EventHandler DirtyStateChanged;
private bool _dirty;
///
/// Gets whether this resource is dirty (ie. has unsaved changes)
///
public bool IsDirty
{
get { return _dirty; }
set
{
_dirty = value;
var handler = this.DirtyStateChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
///
/// Gets whether this resource is a new un-saved resource
///
public bool IsNew
{
get { return _svc != null ? _svc.IsNew : true; } //Mono
}
///
/// Gets whether this resource can be previewed
///
public virtual bool CanProfile
{
get { return false; }
}
///
/// Gets whether this resource can be validated
///
public virtual bool CanBeValidated
{
get { return true; }
}
///
/// Gets whether this resource can be edited in its raw XML form
///
public virtual bool CanEditAsXml
{
get { return true; }
}
///
/// Previews this resource
///
public virtual void Preview()
{
var conn = this.Resource.CurrentConnection;
_svc.PrePreviewProcess();
var previewer = ResourcePreviewerFactory.GetPreviewer(conn.ProviderName);
if (previewer != null)
previewer.Preview(this.Resource, this.EditorService, _svc.PreviewLocale);
}
///
/// Synchronizes the in-memory resource object back to its session-based resource id
///
public virtual void SyncSessionCopy()
{
this.EditorService.SyncSessionCopy();
}
///
/// Gets whether to discard unsaved changes when closed
///
public bool DiscardChangesOnClose
{
get;
private set;
}
///
/// Closes this view
///
///
public virtual void Close(bool discardChanges)
{
this.DiscardChangesOnClose = discardChanges;
base.Close();
}
private void btnUpgrade_Click(object sender, EventArgs e)
{
var res = _svc.GetEditedResource();
var conn = res.CurrentConnection;
var ver = conn.Capabilities.GetMaxSupportedResourceVersion(res.ResourceType);
using (new WaitCursor(this))
{
var conv = new ResourceObjectConverter();
var res2 = conv.Convert(res, ver);
using (var stream = ResourceTypeRegistry.Serialize(res2))
{
using (var sr =new StreamReader(stream))
{
_svc.UpdateResourceContent(sr.ReadToEnd());
((ResourceEditorService)_svc).ReReadSessionResource();
}
}
//This will re-init everything
this.EditorService = this.EditorService;
MessageBox.Show(string.Format(Strings.ResourceUpgraded, ver.Major, ver.Minor, ver.Build));
this.EditorService.MarkDirty(); //It gets re-init with a clean slate, but an in-place upgrade is a dirty operation
}
}
private void btnReload_Click(object sender, EventArgs e)
{
if (this.EditorService.IsNew)
{
MessageService.ShowMessage(Strings.TextReloadNewResource);
this.Close(true);
}
else
{
var omgr = ServiceRegistry.GetService();
var res = this.EditorService.GetEditedResource();
var origResId = this.EditorService.ResourceID;
var conn = res.CurrentConnection;
var wb = Workbench.Instance;
this.Close();
omgr.Open(origResId, conn, false, wb.ActiveSiteExplorer);
}
}
}
}