[mapguide-commits] r6499 - in trunk/Tools/Maestro: . Maestro Maestro.AddIn.FdoToolbox Maestro.AddIn.FdoToolbox/Properties Maestro.AddIn.Scripting Maestro.AddIn.Scripting/Commands Maestro.AddIn.Scripting/Properties Maestro.AddIn.Scripting/Services Maestro.Base Maestro.Base/Services Maestro.Base/UI Maestro.Editors Maestro.Editors/Diff OSGeo.MapGuide.MaestroAPI OSGeo.MapGuide.MaestroAPI/Resource OSGeo.MapGuide.MaestroAPI/Resource/Comparison

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Sun Feb 12 05:40:54 EST 2012


Author: jng
Date: 2012-02-12 02:40:54 -0800 (Sun, 12 Feb 2012)
New Revision: 6499

Added:
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/Commands/
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/Commands/StartupCommand.cs
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/Maestro.AddIn.Scripting.csproj
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/Manifest.addin
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/Properties/
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/Properties/AssemblyInfo.cs
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/Services/
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/Services/ScriptingClasses.cs
   trunk/Tools/Maestro/Maestro.AddIn.Scripting/Services/ScriptingService.cs
   trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.Designer.cs
   trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.cs
   trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.resx
   trunk/Tools/Maestro/Maestro.Editors/Diff/
   trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.Designer.cs
   trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.cs
   trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.resx
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/BinaryData.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/CharData.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/DiffEngine.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/TextFile.cs
Removed:
   trunk/Tools/Maestro/Maestro.Base/Services/Scripting/
   trunk/Tools/Maestro/Maestro.Base/Services/ScriptingService.cs
Modified:
   trunk/Tools/Maestro/Maestro.AddIn.FdoToolbox/Maestro.AddIn.FdoToolbox.csproj
   trunk/Tools/Maestro/Maestro.AddIn.FdoToolbox/Properties/AssemblyInfo.cs
   trunk/Tools/Maestro/Maestro.Base/Maestro.Base.addin
   trunk/Tools/Maestro/Maestro.Base/Maestro.Base.csproj
   trunk/Tools/Maestro/Maestro.Base/Services/OpenResourceManager.cs
   trunk/Tools/Maestro/Maestro.Base/UI/ProfilingDialog.cs
   trunk/Tools/Maestro/Maestro.Editors/Maestro.Editors.csproj
   trunk/Tools/Maestro/Maestro/Maestro_All.sln
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj
Log:
This submission includes the following changes:
 - Move the scripting functionality to a separate addin
 - #1950: Add support for viewing XML diffs when being asked to confirm unsaved changes.

Modified: trunk/Tools/Maestro/Maestro/Maestro_All.sln
===================================================================
--- trunk/Tools/Maestro/Maestro/Maestro_All.sln	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/Maestro/Maestro_All.sln	2012-02-12 10:40:54 UTC (rev 6499)
@@ -131,6 +131,8 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maestro.AddIn.GeoRest", "..\Maestro.AddIn.GeoRest\Maestro.AddIn.GeoRest.csproj", "{19A769B5-7CFA-4E9F-90D8-BF4A17F918C4}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maestro.AddIn.Scripting", "..\Maestro.AddIn.Scripting\Maestro.AddIn.Scripting.csproj", "{3591C5BB-2B87-4FB4-AD87-9C8176DF9835}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -301,6 +303,10 @@
 		{19A769B5-7CFA-4E9F-90D8-BF4A17F918C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{19A769B5-7CFA-4E9F-90D8-BF4A17F918C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{19A769B5-7CFA-4E9F-90D8-BF4A17F918C4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3591C5BB-2B87-4FB4-AD87-9C8176DF9835}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3591C5BB-2B87-4FB4-AD87-9C8176DF9835}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3591C5BB-2B87-4FB4-AD87-9C8176DF9835}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3591C5BB-2B87-4FB4-AD87-9C8176DF9835}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

Modified: trunk/Tools/Maestro/Maestro.AddIn.FdoToolbox/Maestro.AddIn.FdoToolbox.csproj
===================================================================
--- trunk/Tools/Maestro/Maestro.AddIn.FdoToolbox/Maestro.AddIn.FdoToolbox.csproj	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/Maestro.AddIn.FdoToolbox/Maestro.AddIn.FdoToolbox.csproj	2012-02-12 10:40:54 UTC (rev 6499)
@@ -60,6 +60,12 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Properties\GlobalAssemblyInfo.cs">
+      <Link>GlobalAssemblyInfo.cs</Link>
+    </Compile>
+    <Compile Include="..\Properties\SignedAssemblyInfo2.cs">
+      <Link>SignedAssemblyInfo2.cs</Link>
+    </Compile>
     <Compile Include="Commands\StartupCommand.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\Resources.Designer.cs">

