GME
13
|
00001 using System; 00002 using System.Collections.Generic; 00003 using System.IO; 00004 using System.Runtime.InteropServices; 00005 using System.Text; 00006 using GME.MGA.Core; 00007 using GME.CSharp; 00008 using GME; 00009 using GME.MGA; 00010 using System.Linq; 00011 00012 namespace CSGUI 00013 { 00017 [Guid("0ACC000C-29E6-418B-9F8B-968418C533B9"), 00018 ProgId("CSGUI.ReferenceSwitcher"), 00019 ClassInterface(ClassInterfaceType.AutoDual)] 00020 [ComVisible(true)] 00021 public class ReferenceSwitcher 00022 { 00023 MgaGateway MgaGateway { get; set; } 00024 GMEConsole GMEConsole { get; set; } 00025 00026 public void SwitchReferences(object[] lib1Objects, object[] lib2Objects) 00027 { 00028 Switcher switcher = new Switcher(lib1Objects.Cast<IMgaObject>(), lib2Objects.Cast<IMgaObject>(), null); 00029 switcher.UpdateSublibrary(); 00030 } 00031 00032 [ComVisible(false)] 00033 public void PrintLine(Func<string, string, string> f, IMgaFCO a, IMgaFCO b) 00034 { 00035 Console.Out.WriteLine(f(Switcher.getPath(a), Switcher.getPath(b))); 00036 } 00037 public void SwitchReference(IMgaFCO to, IMgaReference @ref) 00038 { 00039 Switcher.MoveReferenceWithRefportConnections(to, @ref, PrintLine); 00040 } 00041 } 00042 00043 [ComVisible(false)] 00044 public class Switcher 00045 { 00046 List<IMgaObject> lib1Objects; 00047 List<IMgaObject> lib2Objects; 00048 GMEConsole GMEConsole; 00049 00050 public Switcher(IMgaObject fco1Object, IMgaObject fco2Object, GMEConsole GMEConsole) 00051 { 00052 this.lib1Objects = new List<IMgaObject>() { fco1Object }; 00053 this.lib2Objects = new List<IMgaObject>() { fco2Object }; 00054 this.GMEConsole = GMEConsole; 00055 } 00056 public Switcher(IEnumerable<IMgaObject> fco1Object, IEnumerable<IMgaObject> fco2Object, GMEConsole GMEConsole) 00057 { 00058 this.lib1Objects = fco1Object.ToList(); 00059 this.lib2Objects = fco2Object.ToList(); 00060 this.GMEConsole = GMEConsole; 00061 } 00062 00063 class ObjectPair 00064 { 00065 public IMgaObject o1 { get; set; } 00066 public IMgaObject o2 { get; set; } 00067 } 00068 00069 public void UpdateSublibrary() 00070 { 00071 int origPrefs = this.lib1Objects.First().Project.Preferences; 00072 // Magic word allows us to remove ConnPoints 00073 this.lib1Objects.First().Project.Preferences = origPrefs | (int)GME.MGA.preference_flags.MGAPREF_IGNORECONNCHECKS 00074 | (int)GME.MGA.preference_flags.MGAPREF_FREEINSTANCEREFS; 00075 try 00076 { 00077 IEnumerator<IMgaObject> lib2ObjectsEnum = lib2Objects.GetEnumerator(); 00078 foreach (IMgaObject lib1Object in lib1Objects) 00079 { 00080 lib2ObjectsEnum.MoveNext(); 00081 UpdateSublibrary(lib1Object, lib2ObjectsEnum.Current); 00082 } 00083 } 00084 finally 00085 { 00086 lib1Objects.First().Project.Preferences = origPrefs; 00087 } 00088 } 00089 00090 private void UpdateSublibrary(IMgaObject fco1Objec, IMgaObject fco2Objec) 00091 { 00092 // fco2Object may be null 00093 if (fco1Objec is IMgaFCO) // references only refer to FCOs 00094 { 00095 IMgaFCO fco1 = (IMgaFCO)fco1Objec; 00096 IMgaFCO fco2 = fco2Objec as IMgaFCO; 00097 foreach (IMgaFCO fco in fco1.ReferencedBy) 00098 { 00099 if (fco.IsInstance) 00100 continue; // instance references will be updated by their archetype 00101 // Don't update references in the old library 00102 bool fcoInLib1Objects = false; 00103 foreach (IMgaObject lib1Root in this.lib1Objects) 00104 { 00105 // FIXME: Contains(this.fco1Object) doesn't work 00106 if (new ParentChain(fco).Contains(lib1Root, new MgaObjectEqualityComparor<IMgaObject>())) 00107 { 00108 fcoInLib1Objects = true; 00109 } 00110 } 00111 if (fcoInLib1Objects) 00112 continue; 00113 IMgaReference refe = (IMgaReference)fco; 00114 if (fco2 != null) 00115 { 00116 if (refe.UsedByConns.Count != 0) 00117 { 00118 if (refe.DerivedFrom == null) 00119 { 00120 try 00121 { 00122 MoveReferenceWithRefportConnections(fco2, refe, WriteLine); 00123 } 00124 catch (Exception e) 00125 { 00126 if (GMEConsole != null) 00127 GMEConsole.Error.WriteLine("Could not set reference " + GetLink(refe, refe.Name)); 00128 throw new Exception("Could not set reference " + getPath(refe) + 00129 " (" + refe.ID + ")", e); 00130 } 00131 } 00132 } 00133 else 00134 { 00135 try 00136 { 00137 bool setRef; 00138 if (refe.DerivedFrom == null) 00139 setRef = true; 00140 else 00141 { 00142 short compareToBase; 00143 refe.CompareToBase(out compareToBase); 00144 setRef = compareToBase != 0; 00145 } 00146 if (setRef) 00147 { 00148 // FIXME: can this fail; should we handle it somehow? 00149 refe.Referred = (GME.MGA.MgaFCO)fco2; 00150 } 00151 } 00152 catch (Exception e) 00153 { 00154 if (GMEConsole != null) 00155 GMEConsole.Error.WriteLine("Could not set reference " + GetLink(refe, refe.Name)); 00156 throw new Exception("Could not set reference " + getPath(refe) + 00157 " (" + refe.ID + ")", e); 00158 } 00159 } 00160 } 00161 else 00162 { 00163 WriteLine((x, y) => "Couldn't update " + x + ": " + y + " has no counterpart", refe, fco1); 00164 } 00165 } 00166 } 00167 00168 List<IMgaObject> fco1Children = getChildren(fco1Objec); 00169 List<IMgaObject> fco2Children = getChildren(fco2Objec); 00170 Dictionary<string, ObjectPair> dict = new Dictionary<string, ObjectPair>(); 00171 foreach (IMgaObject o in fco1Children) 00172 { 00173 dict.GetValueOrDefault(o.Name + "xxx ;xxx" + o.MetaBase.Name).o1 = o; 00174 } 00175 foreach (IMgaObject o in fco2Children) 00176 { 00177 dict.GetValueOrDefault(o.Name + "xxx ;xxx" + o.MetaBase.Name).o2 = o; 00178 } 00179 foreach (KeyValuePair<string, ObjectPair> entry in dict) 00180 { 00181 if (entry.Value.o1 != null) 00182 { 00183 UpdateSublibrary(entry.Value.o1, entry.Value.o2); 00184 } 00185 } 00186 } 00187 00188 00189 public delegate void WriteLineF(Func<string, string, string> f, IMgaFCO a, IMgaFCO b); 00190 public void WriteLine(Func<string, string, string> f, IMgaFCO a, IMgaFCO b) 00191 { 00192 if (GMEConsole != null) 00193 { 00194 GMEConsole.Out.WriteLine(f(GetLink(a, a.Name), GetLink(b, b.Name))); 00195 } 00196 else 00197 { 00198 Console.Out.WriteLine(f(getPath(a), getPath(b))); 00199 } 00200 } 00201 00202 public static List<T> MakeList<T>(T itemOftype) 00203 { 00204 List<T> newList = new List<T>(); 00205 return newList; 00206 } 00207 00211 public static void MoveReferenceWithRefportConnections(IMgaFCO fco2, IMgaReference origref, 00212 WriteLineF WriteLine) 00213 { 00214 Queue<IMgaReference> references = new Queue<IMgaReference>(); 00215 references.Enqueue(origref); 00216 IMgaFCO targetModel = fco2; 00217 while (targetModel is IMgaReference) 00218 { 00219 targetModel = ((IMgaReference)targetModel).Referred; 00220 } 00221 MgaFCOs fco2ChildFCOs = ((IMgaModel)targetModel).ChildFCOs; 00222 Dictionary<string, IMgaFCO> newRefeChildren = GetNameMap(fco2ChildFCOs, 00223 x => { }); 00224 // TODO: warn, but only for refport-connected children 00225 //GMEConsole.Warning.WriteLine("Warning: " + fco2.Name + " has multiple children named " + x)); 00226 00227 int origPrefs = fco2.Project.Preferences; 00228 // Magic word allows us to remove ConnPoints 00229 fco2.Project.Preferences = origPrefs | (int)GME.MGA.preference_flags.MGAPREF_IGNORECONNCHECKS 00230 | (int)GME.MGA.preference_flags.MGAPREF_FREEINSTANCEREFS; 00231 00232 try { 00233 00234 MgaConnection conn = null; 00235 var ReconnectList = MakeList( new { ConnRole = "src", Ref = origref, Port = fco2, Conn = conn } ); 00236 while( references.Count != 0 ) { 00237 IMgaReference refe = references.Dequeue(); 00238 00239 foreach (IMgaConnPoint connPoint in refe.UsedByConns) { 00240 if (connPoint.References[1] != refe) 00241 { 00242 continue; 00243 } 00244 IMgaFCO fco2Port; 00245 if( newRefeChildren.TryGetValue( connPoint.Target.Name, out fco2Port ) ) { 00246 if( fco2Port == null ) { 00247 // fco2Port == null => multiple children with the same name 00248 // Try matching based on Kind too 00249 fco2Port = fco2ChildFCOs.Cast<IMgaFCO>().Where( x => x.Name == connPoint.Target.Name 00250 && x.Meta.MetaRef == connPoint.Target.Meta.MetaRef ).FirstOrDefault(); 00251 } 00252 if( fco2Port != null ) { 00253 ReconnectList.Add( new { ConnRole = connPoint.ConnRole, Ref = refe, Port = fco2Port, Conn = connPoint.Owner } ); 00254 connPoint.Remove(); 00255 } 00256 } else { 00257 WriteLine( ( x, y ) => "Can't find corresponding port for " + x 00258 + " in " + y, connPoint.Target, fco2 ); 00259 connPoint.Owner.DestroyObject(); 00260 } 00261 } 00262 foreach( IMgaReference x in refe.ReferencedBy.Cast<IMgaReference>() ) { 00263 if( x.ID == origref.ID ) 00264 throw new Exception( "Circular reference chain starting with " + origref.AbsPath ); 00265 references.Enqueue( x ); 00266 } 00267 } 00268 origref.Referred = (MgaFCO)fco2; 00269 foreach( var reconnect in ReconnectList ) { 00270 if( reconnect.ConnRole == "src" ) 00271 ( reconnect.Conn as IMgaSimpleConnection ).SetSrc( (MgaFCOs)GetRefChain( reconnect.Ref ), (MgaFCO)reconnect.Port ); 00272 else 00273 ( reconnect.Conn as IMgaSimpleConnection ).SetDst( (MgaFCOs)GetRefChain( reconnect.Ref ), (MgaFCO)reconnect.Port ); 00274 } 00275 00276 } finally { 00277 fco2.Project.Preferences = origPrefs; 00278 } 00279 00280 } 00281 00282 public static string GetLink(IMgaObject o, string linkText = null) 00283 { 00284 if (linkText == null) 00285 { 00286 linkText = getPath(o); 00287 } 00288 return "<a href=\"mga:" + o.ID + "\">" 00289 + linkText 00290 + "</a>"; 00291 } 00292 00293 private static Dictionary<string, IMgaFCO> GetNameMap(IMgaFCOs fcos, 00294 Action<string> warnFunc) 00295 { 00296 Dictionary<string, IMgaFCO> refeChildren; 00297 refeChildren = new Dictionary<string, IMgaFCO>(); 00298 foreach (IMgaFCO refeChild in fcos.Cast<IMgaFCO>()) 00299 { 00300 if (refeChild.ObjType == GME.MGA.Meta.objtype_enum.OBJTYPE_CONNECTION) 00301 continue; 00302 if (refeChildren.ContainsKey(refeChild.Name)) 00303 { 00304 warnFunc(refeChild.Name); 00305 refeChildren[refeChild.Name] = null; 00306 } 00307 else 00308 refeChildren.Add(refeChild.Name, refeChild); 00309 } 00310 return refeChildren; 00311 } 00312 00313 private static IMgaFCOs GetRefChain(IMgaReference reference) 00314 { 00315 IMgaFCOs ret = (IMgaFCOs)Activator.CreateInstance(Type.GetTypeFromProgID("Mga.MgaFCOs")); 00316 ret.Append(reference as MgaFCO); 00317 while (true) 00318 { 00319 if (reference.Referred == null) 00320 { 00321 break; 00322 } 00323 if (reference.Referred.ObjType == GME.MGA.Meta.objtype_enum.OBJTYPE_REFERENCE) 00324 { 00325 reference = reference.Referred as IMgaReference; 00326 ret.Append(reference as MgaFCO); 00327 } 00328 else 00329 { 00330 break; 00331 } 00332 } 00333 return ret; 00334 } 00335 00336 public static string getPath(IMgaObject fco1Object) 00337 { 00338 return String.Join("/", new ParentChain(fco1Object).Select(x => x.Name).Reverse().ToArray()); 00339 } 00340 00341 private List<IMgaObject> getChildren(IMgaObject fco1Objec) 00342 { 00343 List<IMgaObject> fco1Children = new List<IMgaObject>(); 00344 if (fco1Objec == null) 00345 { 00346 return fco1Children; 00347 } 00348 if (fco1Objec is IMgaFolder) 00349 { 00350 fco1Children.AddRange((fco1Objec as IMgaFolder).ChildFolders.Cast<IMgaObject>()); 00351 fco1Children.AddRange((fco1Objec as IMgaFolder).ChildFCOs.Cast<IMgaObject>()); 00352 } 00353 if (fco1Objec is IMgaModel) 00354 { 00355 fco1Children.AddRange((fco1Objec as IMgaModel).ChildFCOs.Cast<IMgaObject>()); 00356 } 00357 return fco1Children; 00358 } 00359 } 00360 00361 [ComVisible(false)] 00362 class MgaObjectEqualityComparor<T> : EqualityComparer<T> where T : IMgaObject 00363 { 00364 public override bool Equals(T x, T y) 00365 { 00366 return x.ID.Equals(y.ID); 00367 } 00368 00369 public override int GetHashCode(T obj) 00370 { 00371 return obj.ID.GetHashCode(); 00372 } 00373 } 00374 00375 [ComVisible(false)] 00376 static class DictionaryExtension 00377 { 00378 public static V GetValueOrDefault<K, V>(this Dictionary<K, V> dic, K key) 00379 where V : new() 00380 { 00381 V ret; 00382 bool found = dic.TryGetValue(key, out ret); 00383 if (found) 00384 { 00385 return ret; 00386 } 00387 else 00388 { 00389 ret = new V(); 00390 dic[key] = ret; 00391 return ret; 00392 } 00393 } 00394 } 00395 }