#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; namespace Maestro.Base.Editor { public partial class EditorContentBase : ViewContentBase, IEditorViewContent { public EditorContentBase() { InitializeComponent(); } public bool CanUpgrade { get { return upgradePanel.Visible; } private set { upgradePanel.Visible = value; } } private IEditorService _svc; public IEditorService EditorService { get { return _svc; } set { if (_svc != null) { //Just being responsible _svc.DirtyStateChanged -= OnDirtyStateChanged; _svc.Saved -= OnSaved; _svc.BeforeSave -= OnBeforeSave; } _svc = value; _svc.DirtyStateChanged += OnDirtyStateChanged; _svc.Saved += OnSaved; _svc.BeforeSave += OnBeforeSave; this.Resource = _svc.GetEditedResource(); 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(); } } /// /// 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(); } } /// /// 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 (validate) { var errors = new List(ValidateEditedResource()).ToArray(); if (errors.Length > 0) { MessageService.ShowError(Properties.Resources.FixErrorsBeforeSaving); ValidationResultsDialog diag = new ValidationResultsDialog(this.Resource.ResourceID, errors); diag.ShowDialog(Workbench.Instance); e.Cancel = true; } else { e.Cancel = false; } } else { LoggingService.Info("Skipping validation on save"); e.Cancel = false; } } catch (Exception ex) { ErrorDialog.Show(ex); e.Cancel = 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 void UpdateTitle() { this.Title = this.IsNew ? Properties.Resources.NewResource : ResourceIdentifier.GetName(_svc.ResourceID); this.Description = this.IsNew ? Properties.Resources.NewResource : _svc.ResourceID; } const string DIRTY_PREFIX = "* "; 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); } } public IResource Resource { get; private set; } /// /// 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(); } public virtual bool CanBePreviewed { get { var res = this.Resource; if (res != null) { var rt = res.ResourceType; return ResourcePreviewEngine.IsPreviewableType(rt) && res.CurrentConnection.Capabilities.SupportsResourcePreviewUrls; } return false; } } public event EventHandler DirtyStateChanged; private bool _dirty; public bool IsDirty { get { return _dirty; } set { _dirty = value; var handler = this.DirtyStateChanged; if (handler != null) handler(this, EventArgs.Empty); } } public bool IsNew { get { return _svc != null ? _svc.IsNew : true; } //Mono } public virtual bool CanProfile { get { return false; } } public virtual bool CanBeValidated { get { return true; } } public virtual bool CanEditAsXml { get { return true; } } public virtual string SetupPreviewUrl(string mapguideRootUrl) { //Save the current resource to another session copy string resId = "Session:" + this.EditorService.SessionID + "//" + Guid.NewGuid() + "." + this.Resource.ResourceType.ToString(); this.EditorService.ResourceService.SetResourceXmlData(resId, ResourceTypeRegistry.Serialize(this.Resource)); //Copy any resource data var previewCopy = this.EditorService.ResourceService.GetResource(resId); this.Resource.CopyResourceDataTo(previewCopy); //Now feed it to the preview engine return new ResourcePreviewEngine(mapguideRootUrl, this.EditorService).GeneratePreviewUrl(previewCopy); } public virtual void SyncSessionCopy() { this.EditorService.SyncSessionCopy(); } public bool DiscardChangesOnClose { get; private set; } 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(Properties.Resources.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 } } } }