Modified: trunk/Tools/Maestro/Maestro.AddIn.FdoToolbox/Properties/AssemblyInfo.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.AddIn.FdoToolbox/Properties/AssemblyInfo.cs	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/Maestro.AddIn.FdoToolbox/Properties/AssemblyInfo.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -7,10 +7,7 @@
 // associated with an assembly.
 [assembly: AssemblyTitle("Maestro.AddIn.FdoToolbox")]
 [assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
 [assembly: AssemblyProduct("Maestro.AddIn.FdoToolbox")]
-[assembly: AssemblyCopyright("Copyright ©  2012")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
@@ -21,16 +18,3 @@
 
 // The following GUID is for the ID of the typelib if this project is exposed to COM
 [assembly: Guid("1d41a9ea-b61e-45f4-8e17-9ac4571062fa")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]


Property changes on: trunk/Tools/Maestro/Maestro.AddIn.Scripting
___________________________________________________________________
Added: svn:ignore
   + bin
obj


Added: trunk/Tools/Maestro/Maestro.AddIn.Scripting/Commands/StartupCommand.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.AddIn.Scripting/Commands/StartupCommand.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.AddIn.Scripting/Commands/StartupCommand.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using ICSharpCode.Core;
+
+namespace Maestro.AddIn.Scripting.Commands
+{
+    internal class StartupCommand : AbstractCommand
+    {
+        public override void Run()
+        {
+            
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.AddIn.Scripting/Maestro.AddIn.Scripting.csproj
===================================================================
--- trunk/Tools/Maestro/Maestro.AddIn.Scripting/Maestro.AddIn.Scripting.csproj	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.AddIn.Scripting/Maestro.AddIn.Scripting.csproj	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{3591C5BB-2B87-4FB4-AD87-9C8176DF9835}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Maestro.AddIn.Scripting</RootNamespace>
+    <AssemblyName>Maestro.AddIn.Scripting</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\out\Debug\AddIns\Scripting\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\out\Release\AddIns\Scripting\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="IronPython">
+      <HintPath>..\Thirdparty\IronPython-2.7.1\IronPython.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="IronPython.Modules">
+      <HintPath>..\Thirdparty\IronPython-2.7.1\IronPython.Modules.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Dynamic">
+      <HintPath>..\Thirdparty\IronPython-2.7.1\Microsoft.Dynamic.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Scripting">
+      <HintPath>..\Thirdparty\IronPython-2.7.1\Microsoft.Scripting.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Scripting.Metadata">
+      <HintPath>..\Thirdparty\IronPython-2.7.1\Microsoft.Scripting.Metadata.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Properties\GlobalAssemblyInfo.cs">
+      <Link>GlobalAssemblyInfo.cs</Link>
+    </Compile>
+    <Compile Include="..\Properties\SignedAssemblyInfo2.cs">
+      <Link>SignedAssemblyInfo2.cs</Link>
+    </Compile>
+    <Compile Include="Commands\StartupCommand.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Services\ScriptingService.cs" />
+    <Compile Include="Services\ScriptingClasses.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Manifest.addin">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Maestro.Base\Maestro.Base.csproj">
+      <Project>{F1E2F468-5030-4DBA-968C-9620284AFAA1}</Project>
+      <Name>Maestro.Base</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\Maestro.Shared.UI\Maestro.Shared.UI.csproj">
+      <Project>{CFD19053-2172-41D3-8460-0FD2123A1E88}</Project>
+      <Name>Maestro.Shared.UI</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\OSGeo.MapGuide.MaestroAPI\OSGeo.MapGuide.MaestroAPI.csproj">
+      <Project>{80FA3158-8B5F-48D1-A393-0378AFE48A7E}</Project>
+      <Name>OSGeo.MapGuide.MaestroAPI</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\Thirdparty\SharpDevelop\ICSharpCode.Core\ICSharpCode.Core.csproj">
+      <Project>{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}</Project>
+      <Name>ICSharpCode.Core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

Added: trunk/Tools/Maestro/Maestro.AddIn.Scripting/Manifest.addin
===================================================================
--- trunk/Tools/Maestro/Maestro.AddIn.Scripting/Manifest.addin	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.AddIn.Scripting/Manifest.addin	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,25 @@
+<AddIn name="Maestro.AddIn.Scripting"
+       author="Jackie Ng"
+       url="http://trac.osgeo.org/mapguide/wiki/maestro"
+       description="Scripting AddIn for MapGuide Maestro"
+       addInManagerHidden="preinstalled">
+
+    <Manifest>
+        <Identity name="Maestro.AddIn.Scripting" />
+    </Manifest>
+
+    <Runtime>
+        <Import assembly="../../Maestro.Base.dll" />
+        <Import assembly="Maestro.AddIn.Scripting.dll" />
+    </Runtime>
+
+    <!-- Auto-start commands -->
+    <Path name="/Workspace/Autostart">
+        <Class id="Startup" class="Maestro.AddIn.Scripting.Commands.StartupCommand" />
+    </Path>
+
+    <!-- Application-level services -->
+    <Path name="/Maestro/ApplicationServices">
+        <Class id="ScriptingService" class="Maestro.AddIn.Scripting.Services.ScriptingService" />
+    </Path>
+</AddIn>

Added: trunk/Tools/Maestro/Maestro.AddIn.Scripting/Properties/AssemblyInfo.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.AddIn.Scripting/Properties/AssemblyInfo.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.AddIn.Scripting/Properties/AssemblyInfo.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,20 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Maestro.AddIn.Scripting")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyProduct("Maestro.AddIn.Scripting")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("bd7639b0-969a-4e6b-82ed-ee582065198f")]
\ No newline at end of file

Added: trunk/Tools/Maestro/Maestro.AddIn.Scripting/Services/ScriptingClasses.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.AddIn.Scripting/Services/ScriptingClasses.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.AddIn.Scripting/Services/ScriptingClasses.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,93 @@
+#region Disclaimer / License
+// Copyright (C) 2011, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at 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.Linq;
+using System.Text;
+using Maestro.Shared.UI;
+using ICSharpCode.Core;
+using OSGeo.MapGuide.MaestroAPI;
+using Maestro.Base;
+using Maestro.Base.Services;
+
+namespace Maestro.AddIn.Scripting.Services
+{
+    /// <summary>
+    /// A simplified helper class that is exposed to python scripts
+    /// </summary>
+    public class HostApplication
+    {
+        /// <summary>
+        /// The main application window
+        /// </summary>
+        public Workbench MainWindow
+        {
+            get { return Workbench.Instance; }
+        }
+
+        /// <summary>
+        /// The connection manager
+        /// </summary>
+        public ServerConnectionManager ConnectionManager
+        {
+            get { return ServiceRegistry.GetService<ServerConnectionManager>(); }
+        }
+
+        /// <summary>
+        /// Launches the specified url
+        /// </summary>
+        /// <param name="url"></param>
+        public void OpenUrl(string url)
+        {
+            var svc = ServiceRegistry.GetService<UrlLauncherService>();
+            svc.OpenUrl(url);
+        }
+
+        /// <summary>
+        /// Prompts for a question that requires a boolean response
+        /// </summary>
+        /// <param name="title"></param>
+        /// <param name="question"></param>
+        /// <returns></returns>
+        public bool AskQuestion(string title, string question)
+        {
+            return MessageService.AskQuestion(question, title);
+        }
+
+        /// <summary>
+        /// Displays a message
+        /// </summary>
+        /// <param name="title"></param>
+        /// <param name="message"></param>
+        public void ShowMessage(string title, string message)
+        {
+            MessageService.ShowMessage(message, title);
+        }
+
+        /// <summary>
+        /// Displays an exception in a dialog
+        /// </summary>
+        /// <param name="ex"></param>
+        public void ShowError(Exception ex)
+        {
+            ErrorDialog.Show(ex);
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.AddIn.Scripting/Services/ScriptingService.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.AddIn.Scripting/Services/ScriptingService.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.AddIn.Scripting/Services/ScriptingService.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,76 @@
+#region Disclaimer / License
+// Copyright (C) 2011, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at 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.Linq;
+using System.Text;
+using Maestro.Shared.UI;
+using Microsoft.Scripting.Hosting;
+using IronPython.Hosting;
+using ICSharpCode.Core;
+
+namespace Maestro.AddIn.Scripting.Services
+{
+    public class ScriptingService : ServiceBase
+    {
+        private ScriptEngine _pyEngine;
+        private ScriptScope _pyGlobalScope;
+
+        public override void Initialize()
+        {
+            base.Initialize();
+            _pyEngine = CreateDefaultEngine();
+            _pyGlobalScope = _pyEngine.CreateScope();
+            InitializeScope(_pyGlobalScope);
+        }
+
+        private void InitializeScope(ScriptScope scope)
+        {
+            scope.SetVariable("app", new HostApplication());
+        }
+
+        private static ScriptEngine CreateDefaultEngine()
+        {
+            return Python.CreateEngine();
+        }
+
+        /// <summary>
+        /// Evaluates the given expression
+        /// </summary>
+        /// <param name="expression"></param>
+        /// <returns></returns>
+        public dynamic Evaluate(string expression)
+        {
+            return _pyEngine.Execute(expression, _pyGlobalScope);
+        }
+
+        /// <summary>
+        /// Compiles and executes the script from the given file
+        /// </summary>
+        /// <param name="file"></param>
+        /// <returns></returns>
+        public dynamic CompileAndExecute(string file)
+        {
+            var source = _pyEngine.CreateScriptSourceFromFile(file);
+            var compiled = source.Compile();
+            return compiled.Execute(_pyGlobalScope);
+        }
+    }
+}

Modified: trunk/Tools/Maestro/Maestro.Base/Maestro.Base.addin
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/Maestro.Base.addin	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/Maestro.Base/Maestro.Base.addin	2012-02-12 10:40:54 UTC (rev 6499)
@@ -255,7 +255,6 @@
         <Class id="OpenResourceManager" class="Maestro.Base.Services.OpenResourceManager" />
         <Class id="ViewContentManager" class="Maestro.Base.Services.ViewContentManager" />
         <Class id="NewItemTemplateService" class="Maestro.Base.Services.NewItemTemplateService" />
-        <Class id="ScriptingService" class="Maestro.Base.Services.ScriptingService" />
     </Path>
 
     <!-- Singleton view content -->

Modified: trunk/Tools/Maestro/Maestro.Base/Maestro.Base.csproj
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/Maestro.Base.csproj	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/Maestro.Base/Maestro.Base.csproj	2012-02-12 10:40:54 UTC (rev 6499)
@@ -53,27 +53,7 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="IronPython">
-      <HintPath>..\Thirdparty\IronPython-2.7.1\IronPython.dll</HintPath>
-      <Private>False</Private>
-    </Reference>
-    <Reference Include="IronPython.Modules">
-      <HintPath>..\Thirdparty\IronPython-2.7.1\IronPython.Modules.dll</HintPath>
-      <Private>False</Private>
-    </Reference>
     <Reference Include="Microsoft.CSharp" />
-    <Reference Include="Microsoft.Dynamic">
-      <HintPath>..\Thirdparty\IronPython-2.7.1\Microsoft.Dynamic.dll</HintPath>
-      <Private>False</Private>
-    </Reference>
-    <Reference Include="Microsoft.Scripting">
-      <HintPath>..\Thirdparty\IronPython-2.7.1\Microsoft.Scripting.dll</HintPath>
-      <Private>False</Private>
-    </Reference>
-    <Reference Include="Microsoft.Scripting.Metadata">
-      <HintPath>..\Thirdparty\IronPython-2.7.1\Microsoft.Scripting.Metadata.dll</HintPath>
-      <Private>False</Private>
-    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Data" />
     <Reference Include="System.Drawing" />
@@ -273,8 +253,6 @@
     <Compile Include="Services\NewItemTemplateService.cs" />
     <Compile Include="Services\OpenResourceManager.cs" />
     <Compile Include="Services\ResourcePreviewerFactory.cs" />
-    <Compile Include="Services\ScriptingService.cs" />
-    <Compile Include="Services\Scripting\ScriptingClasses.cs" />
     <Compile Include="Services\ServerConnectionManager.cs" />
     <Compile Include="Services\ServiceRegistry.cs" />
     <Compile Include="Services\UrlLauncherService.cs" />
@@ -304,6 +282,12 @@
       <DependentUpon>BoundsPicker.cs</DependentUpon>
     </Compile>
     <Compile Include="UI\BroadcastTextWriter.cs" />
+    <Compile Include="UI\DirtyStateConfirmationDialog.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="UI\DirtyStateConfirmationDialog.Designer.cs">
+      <DependentUpon>DirtyStateConfirmationDialog.cs</DependentUpon>
+    </Compile>
     <Compile Include="UI\ISiteExplorer.cs" />
     <Compile Include="UI\LabelLocalizationDialog.cs">
       <SubType>Form</SubType>
@@ -534,6 +518,9 @@
       <DependentUpon>BoundsPicker.cs</DependentUpon>
       <SubType>Designer</SubType>
     </EmbeddedResource>
+    <EmbeddedResource Include="UI\DirtyStateConfirmationDialog.resx">
+      <DependentUpon>DirtyStateConfirmationDialog.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="UI\LabelLocalizationDialog.resx">
       <DependentUpon>LabelLocalizationDialog.cs</DependentUpon>
     </EmbeddedResource>

Modified: trunk/Tools/Maestro/Maestro.Base/Services/OpenResourceManager.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/Services/OpenResourceManager.cs	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/Maestro.Base/Services/OpenResourceManager.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -167,11 +167,23 @@
                 {
                     if (ed.IsDirty && !ed.DiscardChangesOnClose)
                     {
-                        string name = ed.IsNew ? string.Empty : "(" + ResourceIdentifier.GetName(ed.EditorService.ResourceID) + ")";
-                        if (!MessageService.AskQuestion(string.Format(Properties.Resources.CloseUnsavedResource, name)))
+                        if (ed.IsNew)
                         {
-                            e.Cancel = true;
+                            if (!MessageService.AskQuestion(string.Format(Properties.Resources.CloseUnsavedResource, string.Empty)))
+                            {
+                                e.Cancel = true;
+                            }
                         }
+                        else
+                        {
+                            using (var diag = new DirtyStateConfirmationDialog(ed.EditorService))
+                            {
+                                if (diag.ShowDialog() == System.Windows.Forms.DialogResult.No)
+                                {
+                                    e.Cancel = true;
+                                }
+                            }
+                        }
                     }
                 };
                 ed.ViewContentClosed += (sender, e) =>

Deleted: trunk/Tools/Maestro/Maestro.Base/Services/ScriptingService.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/Services/ScriptingService.cs	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/Maestro.Base/Services/ScriptingService.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -1,76 +0,0 @@
-#region Disclaimer / License
-// Copyright (C) 2011, Jackie Ng
-// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at 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.Linq;
-using System.Text;
-using Maestro.Shared.UI;
-using Microsoft.Scripting.Hosting;
-using IronPython.Hosting;
-using ICSharpCode.Core;
-
-namespace Maestro.Base.Services
-{
-    public class ScriptingService : ServiceBase
-    {
-        private ScriptEngine _pyEngine;
-        private ScriptScope _pyGlobalScope;
-
-        public override void Initialize()
-        {
-            base.Initialize();
-            _pyEngine = CreateDefaultEngine();
-            _pyGlobalScope = _pyEngine.CreateScope();
-            InitializeScope(_pyGlobalScope);
-        }
-
-        private void InitializeScope(ScriptScope scope)
-        {
-            scope.SetVariable("app", new Scripting.App());
-        }
-
-        private static ScriptEngine CreateDefaultEngine()
-        {
-            return Python.CreateEngine();
-        }
-
-        /// <summary>
-        /// Evaluates the given expression
-        /// </summary>
-        /// <param name="expression"></param>
-        /// <returns></returns>
-        public dynamic Evaluate(string expression)
-        {
-            return _pyEngine.Execute(expression, _pyGlobalScope);
-        }
-
-        /// <summary>
-        /// Compiles and executes the script from the given file
-        /// </summary>
-        /// <param name="file"></param>
-        /// <returns></returns>
-        public dynamic CompileAndExecute(string file)
-        {
-            var source = _pyEngine.CreateScriptSourceFromFile(file);
-            var compiled = source.Compile();
-            return compiled.Execute(_pyGlobalScope);
-        }
-    }
-}

Added: trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.Designer.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.Designer.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.Designer.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,88 @@
+namespace Maestro.Base.UI
+{
+    partial class DirtyStateConfirmationDialog
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DirtyStateConfirmationDialog));
+            this.lblConfirm = new System.Windows.Forms.Label();
+            this.btnYes = new System.Windows.Forms.Button();
+            this.btnNo = new System.Windows.Forms.Button();
+            this.btnDiff = new System.Windows.Forms.Button();
+            this.SuspendLayout();
+            // 
+            // lblConfirm
+            // 
+            resources.ApplyResources(this.lblConfirm, "lblConfirm");
+            this.lblConfirm.Name = "lblConfirm";
+            // 
+            // btnYes
+            // 
+            resources.ApplyResources(this.btnYes, "btnYes");
+            this.btnYes.Name = "btnYes";
+            this.btnYes.UseVisualStyleBackColor = true;
+            this.btnYes.Click += new System.EventHandler(this.btnYes_Click);
+            // 
+            // btnNo
+            // 
+            resources.ApplyResources(this.btnNo, "btnNo");
+            this.btnNo.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnNo.Name = "btnNo";
+            this.btnNo.UseVisualStyleBackColor = true;
+            this.btnNo.Click += new System.EventHandler(this.btnNo_Click);
+            // 
+            // btnDiff
+            // 
+            resources.ApplyResources(this.btnDiff, "btnDiff");
+            this.btnDiff.Name = "btnDiff";
+            this.btnDiff.UseVisualStyleBackColor = true;
+            this.btnDiff.Click += new System.EventHandler(this.btnDiff_Click);
+            // 
+            // DirtyStateConfirmationDialog
+            // 
+            this.AcceptButton = this.btnYes;
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
+            this.CancelButton = this.btnNo;
+            resources.ApplyResources(this, "$this");
+            this.ControlBox = false;
+            this.Controls.Add(this.btnDiff);
+            this.Controls.Add(this.btnNo);
+            this.Controls.Add(this.btnYes);
+            this.Controls.Add(this.lblConfirm);
+            this.Name = "DirtyStateConfirmationDialog";
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Label lblConfirm;
+        private System.Windows.Forms.Button btnYes;
+        private System.Windows.Forms.Button btnNo;
+        private System.Windows.Forms.Button btnDiff;
+    }
+}
\ No newline at end of file

Added: trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,118 @@
+#region Disclaimer / License
+// Copyright (C) 2012, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at 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.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using Maestro.Editors;
+using OSGeo.MapGuide.MaestroAPI.Resource.Comparison;
+using System.Collections;
+using Maestro.Editors.Diff;
+using Maestro.Shared.UI;
+using System.IO;
+
+namespace Maestro.Base.UI
+{
+    public partial class DirtyStateConfirmationDialog : Form
+    {
+        private DirtyStateConfirmationDialog()
+        {
+            InitializeComponent();
+        }
+
+        private IEditorService _edSvc;
+
+        public DirtyStateConfirmationDialog(IEditorService edSvc)
+            : this()
+        {
+            _edSvc = edSvc;
+            lblConfirm.Text = string.Format(lblConfirm.Text, _edSvc.ResourceID);
+        }
+
+        private void btnYes_Click(object sender, EventArgs e)
+        {
+            this.DialogResult = System.Windows.Forms.DialogResult.Yes;
+        }
+
+        private void btnNo_Click(object sender, EventArgs e)
+        {
+            this.DialogResult = System.Windows.Forms.DialogResult.No;
+        }
+
+        private void btnDiff_Click(object sender, EventArgs e)
+        {
+            DiffList_TextFile sLF = null;
+            DiffList_TextFile dLF = null;
+            string sourceFile = Path.GetTempFileName();
+            string targetFile = Path.GetTempFileName();
+            try
+            {
+                _edSvc.SyncSessionCopy();
+                using (var source = new StreamReader(_edSvc.ResourceService.GetResourceXmlData(_edSvc.ResourceID)))
+                using (var target = new StreamReader(_edSvc.ResourceService.GetResourceXmlData(_edSvc.EditedResourceID)))
+                {
+                    File.WriteAllText(sourceFile, source.ReadToEnd());
+                    File.WriteAllText(targetFile, target.ReadToEnd());
+
+                    sLF = new DiffList_TextFile(sourceFile);
+                    dLF = new DiffList_TextFile(targetFile);
+                }
+            }
+            catch (Exception ex)
+            {
+                ErrorDialog.Show(ex);
+                return;
+            }
+            finally
+            {
+                try { File.Delete(sourceFile); }
+                catch { }
+                try { File.Delete(targetFile); }
+                catch { }
+            }
+
+            try
+            {
+                double time = 0;
+                DiffEngine de = new DiffEngine();
+                time = de.ProcessDiff(sLF, dLF, DiffEngineLevel.SlowPerfect);
+
+                ArrayList rep = de.DiffReport();
+                TextDiffView dlg = new TextDiffView(sLF, dLF, rep, time);
+                dlg.ShowDialog();
+                dlg.Dispose();
+            }
+            catch (Exception ex)
+            {
+                this.Cursor = Cursors.Default;
+                string tmp = string.Format("{0}{1}{1}***STACK***{1}{2}",
+                    ex.Message,
+                    Environment.NewLine,
+                    ex.StackTrace);
+                MessageBox.Show(tmp, "Compare Error");
+                return;
+            }
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.resx
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.resx	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Base/UI/DirtyStateConfirmationDialog.resx	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="lblConfirm.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+    <value>Top, Left, Right</value>
+  </data>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="lblConfirm.Location" type="System.Drawing.Point, System.Drawing">
+    <value>13, 9</value>
+  </data>
+  <data name="lblConfirm.Size" type="System.Drawing.Size, System.Drawing">
+    <value>398, 86</value>
+  </data>
+  <assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="lblConfirm.TabIndex" type="System.Int32, mscorlib">
+    <value>0</value>
+  </data>
+  <data name="lblConfirm.Text" xml:space="preserve">
+    <value>This resource {0} has unsaved changes. Close and discard these changes?</value>
+  </data>
+  <data name="&gt;&gt;lblConfirm.Name" xml:space="preserve">
+    <value>lblConfirm</value>
+  </data>
+  <data name="&gt;&gt;lblConfirm.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;lblConfirm.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;lblConfirm.ZOrder" xml:space="preserve">
+    <value>3</value>
+  </data>
+  <data name="btnYes.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+    <value>Bottom, Left</value>
+  </data>
+  <data name="btnYes.Location" type="System.Drawing.Point, System.Drawing">
+    <value>94, 98</value>
+  </data>
+  <data name="btnYes.Size" type="System.Drawing.Size, System.Drawing">
+    <value>75, 23</value>
+  </data>
+  <data name="btnYes.TabIndex" type="System.Int32, mscorlib">
+    <value>1</value>
+  </data>
+  <data name="btnYes.Text" xml:space="preserve">
+    <value>Yes</value>
+  </data>
+  <data name="&gt;&gt;btnYes.Name" xml:space="preserve">
+    <value>btnYes</value>
+  </data>
+  <data name="&gt;&gt;btnYes.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;btnYes.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;btnYes.ZOrder" xml:space="preserve">
+    <value>2</value>
+  </data>
+  <data name="btnNo.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+    <value>Bottom, Left</value>
+  </data>
+  <data name="btnNo.Location" type="System.Drawing.Point, System.Drawing">
+    <value>175, 98</value>
+  </data>
+  <data name="btnNo.Size" type="System.Drawing.Size, System.Drawing">
+    <value>75, 23</value>
+  </data>
+  <data name="btnNo.TabIndex" type="System.Int32, mscorlib">
+    <value>2</value>
+  </data>
+  <data name="btnNo.Text" xml:space="preserve">
+    <value>No</value>
+  </data>
+  <data name="&gt;&gt;btnNo.Name" xml:space="preserve">
+    <value>btnNo</value>
+  </data>
+  <data name="&gt;&gt;btnNo.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;btnNo.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;btnNo.ZOrder" xml:space="preserve">
+    <value>1</value>
+  </data>
+  <data name="btnDiff.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+    <value>Bottom, Left</value>
+  </data>
+  <data name="btnDiff.Location" type="System.Drawing.Point, System.Drawing">
+    <value>256, 98</value>
+  </data>
+  <data name="btnDiff.Size" type="System.Drawing.Size, System.Drawing">
+    <value>75, 23</value>
+  </data>
+  <data name="btnDiff.TabIndex" type="System.Int32, mscorlib">
+    <value>3</value>
+  </data>
+  <data name="btnDiff.Text" xml:space="preserve">
+    <value>View Diff</value>
+  </data>
+  <data name="&gt;&gt;btnDiff.Name" xml:space="preserve">
+    <value>btnDiff</value>
+  </data>
+  <data name="&gt;&gt;btnDiff.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;btnDiff.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;btnDiff.ZOrder" xml:space="preserve">
+    <value>0</value>
+  </data>
+  <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
+    <value>423, 132</value>
+  </data>
+  <data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
+    <value>CenterParent</value>
+  </data>
+  <data name="$this.Text" xml:space="preserve">
+    <value>Unsaved Resource</value>
+  </data>
+  <data name="&gt;&gt;$this.Name" xml:space="preserve">
+    <value>DirtyStateConfirmationDialog</value>
+  </data>
+  <data name="&gt;&gt;$this.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+</root>
\ No newline at end of file

Modified: trunk/Tools/Maestro/Maestro.Base/UI/ProfilingDialog.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/UI/ProfilingDialog.cs	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/Maestro.Base/UI/ProfilingDialog.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -141,7 +141,7 @@
                     var map = mpsvc.CreateMap(mdef);
                     using (new Timer(Properties.Resources.Prof_LogMessageIdentifyFetching, backgroundWorker))
                     {
-                        var rtl = map.GetLayerByName("Test Layer");
+                    	var rtl = map.Layers["Test Layer"];
                         rtl.Visible = true;
                         rtl.Selectable = true;
                     }

Added: trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.Designer.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.Designer.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.Designer.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,108 @@
+namespace Maestro.Editors.Diff
+{
+    partial class TextDiffView
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TextDiffView));
+            this.lvDestination = new System.Windows.Forms.ListView();
+            this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+            this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+            this.lvSource = new System.Windows.Forms.ListView();
+            this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+            this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+            this.SuspendLayout();
+            // 
+            // lvDestination
+            // 
+            this.lvDestination.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+            this.columnHeader3,
+            this.columnHeader4});
+            resources.ApplyResources(this.lvDestination, "lvDestination");
+            this.lvDestination.FullRowSelect = true;
+            this.lvDestination.HideSelection = false;
+            this.lvDestination.MultiSelect = false;
+            this.lvDestination.Name = "lvDestination";
+            this.lvDestination.UseCompatibleStateImageBehavior = false;
+            this.lvDestination.View = System.Windows.Forms.View.Details;
+            this.lvDestination.SelectedIndexChanged += new System.EventHandler(this.lvSource_SelectedIndexChanged);
+            this.lvDestination.Resize += new System.EventHandler(this.lvDestination_Resize);
+            // 
+            // columnHeader3
+            // 
+            resources.ApplyResources(this.columnHeader3, "columnHeader3");
+            // 
+            // columnHeader4
+            // 
+            resources.ApplyResources(this.columnHeader4, "columnHeader4");
+            // 
+            // lvSource
+            // 
+            this.lvSource.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+            this.columnHeader1,
+            this.columnHeader2});
+            resources.ApplyResources(this.lvSource, "lvSource");
+            this.lvSource.FullRowSelect = true;
+            this.lvSource.HideSelection = false;
+            this.lvSource.MultiSelect = false;
+            this.lvSource.Name = "lvSource";
+            this.lvSource.UseCompatibleStateImageBehavior = false;
+            this.lvSource.View = System.Windows.Forms.View.Details;
+            this.lvSource.SelectedIndexChanged += new System.EventHandler(this.lvSource_SelectedIndexChanged);
+            this.lvSource.Resize += new System.EventHandler(this.lvSource_Resize);
+            // 
+            // columnHeader1
+            // 
+            resources.ApplyResources(this.columnHeader1, "columnHeader1");
+            // 
+            // columnHeader2
+            // 
+            resources.ApplyResources(this.columnHeader2, "columnHeader2");
+            // 
+            // TextDiffView
+            // 
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
+            resources.ApplyResources(this, "$this");
+            this.Controls.Add(this.lvDestination);
+            this.Controls.Add(this.lvSource);
+            this.Name = "TextDiffView";
+            this.Load += new System.EventHandler(this.Results_Load);
+            this.Resize += new System.EventHandler(this.Results_Resize);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.ListView lvDestination;
+        private System.Windows.Forms.ColumnHeader columnHeader3;
+        private System.Windows.Forms.ColumnHeader columnHeader4;
+        private System.Windows.Forms.ListView lvSource;
+        private System.Windows.Forms.ColumnHeader columnHeader1;
+        private System.Windows.Forms.ColumnHeader columnHeader2;
+    }
+}
\ No newline at end of file

Added: trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,180 @@
+#region Disclaimer / License
+// Copyright (C) 2012, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at 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
+// 
+
+// Original code by Michael Potter, made available under Public Domain
+//
+// http://www.codeproject.com/Articles/6943/A-Generic-Reusable-Diff-Algorithm-in-C-II/
+#endregion
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using OSGeo.MapGuide.MaestroAPI.Resource.Comparison;
+using System.Collections;
+
+namespace Maestro.Editors.Diff
+{
+    public partial class TextDiffView : Form
+    {
+        public TextDiffView()
+        {
+            InitializeComponent();
+        }
+
+        public TextDiffView(DiffList_TextFile source, DiffList_TextFile destination, ArrayList DiffLines, double seconds)
+            : this()
+        {
+            //this.Text = string.Format("Results: {0} secs.",seconds.ToString("#0.00"));
+
+            ListViewItem lviS;
+            ListViewItem lviD;
+            int cnt = 1;
+            int i;
+
+            foreach (DiffResultSpan drs in DiffLines)
+            {
+                switch (drs.Status)
+                {
+                    case DiffResultSpanStatus.DeleteSource:
+                        for (i = 0; i < drs.Length; i++)
+                        {
+                            lviS = new ListViewItem(cnt.ToString("00000"));
+                            lviD = new ListViewItem(cnt.ToString("00000"));
+                            lviS.BackColor = Color.Red;
+                            lviS.SubItems.Add(((TextLine)source.GetByIndex(drs.SourceIndex + i)).Line);
+                            lviD.BackColor = Color.LightGray;
+                            lviD.SubItems.Add("");
+
+                            lvSource.Items.Add(lviS);
+                            lvDestination.Items.Add(lviD);
+                            cnt++;
+                        }
+
+                        break;
+                    case DiffResultSpanStatus.NoChange:
+                        for (i = 0; i < drs.Length; i++)
+                        {
+                            lviS = new ListViewItem(cnt.ToString("00000"));
+                            lviD = new ListViewItem(cnt.ToString("00000"));
+                            lviS.BackColor = Color.White;
+                            lviS.SubItems.Add(((TextLine)source.GetByIndex(drs.SourceIndex + i)).Line);
+                            lviD.BackColor = Color.White;
+                            lviD.SubItems.Add(((TextLine)destination.GetByIndex(drs.DestIndex + i)).Line);
+
+                            lvSource.Items.Add(lviS);
+                            lvDestination.Items.Add(lviD);
+                            cnt++;
+                        }
+
+                        break;
+                    case DiffResultSpanStatus.AddDestination:
+                        for (i = 0; i < drs.Length; i++)
+                        {
+                            lviS = new ListViewItem(cnt.ToString("00000"));
+                            lviD = new ListViewItem(cnt.ToString("00000"));
+                            lviS.BackColor = Color.LightGray;
+                            lviS.SubItems.Add("");
+                            lviD.BackColor = Color.LightGreen;
+                            lviD.SubItems.Add(((TextLine)destination.GetByIndex(drs.DestIndex + i)).Line);
+
+                            lvSource.Items.Add(lviS);
+                            lvDestination.Items.Add(lviD);
+                            cnt++;
+                        }
+
+                        break;
+                    case DiffResultSpanStatus.Replace:
+                        for (i = 0; i < drs.Length; i++)
+                        {
+                            lviS = new ListViewItem(cnt.ToString("00000"));
+                            lviD = new ListViewItem(cnt.ToString("00000"));
+                            lviS.BackColor = Color.Red;
+                            lviS.SubItems.Add(((TextLine)source.GetByIndex(drs.SourceIndex + i)).Line);
+                            lviD.BackColor = Color.LightGreen;
+                            lviD.SubItems.Add(((TextLine)destination.GetByIndex(drs.DestIndex + i)).Line);
+
+                            lvSource.Items.Add(lviS);
+                            lvDestination.Items.Add(lviD);
+                            cnt++;
+                        }
+
+                        break;
+                }
+
+            }
+        }
+
+        private void lvSource_Resize(object sender, System.EventArgs e)
+        {
+            if (lvSource.Width > 100)
+            {
+                lvSource.Columns[1].Width = -2;
+            }
+        }
+
+        private void lvDestination_Resize(object sender, System.EventArgs e)
+        {
+            if (lvDestination.Width > 100)
+            {
+                lvDestination.Columns[1].Width = -2;
+            }
+        }
+
+        private void Results_Resize(object sender, System.EventArgs e)
+        {
+            int w = this.ClientRectangle.Width / 2;
+            lvSource.Location = new Point(0, 0);
+            lvSource.Width = w;
+            lvSource.Height = this.ClientRectangle.Height;
+
+            lvDestination.Location = new Point(w + 1, 0);
+            lvDestination.Width = this.ClientRectangle.Width - (w + 1);
+            lvDestination.Height = this.ClientRectangle.Height;
+        }
+
+        private void Results_Load(object sender, System.EventArgs e)
+        {
+            Results_Resize(sender, e);
+        }
+
+        private void lvSource_SelectedIndexChanged(object sender, System.EventArgs e)
+        {
+            if (lvSource.SelectedItems.Count > 0)
+            {
+                ListViewItem lvi = lvDestination.Items[lvSource.SelectedItems[0].Index];
+                lvi.Selected = true;
+                lvi.EnsureVisible();
+            }
+        }
+
+        private void lvDestination_SelectedIndexChanged(object sender, System.EventArgs e)
+        {
+            if (lvDestination.SelectedItems.Count > 0)
+            {
+                ListViewItem lvi = lvSource.Items[lvDestination.SelectedItems[0].Index];
+                lvi.Selected = true;
+                lvi.EnsureVisible();
+            }
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.resx
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.resx	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Diff/TextDiffView.resx	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="columnHeader3.Text" xml:space="preserve">
+    <value>Line</value>
+  </data>
+  <assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="columnHeader3.Width" type="System.Int32, mscorlib">
+    <value>50</value>
+  </data>
+  <data name="columnHeader4.Text" xml:space="preserve">
+    <value>Text (Destination)</value>
+  </data>
+  <data name="columnHeader4.Width" type="System.Int32, mscorlib">
+    <value>198</value>
+  </data>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="lvDestination.Font" type="System.Drawing.Font, System.Drawing">
+    <value>Courier New, 8.25pt</value>
+  </data>
+  <data name="lvDestination.Location" type="System.Drawing.Point, System.Drawing">
+    <value>155, 76</value>
+  </data>
+  <data name="lvDestination.Size" type="System.Drawing.Size, System.Drawing">
+    <value>123, 110</value>
+  </data>
+  <data name="lvDestination.TabIndex" type="System.Int32, mscorlib">
+    <value>4</value>
+  </data>
+  <data name="&gt;&gt;lvDestination.Name" xml:space="preserve">
+    <value>lvDestination</value>
+  </data>
+  <data name="&gt;&gt;lvDestination.Type" xml:space="preserve">
+    <value>System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;lvDestination.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;lvDestination.ZOrder" xml:space="preserve">
+    <value>0</value>
+  </data>
+  <data name="columnHeader1.Text" xml:space="preserve">
+    <value>Line</value>
+  </data>
+  <data name="columnHeader1.Width" type="System.Int32, mscorlib">
+    <value>50</value>
+  </data>
+  <data name="columnHeader2.Text" xml:space="preserve">
+    <value>Text (Source)</value>
+  </data>
+  <data name="columnHeader2.Width" type="System.Int32, mscorlib">
+    <value>147</value>
+  </data>
+  <data name="lvSource.Font" type="System.Drawing.Font, System.Drawing">
+    <value>Courier New, 8.25pt</value>
+  </data>
+  <data name="lvSource.Location" type="System.Drawing.Point, System.Drawing">
+    <value>7, 78</value>
+  </data>
+  <data name="lvSource.Size" type="System.Drawing.Size, System.Drawing">
+    <value>114, 102</value>
+  </data>
+  <data name="lvSource.TabIndex" type="System.Int32, mscorlib">
+    <value>3</value>
+  </data>
+  <data name="&gt;&gt;lvSource.Name" xml:space="preserve">
+    <value>lvSource</value>
+  </data>
+  <data name="&gt;&gt;lvSource.Type" xml:space="preserve">
+    <value>System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;lvSource.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;lvSource.ZOrder" xml:space="preserve">
+    <value>1</value>
+  </data>
+  <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
+    <value>784, 562</value>
+  </data>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
+    <value>CenterParent</value>
+  </data>
+  <data name="$this.Text" xml:space="preserve">
+    <value>Diff</value>
+  </data>
+  <data name="&gt;&gt;columnHeader3.Name" xml:space="preserve">
+    <value>columnHeader3</value>
+  </data>
+  <data name="&gt;&gt;columnHeader3.Type" xml:space="preserve">
+    <value>System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;columnHeader4.Name" xml:space="preserve">
+    <value>columnHeader4</value>
+  </data>
+  <data name="&gt;&gt;columnHeader4.Type" xml:space="preserve">
+    <value>System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;columnHeader1.Name" xml:space="preserve">
+    <value>columnHeader1</value>
+  </data>
+  <data name="&gt;&gt;columnHeader1.Type" xml:space="preserve">
+    <value>System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;columnHeader2.Name" xml:space="preserve">
+    <value>columnHeader2</value>
+  </data>
+  <data name="&gt;&gt;columnHeader2.Type" xml:space="preserve">
+    <value>System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;$this.Name" xml:space="preserve">
+    <value>TextDiffView</value>
+  </data>
+  <data name="&gt;&gt;$this.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+</root>
\ No newline at end of file

Modified: trunk/Tools/Maestro/Maestro.Editors/Maestro.Editors.csproj
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Maestro.Editors.csproj	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/Maestro.Editors/Maestro.Editors.csproj	2012-02-12 10:40:54 UTC (rev 6499)
@@ -164,6 +164,12 @@
     <Compile Include="Diagnostics\ServerStatusMonitor.designer.cs">
       <DependentUpon>ServerStatusMonitor.cs</DependentUpon>
     </Compile>
+    <Compile Include="Diff\TextDiffView.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Diff\TextDiffView.Designer.cs">
+      <DependentUpon>TextDiffView.cs</DependentUpon>
+    </Compile>
     <Compile Include="DrawingSource\DrawingSourceEditorCtrl.cs">
       <SubType>UserControl</SubType>
     </Compile>
@@ -1244,6 +1250,9 @@
     <EmbeddedResource Include="Diagnostics\ServerStatusMonitor.resx">
       <DependentUpon>ServerStatusMonitor.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="Diff\TextDiffView.resx">
+      <DependentUpon>TextDiffView.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="DrawingSource\DrawingSourceEditorCtrl.resx">
       <DependentUpon>DrawingSourceEditorCtrl.cs</DependentUpon>
       <SubType>Designer</SubType>

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj	2012-02-12 04:16:13 UTC (rev 6498)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj	2012-02-12 10:40:54 UTC (rev 6499)
@@ -252,6 +252,10 @@
     <Compile Include="ObjectModels\NsDoc.cs" />
     <Compile Include="ObjectModels\SymbolDefFactory.cs" />
     <Compile Include="ObjectModels\WatermarkInterfaces.cs" />
+    <Compile Include="Resource\Comparison\BinaryData.cs" />
+    <Compile Include="Resource\Comparison\CharData.cs" />
+    <Compile Include="Resource\Comparison\DiffEngine.cs" />
+    <Compile Include="Resource\Comparison\TextFile.cs" />
     <Compile Include="Resource\Conversion\NsDoc.cs" />
     <Compile Include="Resource\NsDoc.cs" />
     <Compile Include="Resource\Validation\BaseMapDefinitionValidator.cs" />
@@ -532,6 +536,7 @@
       <Install>true</Install>
     </BootstrapperPackage>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/BinaryData.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/BinaryData.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/BinaryData.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,72 @@
+#region Disclaimer / License
+// Copyright (C) 2012, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at 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
+// 
+
+// Original code by Michael Potter, made available under Public Domain
+//
+// http://www.codeproject.com/Articles/6943/A-Generic-Reusable-Diff-Algorithm-in-C-II/
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace OSGeo.MapGuide.MaestroAPI.Resource.Comparison
+{
+    public class DiffList_BinaryFile : IDiffList
+    {
+        private byte[] _byteList;
+
+        public DiffList_BinaryFile(string fileName)
+        {
+            FileStream fs = null;
+            BinaryReader br = null;
+            try
+            {
+                fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
+                int len = (int)fs.Length;
+                br = new BinaryReader(fs);
+                _byteList = br.ReadBytes(len);
+            }
+            catch (Exception ex)
+            {
+                throw ex;
+            }
+            finally
+            {
+                if (br != null) br.Close();
+                if (fs != null) fs.Close();
+            }
+
+        }
+        #region IDiffList Members
+
+        public int Count()
+        {
+            return _byteList.Length;
+        }
+
+        public IComparable GetByIndex(int index)
+        {
+            return _byteList[index];
+        }
+
+        #endregion
+    }
+}

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/CharData.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/CharData.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/CharData.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,53 @@
+#region Disclaimer / License
+// Copyright (C) 2012, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at 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
+// 
+
+// Original code by Michael Potter, made available under Public Domain
+//
+// http://www.codeproject.com/Articles/6943/A-Generic-Reusable-Diff-Algorithm-in-C-II/
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OSGeo.MapGuide.MaestroAPI.Resource.Comparison
+{
+    public class DiffList_CharData : IDiffList
+    {
+        private char[] _charList;
+
+        public DiffList_CharData(string charData)
+        {
+            _charList = charData.ToCharArray();
+        }
+        #region IDiffList Members
+
+        public int Count()
+        {
+            return _charList.Length;
+        }
+
+        public IComparable GetByIndex(int index)
+        {
+            return _charList[index];
+        }
+
+        #endregion
+    }
+}

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/DiffEngine.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/DiffEngine.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/DiffEngine.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,558 @@
+#region Disclaimer / License
+// Copyright (C) 2012, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at 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
+// 
+
+// Original code by Michael Potter, made available under Public Domain
+//
+// http://www.codeproject.com/Articles/6943/A-Generic-Reusable-Diff-Algorithm-in-C-II/
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Text;
+using System.Collections;
+
+namespace OSGeo.MapGuide.MaestroAPI.Resource.Comparison
+{
+    public interface IDiffList
+    {
+        int Count();
+        IComparable GetByIndex(int index);
+    }
+
+    internal enum DiffStatus
+    {
+        Matched = 1,
+        NoMatch = -1,
+        Unknown = -2
+
+    }
+
+    internal class DiffState
+    {
+        private const int BAD_INDEX = -1;
+        private int _startIndex;
+        private int _length;
+
+        public int StartIndex { get { return _startIndex; } }
+        public int EndIndex { get { return ((_startIndex + _length) - 1); } }
+        public int Length
+        {
+            get
+            {
+                int len;
+                if (_length > 0)
+                {
+                    len = _length;
+                }
+                else
+                {
+                    if (_length == 0)
+                    {
+                        len = 1;
+                    }
+                    else
+                    {
+                        len = 0;
+                    }
+                }
+                return len;
+            }
+        }
+        public DiffStatus Status
+        {
+            get
+            {
+                DiffStatus stat;
+                if (_length > 0)
+                {
+                    stat = DiffStatus.Matched;
+                }
+                else
+                {
+                    switch (_length)
+                    {
+                        case -1:
+                            stat = DiffStatus.NoMatch;
+                            break;
+                        default:
+                            System.Diagnostics.Debug.Assert(_length == -2, "Invalid status: _length < -2");
+                            stat = DiffStatus.Unknown;
+                            break;
+                    }
+                }
+                return stat;
+            }
+        }
+
+        public DiffState()
+        {
+            SetToUnkown();
+        }
+
+        protected void SetToUnkown()
+        {
+            _startIndex = BAD_INDEX;
+            _length = (int)DiffStatus.Unknown;
+        }
+
+        public void SetMatch(int start, int length)
+        {
+            System.Diagnostics.Debug.Assert(length > 0, "Length must be greater than zero");
+            System.Diagnostics.Debug.Assert(start >= 0, "Start must be greater than or equal to zero");
+            _startIndex = start;
+            _length = length;
+        }
+
+        public void SetNoMatch()
+        {
+            _startIndex = BAD_INDEX;
+            _length = (int)DiffStatus.NoMatch;
+        }
+
+
+        public bool HasValidLength(int newStart, int newEnd, int maxPossibleDestLength)
+        {
+            if (_length > 0) //have unlocked match
+            {
+                if ((maxPossibleDestLength < _length) ||
+                    ((_startIndex < newStart) || (EndIndex > newEnd)))
+                {
+                    SetToUnkown();
+                }
+            }
+            return (_length != (int)DiffStatus.Unknown);
+        }
+    }
+
+    internal class DiffStateList
+    {
+#if USE_HASH_TABLE
+		private Hashtable _table;
+#else
+        private DiffState[] _array;
+#endif
+        public DiffStateList(int destCount)
+        {
+#if USE_HASH_TABLE
+			_table = new Hashtable(Math.Max(9,destCount/10));
+#else
+            _array = new DiffState[destCount];
+#endif
+        }
+
+        public DiffState GetByIndex(int index)
+        {
+#if USE_HASH_TABLE
+			DiffState retval = (DiffState)_table[index];
+			if (retval == null)
+			{
+				retval = new DiffState();
+				_table.Add(index,retval);
+			}
+#else
+            DiffState retval = _array[index];
+            if (retval == null)
+            {
+                retval = new DiffState();
+                _array[index] = retval;
+            }
+#endif
+            return retval;
+        }
+    }
+
+
+    public enum DiffResultSpanStatus
+    {
+        NoChange,
+        Replace,
+        DeleteSource,
+        AddDestination
+    }
+
+    public class DiffResultSpan : IComparable
+    {
+        private const int BAD_INDEX = -1;
+        private int _destIndex;
+        private int _sourceIndex;
+        private int _length;
+        private DiffResultSpanStatus _status;
+
+        public int DestIndex { get { return _destIndex; } }
+        public int SourceIndex { get { return _sourceIndex; } }
+        public int Length { get { return _length; } }
+        public DiffResultSpanStatus Status { get { return _status; } }
+
+        protected DiffResultSpan(
+            DiffResultSpanStatus status,
+            int destIndex,
+            int sourceIndex,
+            int length)
+        {
+            _status = status;
+            _destIndex = destIndex;
+            _sourceIndex = sourceIndex;
+            _length = length;
+        }
+
+        public static DiffResultSpan CreateNoChange(int destIndex, int sourceIndex, int length)
+        {
+            return new DiffResultSpan(DiffResultSpanStatus.NoChange, destIndex, sourceIndex, length);
+        }
+
+        public static DiffResultSpan CreateReplace(int destIndex, int sourceIndex, int length)
+        {
+            return new DiffResultSpan(DiffResultSpanStatus.Replace, destIndex, sourceIndex, length);
+        }
+
+        public static DiffResultSpan CreateDeleteSource(int sourceIndex, int length)
+        {
+            return new DiffResultSpan(DiffResultSpanStatus.DeleteSource, BAD_INDEX, sourceIndex, length);
+        }
+
+        public static DiffResultSpan CreateAddDestination(int destIndex, int length)
+        {
+            return new DiffResultSpan(DiffResultSpanStatus.AddDestination, destIndex, BAD_INDEX, length);
+        }
+
+        public void AddLength(int i)
+        {
+            _length += i;
+        }
+
+        public override string ToString()
+        {
+            return string.Format("{0} (Dest: {1},Source: {2}) {3}",
+                _status.ToString(),
+                _destIndex.ToString(),
+                _sourceIndex.ToString(),
+                _length.ToString());
+        }
+        #region IComparable Members
+
+        public int CompareTo(object obj)
+        {
+            return _destIndex.CompareTo(((DiffResultSpan)obj)._destIndex);
+        }
+
+        #endregion
+    }
+
+    public enum DiffEngineLevel
+    {
+        FastImperfect,
+        Medium,
+        SlowPerfect
+    }
+
+    public class DiffEngine
+    {
+        private IDiffList _source;
+        private IDiffList _dest;
+        private ArrayList _matchList;
+
+        private DiffEngineLevel _level;
+
+        private DiffStateList _stateList;
+
+        public DiffEngine()
+        {
+            _source = null;
+            _dest = null;
+            _matchList = null;
+            _stateList = null;
+            _level = DiffEngineLevel.FastImperfect;
+        }
+
+        private int GetSourceMatchLength(int destIndex, int sourceIndex, int maxLength)
+        {
+            int matchCount;
+            for (matchCount = 0; matchCount < maxLength; matchCount++)
+            {
+                if (_dest.GetByIndex(destIndex + matchCount).CompareTo(_source.GetByIndex(sourceIndex + matchCount)) != 0)
+                {
+                    break;
+                }
+            }
+            return matchCount;
+        }
+
+        private void GetLongestSourceMatch(DiffState curItem, int destIndex, int destEnd, int sourceStart, int sourceEnd)
+        {
+
+            int maxDestLength = (destEnd - destIndex) + 1;
+            int curLength = 0;
+            int curBestLength = 0;
+            int curBestIndex = -1;
+            int maxLength = 0;
+            for (int sourceIndex = sourceStart; sourceIndex <= sourceEnd; sourceIndex++)
+            {
+                maxLength = Math.Min(maxDestLength, (sourceEnd - sourceIndex) + 1);
+                if (maxLength <= curBestLength)
+                {
+                    //No chance to find a longer one any more
+                    break;
+                }
+                curLength = GetSourceMatchLength(destIndex, sourceIndex, maxLength);
+                if (curLength > curBestLength)
+                {
+                    //This is the best match so far
+                    curBestIndex = sourceIndex;
+                    curBestLength = curLength;
+                }
+                //jump over the match
+                sourceIndex += curBestLength;
+            }
+            //DiffState cur = _stateList.GetByIndex(destIndex);
+            if (curBestIndex == -1)
+            {
+                curItem.SetNoMatch();
+            }
+            else
+            {
+                curItem.SetMatch(curBestIndex, curBestLength);
+            }
+
+        }
+
+        private void ProcessRange(int destStart, int destEnd, int sourceStart, int sourceEnd)
+        {
+            int curBestIndex = -1;
+            int curBestLength = -1;
+            int maxPossibleDestLength = 0;
+            DiffState curItem = null;
+            DiffState bestItem = null;
+            for (int destIndex = destStart; destIndex <= destEnd; destIndex++)
+            {
+                maxPossibleDestLength = (destEnd - destIndex) + 1;
+                if (maxPossibleDestLength <= curBestLength)
+                {
+                    //we won't find a longer one even if we looked
+                    break;
+                }
+                curItem = _stateList.GetByIndex(destIndex);
+
+                if (!curItem.HasValidLength(sourceStart, sourceEnd, maxPossibleDestLength))
+                {
+                    //recalc new best length since it isn't valid or has never been done.
+                    GetLongestSourceMatch(curItem, destIndex, destEnd, sourceStart, sourceEnd);
+                }
+                if (curItem.Status == DiffStatus.Matched)
+                {
+                    switch (_level)
+                    {
+                        case DiffEngineLevel.FastImperfect:
+                            if (curItem.Length > curBestLength)
+                            {
+                                //this is longest match so far
+                                curBestIndex = destIndex;
+                                curBestLength = curItem.Length;
+                                bestItem = curItem;
+                            }
+                            //Jump over the match 
+                            destIndex += curItem.Length - 1;
+                            break;
+                        case DiffEngineLevel.Medium:
+                            if (curItem.Length > curBestLength)
+                            {
+                                //this is longest match so far
+                                curBestIndex = destIndex;
+                                curBestLength = curItem.Length;
+                                bestItem = curItem;
+                                //Jump over the match 
+                                destIndex += curItem.Length - 1;
+                            }
+                            break;
+                        default:
+                            if (curItem.Length > curBestLength)
+                            {
+                                //this is longest match so far
+                                curBestIndex = destIndex;
+                                curBestLength = curItem.Length;
+                                bestItem = curItem;
+                            }
+                            break;
+                    }
+                }
+            }
+            if (curBestIndex < 0)
+            {
+                //we are done - there are no matches in this span
+            }
+            else
+            {
+
+                int sourceIndex = bestItem.StartIndex;
+                _matchList.Add(DiffResultSpan.CreateNoChange(curBestIndex, sourceIndex, curBestLength));
+                if (destStart < curBestIndex)
+                {
+                    //Still have more lower destination data
+                    if (sourceStart < sourceIndex)
+                    {
+                        //Still have more lower source data
+                        // Recursive call to process lower indexes
+                        ProcessRange(destStart, curBestIndex - 1, sourceStart, sourceIndex - 1);
+                    }
+                }
+                int upperDestStart = curBestIndex + curBestLength;
+                int upperSourceStart = sourceIndex + curBestLength;
+                if (destEnd > upperDestStart)
+                {
+                    //we still have more upper dest data
+                    if (sourceEnd > upperSourceStart)
+                    {
+                        //set still have more upper source data
+                        // Recursive call to process upper indexes
+                        ProcessRange(upperDestStart, destEnd, upperSourceStart, sourceEnd);
+                    }
+                }
+            }
+        }
+
+        public double ProcessDiff(IDiffList source, IDiffList destination, DiffEngineLevel level)
+        {
+            _level = level;
+            return ProcessDiff(source, destination);
+        }
+
+        public double ProcessDiff(IDiffList source, IDiffList destination)
+        {
+            DateTime dt = DateTime.Now;
+            _source = source;
+            _dest = destination;
+            _matchList = new ArrayList();
+
+            int dcount = _dest.Count();
+            int scount = _source.Count();
+
+
+            if ((dcount > 0) && (scount > 0))
+            {
+                _stateList = new DiffStateList(dcount);
+                ProcessRange(0, dcount - 1, 0, scount - 1);
+            }
+
+            TimeSpan ts = DateTime.Now - dt;
+            return ts.TotalSeconds;
+        }
+
+
+        private bool AddChanges(
+            ArrayList report,
+            int curDest,
+            int nextDest,
+            int curSource,
+            int nextSource)
+        {
+            bool retval = false;
+            int diffDest = nextDest - curDest;
+            int diffSource = nextSource - curSource;
+            int minDiff = 0;
+            if (diffDest > 0)
+            {
+                if (diffSource > 0)
+                {
+                    minDiff = Math.Min(diffDest, diffSource);
+                    report.Add(DiffResultSpan.CreateReplace(curDest, curSource, minDiff));
+                    if (diffDest > diffSource)
+                    {
+                        curDest += minDiff;
+                        report.Add(DiffResultSpan.CreateAddDestination(curDest, diffDest - diffSource));
+                    }
+                    else
+                    {
+                        if (diffSource > diffDest)
+                        {
+                            curSource += minDiff;
+                            report.Add(DiffResultSpan.CreateDeleteSource(curSource, diffSource - diffDest));
+                        }
+                    }
+                }
+                else
+                {
+                    report.Add(DiffResultSpan.CreateAddDestination(curDest, diffDest));
+                }
+                retval = true;
+            }
+            else
+            {
+                if (diffSource > 0)
+                {
+                    report.Add(DiffResultSpan.CreateDeleteSource(curSource, diffSource));
+                    retval = true;
+                }
+            }
+            return retval;
+        }
+
+        public ArrayList DiffReport()
+        {
+            ArrayList retval = new ArrayList();
+            int dcount = _dest.Count();
+            int scount = _source.Count();
+
+            //Deal with the special case of empty files
+            if (dcount == 0)
+            {
+                if (scount > 0)
+                {
+                    retval.Add(DiffResultSpan.CreateDeleteSource(0, scount));
+                }
+                return retval;
+            }
+            else
+            {
+                if (scount == 0)
+                {
+                    retval.Add(DiffResultSpan.CreateAddDestination(0, dcount));
+                    return retval;
+                }
+            }
+
+
+            _matchList.Sort();
+            int curDest = 0;
+            int curSource = 0;
+            DiffResultSpan last = null;
+
+            //Process each match record
+            foreach (DiffResultSpan drs in _matchList)
+            {
+                if ((!AddChanges(retval, curDest, drs.DestIndex, curSource, drs.SourceIndex)) &&
+                    (last != null))
+                {
+                    last.AddLength(drs.Length);
+                }
+                else
+                {
+                    retval.Add(drs);
+                }
+                curDest = drs.DestIndex + drs.Length;
+                curSource = drs.SourceIndex + drs.Length;
+                last = drs;
+            }
+
+            //Process any tail end data
+            AddChanges(retval, curDest, dcount, curSource, scount);
+
+            return retval;
+        }
+    }
+}

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/TextFile.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/TextFile.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Comparison/TextFile.cs	2012-02-12 10:40:54 UTC (rev 6499)
@@ -0,0 +1,94 @@
+#region Disclaimer / License
+// Copyright (C) 2012, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at 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
+// 
+
+// Original code by Michael Potter, made available under Public Domain
+//
+// http://www.codeproject.com/Articles/6943/A-Generic-Reusable-Diff-Algorithm-in-C-II/
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections;
+using System.IO;
+
+namespace OSGeo.MapGuide.MaestroAPI.Resource.Comparison
+{
+    public class TextLine : IComparable
+    {
+        public string Line;
+        public int _hash;
+
+        public TextLine(string str)
+        {
+            Line = str.Replace("\t", "    ");
+            _hash = str.GetHashCode();
+        }
+        #region IComparable Members
+
+        public int CompareTo(object obj)
+        {
+            return _hash.CompareTo(((TextLine)obj)._hash);
+        }
+
+        #endregion
+    }
+
+
+    public class DiffList_TextFile : IDiffList
+    {
+        private const int MaxLineLength = 1024;
+        private ArrayList _lines;
+
+        public DiffList_TextFile(string fileName)
+        {
+            _lines = new ArrayList();
+            using (StreamReader sr = new StreamReader(fileName))
+            {
+                String line;
+                // Read and display lines from the file until the end of 
+                // the file is reached.
+                while ((line = sr.ReadLine()) != null)
+                {
+                    if (line.Length > MaxLineLength)
+                    {
+                        throw new InvalidOperationException(
+                            string.Format("File contains a line greater than {0} characters.",
+                            MaxLineLength.ToString()));
+                    }
+                    _lines.Add(new TextLine(line));
+                }
+            }
+        }
+        #region IDiffList Members
+
+        public int Count()
+        {
+            return _lines.Count;
+        }
+
+        public IComparable GetByIndex(int index)
+        {
+            return (TextLine)_lines[index];
+        }
+
+        #endregion
+
+    }
+}



More information about the mapguide-commits mailing list