[commit] r2097 - trunk/GME/CSGUI
GMESRC Repository Notifications
gme-commit at list.isis.vanderbilt.edu
Fri Nov 2 11:36:05 CDT 2012
Author: ksmyth
Date: Fri Nov 2 11:36:03 2012
New Revision: 2097
Log:
Use ReferenceSwitcher on drag-n-drop to reconnect refports based on name and kind
Added:
trunk/GME/CSGUI/GMEConsole.cs
trunk/GME/CSGUI/MgaGateway.cs
trunk/GME/CSGUI/ParentChain.cs
trunk/GME/CSGUI/ReferenceSwitcher.cs
Added: trunk/GME/CSGUI/GMEConsole.cs
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/GME/CSGUI/GMEConsole.cs Fri Nov 2 11:36:03 2012 (r2097)
@@ -0,0 +1,162 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using GME;
+
+namespace GME.CSharp
+{
+ /// <summary>
+ /// Automatically redirects console messages to the GME console output, if GME is available.
+ /// Otherwise prints the output to System console.
+ /// </summary>
+ public class GMEConsole
+ {
+
+ /// <summary>
+ /// The GME application variable
+ /// </summary>
+ public IGMEOLEApp gme = null;
+ private GMETextWriter error;
+ private GMETextWriter warning;
+ private GMETextWriter info;
+ private GMETextWriter normal;
+
+ public GMEConsole()
+ {
+ error = new GMETextWriter(msgtype_enum.MSG_ERROR, this);
+ warning = new GMETextWriter(msgtype_enum.MSG_WARNING, this);
+ info = new GMETextWriter(msgtype_enum.MSG_INFO, this);
+ normal = new GMETextWriter(msgtype_enum.MSG_NORMAL, this);
+ }
+
+ /// <summary>
+ /// Handles error messages
+ /// The message to be written. GME Console does not handle special characters and trims white-spaces.
+ /// Example: GMEConsole.Error.Write("RootFolder name error: {0}.", rf.Name);
+ /// If console is initialized, the message appears in GME console, if not, then in standard error.
+ /// If DEBUG is defined, it also appears in VS output window.
+ /// </summary>
+ public TextWriter Error
+ {
+ get { return error; }
+ }
+
+ /// <summary>
+ /// Prints messages.
+ /// The message to be written. GME Console does not handle special characters and trims white-spaces.
+ /// Example: GMEConsole.Out.Write("RootFolder name : {0}.", rf.Name);
+ /// </summary>
+ public TextWriter Out
+ {
+ get { return normal; }
+ }
+
+
+ /// <summary>
+ /// Prints warning messages.
+ /// The message to be written. GME Console does not handle special characters and trims white-spaces.
+ /// Example: GMEConsole.Warning.Write("RootFolder name is not changed : {0}.", rf.Name);
+ /// </summary>
+ public TextWriter Warning
+ {
+ get { return warning; }
+ }
+
+
+ /// <summary>
+ /// Proints info messages.
+ /// The message to be written. GME Console does not handle special characters and trims white-spaces.
+ /// Example: GMEConsole.Info.Write("RootFolder name is changed : {0}.", rf.Name);
+ /// </summary>
+ public TextWriter Info
+ {
+ get { return info; }
+ }
+
+ /// <summary>
+ /// Clear the console
+ /// </summary>
+ public void Clear()
+ {
+ if (gme != null)
+ gme.ConsoleClear();
+ else
+ System.Console.Clear();
+ }
+
+
+ public static GMEConsole CreateFromProject(GME.MGA.MgaProject project)
+ {
+ GMEConsole console = new GMEConsole();
+ try
+ {
+ // Initializing console
+ console.gme = (IGMEOLEApp)project.GetClientByName("GME.Application").OLEServer;
+ }
+ catch (System.Runtime.InteropServices.COMException ex)
+ {
+ // if GME is not present, the interpreter is called from standalone test application
+ if (ex.ErrorCode != -2023423888) // HResult 0x87650070: "Search by name failed"
+ {
+ throw;
+ }
+ console.gme = null;
+ }
+ return console;
+ }
+ }
+
+
+ public class GMETextWriter : System.IO.TextWriter
+ {
+ private msgtype_enum type;
+ private GMEConsole console;
+
+ public GMETextWriter(msgtype_enum type, GMEConsole console)
+ {
+ this.type = type;
+ this.console = console;
+ }
+
+ override public Encoding Encoding
+ {
+ get { return Encoding.Unicode; }
+ }
+
+ override public void WriteLine(string str)
+ {
+ Write(str + Environment.NewLine);
+ }
+
+ override public void Write(string str)
+ {
+ if (console.gme == null)
+ {
+ switch (type)
+ {
+ case msgtype_enum.MSG_NORMAL:
+ Console.Out.Write(str);
+ break;
+ case msgtype_enum.MSG_INFO:
+ Console.Out.Write("Information: " + str);
+ break;
+ case msgtype_enum.MSG_WARNING:
+ Console.Out.Write("Warning: " + str);
+ break;
+ case msgtype_enum.MSG_ERROR:
+ Console.Error.Write(str);
+#if(DEBUG)
+ System.Diagnostics.Debug.Write(str);
+#endif
+ break;
+ }
+ }
+ else
+ {
+ console.gme.ConsoleMessage(str, type);
+ }
+ }
+ }
+}
Added: trunk/GME/CSGUI/MgaGateway.cs
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/GME/CSGUI/MgaGateway.cs Fri Nov 2 11:36:03 2012 (r2097)
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using GME.MGA;
+using GME;
+using GME.MGA.Meta;
+using GME.MGA.Core;
+
+namespace GME.CSharp
+{
+ class MgaGateway
+ {
+ public MgaGateway(IMgaProject project)
+ {
+ this.project = project;
+ }
+
+ public IMgaProject project = null;
+ public IMgaTerritory territory = null;
+
+ #region TRANSACTION HANDLING
+ public void BeginTransaction(transactiontype_enum mode = transactiontype_enum.TRANSACTION_GENERAL)
+ {
+ project.BeginTransaction(territory, mode);
+ }
+
+ public void CommitTransaction()
+ {
+ if ((project.ProjectStatus & 8) != 0)
+ {
+ project.CommitTransaction();
+ }
+ }
+
+ public void AbortTransaction()
+ {
+ if ((project.ProjectStatus & 8) != 0)
+ {
+ project.AbortTransaction();
+ }
+ }
+
+ public delegate void voidDelegate();
+ public void PerformInTransaction(voidDelegate d, transactiontype_enum mode = transactiontype_enum.TRANSACTION_GENERAL)
+ {
+ BeginTransaction(mode);
+ try
+ {
+ d();
+ CommitTransaction();
+ }
+ finally
+ {
+ AbortTransaction();
+ }
+ }
+ #endregion
+ #region UTILITIES
+ public IMgaMetaBase GetMetaByName(string name)
+ {
+ try
+ {
+ return project.RootMeta.RootFolder.get_DefinedFCOByName(name, false) as MgaMetaFCO;
+ }
+#pragma warning disable 0168
+ catch (System.Runtime.InteropServices.COMException e)
+ {
+ return project.RootMeta.RootFolder.get_DefinedFolderByName(name, false) as MgaMetaFolder;
+ }
+#pragma warning restore 0168
+ }
+
+ #endregion
+
+
+ }
+}
Added: trunk/GME/CSGUI/ParentChain.cs
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/GME/CSGUI/ParentChain.cs Fri Nov 2 11:36:03 2012 (r2097)
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using GME.MGA;
+
+namespace CSGUI
+{
+ public class ParentChainEnumerator : IEnumerator<IMgaObject>
+ {
+ #region IEnumerator<IMgaObject> Members
+
+ IMgaObject original;
+ public ParentChainEnumerator(IMgaObject obj)
+ {
+ this.original = obj;
+ }
+ public IMgaObject Current { get; set; }
+
+ #endregion
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ }
+
+ #endregion
+
+ #region IEnumerator Members
+
+ object System.Collections.IEnumerator.Current
+ {
+ get { return Current; }
+ }
+
+ public bool MoveNext()
+ {
+ if (Current == null)
+ {
+ Current = original;
+ }
+ else
+ {
+ GME.MGA.Meta.objtype_enum objType;
+ GME.MGA.MgaObject o;
+ Current.GetParent(out o, out objType);
+ Current = o;
+ }
+ return Current != null;
+ }
+
+ public void Reset()
+ {
+ Current = null;
+ }
+
+ #endregion
+ }
+
+ public class ParentChain : IEnumerable<IMgaObject>
+ {
+ IMgaObject obj;
+ public ParentChain(IMgaObject obj)
+ {
+ this.obj = obj;
+ }
+ public IEnumerator<IMgaObject> GetEnumerator()
+ {
+ return new ParentChainEnumerator(obj);
+ }
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return new ParentChainEnumerator(obj);
+ }
+ }
+}
Added: trunk/GME/CSGUI/ReferenceSwitcher.cs
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/GME/CSGUI/ReferenceSwitcher.cs Fri Nov 2 11:36:03 2012 (r2097)
@@ -0,0 +1,386 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Windows.Forms;
+using GME.MGA.Core;
+using GME.CSharp;
+using GME;
+using GME.MGA;
+using System.Linq;
+
+namespace CSGUI
+{
+ /// <summary>
+ /// This class implements the necessary COM interfaces for a GME interpreter component.
+ /// </summary>
+ [Guid("0ACC000C-29E6-418B-9F8B-968418C533B9"),
+ ProgId("CSGUI.ReferenceSwitcher"),
+ ClassInterface(ClassInterfaceType.AutoDual)]
+ [ComVisible(true)]
+ public class ReferenceSwitcher
+ {
+ MgaGateway MgaGateway { get; set; }
+ GMEConsole GMEConsole { get; set; }
+
+ public void SwitchReferences(object[] lib1Objects, object[] lib2Objects)
+ {
+ Switcher switcher = new Switcher(lib1Objects.Cast<IMgaObject>(), lib2Objects.Cast<IMgaObject>(), null);
+ switcher.UpdateSublibrary();
+ }
+
+ public void PrintLine(Func<string, string, string> f, IMgaFCO a, IMgaFCO b)
+ {
+ Console.Out.WriteLine(f(Switcher.getPath(a), Switcher.getPath(b)));
+ }
+ public void SwitchReference(IMgaFCO to, IMgaReference @ref)
+ {
+ Switcher.MoveReferenceWithRefportConnections(to, @ref, PrintLine);
+ }
+ }
+
+ [ComVisible(false)]
+ public class Switcher
+ {
+ List<IMgaObject> lib1Objects;
+ List<IMgaObject> lib2Objects;
+ GMEConsole GMEConsole;
+
+ public Switcher(IMgaObject fco1Object, IMgaObject fco2Object, GMEConsole GMEConsole)
+ {
+ this.lib1Objects = new List<IMgaObject>() { fco1Object };
+ this.lib2Objects = new List<IMgaObject>() { fco2Object };
+ this.GMEConsole = GMEConsole;
+ }
+ public Switcher(IEnumerable<IMgaObject> fco1Object, IEnumerable<IMgaObject> fco2Object, GMEConsole GMEConsole)
+ {
+ this.lib1Objects = fco1Object.ToList();
+ this.lib2Objects = fco2Object.ToList();
+ this.GMEConsole = GMEConsole;
+ }
+
+ class ObjectPair
+ {
+ public IMgaObject o1 { get; set; }
+ public IMgaObject o2 { get; set; }
+ }
+
+ public void UpdateSublibrary()
+ {
+ int origPrefs = this.lib1Objects.First().Project.Preferences;
+ // Magic word allows us to remove ConnPoints
+ this.lib1Objects.First().Project.Preferences = origPrefs | (int)GME.MGA.preference_flags.MGAPREF_IGNORECONNCHECKS
+ | (int)GME.MGA.preference_flags.MGAPREF_FREEINSTANCEREFS;
+ try
+ {
+ IEnumerator<IMgaObject> lib2ObjectsEnum = lib2Objects.GetEnumerator();
+ foreach (IMgaObject lib1Object in lib1Objects)
+ {
+ lib2ObjectsEnum.MoveNext();
+ UpdateSublibrary(lib1Object, lib2ObjectsEnum.Current);
+ }
+ }
+ finally
+ {
+ lib1Objects.First().Project.Preferences = origPrefs;
+ }
+ }
+
+ private void UpdateSublibrary(IMgaObject fco1Objec, IMgaObject fco2Objec)
+ {
+ // fco2Object may be null
+ if (fco1Objec is IMgaFCO) // references only refer to FCOs
+ {
+ IMgaFCO fco1 = (IMgaFCO)fco1Objec;
+ IMgaFCO fco2 = fco2Objec as IMgaFCO;
+ foreach (IMgaFCO fco in fco1.ReferencedBy)
+ {
+ if (fco.IsInstance)
+ continue; // instance references will be updated by their archetype
+ // Don't update references in the old library
+ bool fcoInLib1Objects = false;
+ foreach (IMgaObject lib1Root in this.lib1Objects)
+ {
+ // FIXME: Contains(this.fco1Object) doesn't work
+ if (new ParentChain(fco).Contains(lib1Root, new MgaObjectEqualityComparor<IMgaObject>()))
+ {
+ fcoInLib1Objects = true;
+ }
+ }
+ if (fcoInLib1Objects)
+ continue;
+ IMgaReference refe = (IMgaReference)fco;
+ if (fco2 != null)
+ {
+ if (refe.UsedByConns.Count != 0)
+ {
+ if (refe.DerivedFrom == null)
+ {
+ try
+ {
+ MoveReferenceWithRefportConnections(fco2, refe, WriteLine);
+ }
+ catch (Exception e)
+ {
+ if (GMEConsole != null)
+ GMEConsole.Error.WriteLine("Could not set reference " + GetLink(refe, refe.Name));
+ throw new Exception("Could not set reference " + getPath(refe) +
+ " (" + refe.ID + ")", e);
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ bool setRef;
+ if (refe.DerivedFrom == null)
+ setRef = true;
+ else
+ {
+ short compareToBase;
+ refe.CompareToBase(out compareToBase);
+ setRef = compareToBase != 0;
+ }
+ if (setRef)
+ {
+ // FIXME: can this fail; should we handle it somehow?
+ refe.Referred = (GME.MGA.MgaFCO)fco2;
+ }
+ }
+ catch (Exception e)
+ {
+ if (GMEConsole != null)
+ GMEConsole.Error.WriteLine("Could not set reference " + GetLink(refe, refe.Name));
+ throw new Exception("Could not set reference " + getPath(refe) +
+ " (" + refe.ID + ")", e);
+ }
+ }
+ }
+ else
+ {
+ WriteLine((x, y) => "Couldn't update " + x + ": " + y + " has no counterpart", refe, fco1);
+ }
+ }
+ }
+
+ List<IMgaObject> fco1Children = getChildren(fco1Objec);
+ List<IMgaObject> fco2Children = getChildren(fco2Objec);
+ Dictionary<string, ObjectPair> dict = new Dictionary<string, ObjectPair>();
+ foreach (IMgaObject o in fco1Children)
+ {
+ dict.GetValueOrDefault(o.Name + "xxx ;xxx" + o.MetaBase.Name).o1 = o;
+ }
+ foreach (IMgaObject o in fco2Children)
+ {
+ dict.GetValueOrDefault(o.Name + "xxx ;xxx" + o.MetaBase.Name).o2 = o;
+ }
+ foreach (KeyValuePair<string, ObjectPair> entry in dict)
+ {
+ if (entry.Value.o1 != null)
+ {
+ UpdateSublibrary(entry.Value.o1, entry.Value.o2);
+ }
+ }
+ }
+
+
+ public delegate void WriteLineF(Func<string, string, string> f, IMgaFCO a, IMgaFCO b);
+ public void WriteLine(Func<string, string, string> f, IMgaFCO a, IMgaFCO b)
+ {
+ if (GMEConsole != null)
+ {
+ GMEConsole.Out.WriteLine(f(GetLink(a, a.Name), GetLink(b, b.Name)));
+ }
+ else
+ {
+ Console.Out.WriteLine(f(getPath(a), getPath(b)));
+ }
+ }
+
+ public static List<T> MakeList<T>(T itemOftype)
+ {
+ List<T> newList = new List<T>();
+ return newList;
+ }
+
+ /**
+ * First we disconnect all connections to refports, then move the reference, then reconnect
+ */
+ public static void MoveReferenceWithRefportConnections(IMgaFCO fco2, IMgaReference origref,
+ WriteLineF WriteLine)
+ {
+ Queue<IMgaReference> references = new Queue<IMgaReference>();
+ references.Enqueue(origref);
+ MgaFCOs fco2ChildFCOs = (fco2 as IMgaModel).ChildFCOs;
+ Dictionary<string, IMgaFCO> newRefeChildren = GetNameMap(fco2ChildFCOs,
+ x => { });
+ // TODO: warn, but only for refport-connected children
+ //GMEConsole.Warning.WriteLine("Warning: " + fco2.Name + " has multiple children named " + x));
+
+ int origPrefs = fco2.Project.Preferences;
+ // Magic word allows us to remove ConnPoints
+ fco2.Project.Preferences = origPrefs | (int)GME.MGA.preference_flags.MGAPREF_IGNORECONNCHECKS
+ | (int)GME.MGA.preference_flags.MGAPREF_FREEINSTANCEREFS;
+
+ try {
+
+ MgaConnection conn = null;
+ var ReconnectList = MakeList( new { ConnRole = "src", Ref = origref, Port = fco2, Conn = conn } );
+ while( references.Count != 0 ) {
+ IMgaReference refe = references.Dequeue();
+
+ foreach( IMgaConnPoint connPoint in refe.UsedByConns ) {
+ IMgaFCO fco2Port;
+ if( newRefeChildren.TryGetValue( connPoint.Target.Name, out fco2Port ) ) {
+ if( fco2Port == null ) {
+ // fco2Port == null => multiple children with the same name
+ // Try matching based on Kind too
+ fco2Port = fco2ChildFCOs.Cast<IMgaFCO>().Where( x => x.Name == connPoint.Target.Name
+ && x.Meta.MetaRef == connPoint.Target.Meta.MetaRef ).FirstOrDefault();
+ }
+ if( fco2Port != null ) {
+ ReconnectList.Add( new { ConnRole = connPoint.ConnRole, Ref = refe, Port = fco2Port, Conn = connPoint.Owner } );
+ connPoint.Remove();
+ }
+ } else {
+ WriteLine( ( x, y ) => "Can't find corresponding port for " + x
+ + " in " + y, connPoint.Target, fco2 );
+ connPoint.Owner.DestroyObject();
+ }
+ }
+ foreach( IMgaReference x in refe.ReferencedBy.Cast<IMgaReference>() ) {
+ if( x.ID == origref.ID )
+ throw new Exception( "Circular reference chain starting with " + origref.AbsPath );
+ references.Enqueue( x );
+ }
+ }
+ origref.Referred = (MgaFCO)fco2;
+ foreach( var reconnect in ReconnectList ) {
+ if( reconnect.ConnRole == "src" )
+ ( reconnect.Conn as IMgaSimpleConnection ).SetSrc( (MgaFCOs)GetRefChain( reconnect.Ref ), (MgaFCO)reconnect.Port );
+ else
+ ( reconnect.Conn as IMgaSimpleConnection ).SetDst( (MgaFCOs)GetRefChain( reconnect.Ref ), (MgaFCO)reconnect.Port );
+ }
+
+ } finally {
+ fco2.Project.Preferences = origPrefs;
+ }
+
+ }
+
+ public static string GetLink(IMgaObject o, string linkText = null)
+ {
+ if (linkText == null)
+ {
+ linkText = getPath(o);
+ }
+ return "<a href=\"mga:" + o.ID + "\">"
+ + linkText
+ + "</a>";
+ }
+
+ private static Dictionary<string, IMgaFCO> GetNameMap(IMgaFCOs fcos,
+ Action<string> warnFunc)
+ {
+ Dictionary<string, IMgaFCO> refeChildren;
+ refeChildren = new Dictionary<string, IMgaFCO>();
+ foreach (IMgaFCO refeChild in fcos.Cast<IMgaFCO>())
+ {
+ if (refeChild.ObjType == GME.MGA.Meta.objtype_enum.OBJTYPE_CONNECTION)
+ continue;
+ if (refeChildren.ContainsKey(refeChild.Name))
+ {
+ warnFunc(refeChild.Name);
+ refeChildren[refeChild.Name] = null;
+ }
+ else
+ refeChildren.Add(refeChild.Name, refeChild);
+ }
+ return refeChildren;
+ }
+
+ private static IMgaFCOs GetRefChain(IMgaReference reference)
+ {
+ IMgaFCOs ret = (IMgaFCOs)Activator.CreateInstance(Type.GetTypeFromProgID("Mga.MgaFCOs"));
+ ret.Append(reference as MgaFCO);
+ while (true)
+ {
+ if (reference.Referred == null)
+ {
+ break;
+ }
+ if (reference.Referred.ObjType == GME.MGA.Meta.objtype_enum.OBJTYPE_REFERENCE)
+ {
+ reference = reference.Referred as IMgaReference;
+ ret.Append(reference as MgaFCO);
+ }
+ else
+ {
+ break;
+ }
+ }
+ return ret;
+ }
+
+ public static string getPath(IMgaObject fco1Object)
+ {
+ return String.Join("/", new ParentChain(fco1Object).Select(x => x.Name).Reverse().ToArray());
+ }
+
+ private List<IMgaObject> getChildren(IMgaObject fco1Objec)
+ {
+ List<IMgaObject> fco1Children = new List<IMgaObject>();
+ if (fco1Objec == null)
+ {
+ return fco1Children;
+ }
+ if (fco1Objec is IMgaFolder)
+ {
+ fco1Children.AddRange((fco1Objec as IMgaFolder).ChildFolders.Cast<IMgaObject>());
+ fco1Children.AddRange((fco1Objec as IMgaFolder).ChildFCOs.Cast<IMgaObject>());
+ }
+ if (fco1Objec is IMgaModel)
+ {
+ fco1Children.AddRange((fco1Objec as IMgaModel).ChildFCOs.Cast<IMgaObject>());
+ }
+ return fco1Children;
+ }
+ }
+
+ [ComVisible(false)]
+ class MgaObjectEqualityComparor<T> : EqualityComparer<T> where T : IMgaObject
+ {
+ public override bool Equals(T x, T y)
+ {
+ return x.ID.Equals(y.ID);
+ }
+
+ public override int GetHashCode(T obj)
+ {
+ return obj.ID.GetHashCode();
+ }
+ }
+
+ [ComVisible(false)]
+ static class DictionaryExtension
+ {
+ public static V GetValueOrDefault<K, V>(this Dictionary<K, V> dic, K key)
+ where V : new()
+ {
+ V ret;
+ bool found = dic.TryGetValue(key, out ret);
+ if (found)
+ {
+ return ret;
+ }
+ else
+ {
+ ret = new V();
+ dic[key] = ret;
+ return ret;
+ }
+ }
+ }
+}
More information about the gme-commit
mailing list