1// Builder.custom - customizations to Gtk.Builder 2// 3// Authors: Stephane Delcroix <stephane@delcroix.org> 4// The biggest part of this code is adapted from glade#, by 5// Ricardo Fernández Pascual <ric@users.sourceforge.net> 6// Rachel Hestilow <hestilow@ximian.com> 7// 8// Copyright (c) 2002 Ricardo Fernández Pascual 9// Copyright (c) 2003 Rachel Hestilow 10// Copyright (c) 2008 Novell, Inc. 11// 12// This program is free software; you can redistribute it and/or 13// modify it under the terms of version 2 of the Lesser GNU General 14// Public License as published by the Free Software Foundation. 15// 16// This program is distributed in the hope that it will be useful, 17// but WITHOUT ANY WARRANTY; without even the implied warranty of 18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19// Lesser General Public License for more details. 20// 21// You should have received a copy of the GNU Lesser General Public 22// License along with this program; if not, write to the 23// Free Software Foundation, Inc., 59 Temple Place - Suite 330, 24// Boston, MA 02111-1307, USA. 25 26 27[System.Serializable] 28public class HandlerNotFoundException : SystemException 29{ 30 string handler_name; 31 string signal_name; 32 System.Reflection.EventInfo evnt; 33 Type delegate_type; 34 35 public HandlerNotFoundException (string handler_name, string signal_name, 36 System.Reflection.EventInfo evnt, Type delegate_type) 37 : this (handler_name, signal_name, evnt, delegate_type, null) 38 { 39 } 40 41 public HandlerNotFoundException (string handler_name, string signal_name, 42 System.Reflection.EventInfo evnt, Type delegate_type, Exception inner) 43 : base ("No handler " + handler_name + " found for signal " + signal_name, 44 inner) 45 { 46 this.handler_name = handler_name; 47 this.signal_name = signal_name; 48 this.evnt = evnt; 49 this.delegate_type = delegate_type; 50 } 51 52 public HandlerNotFoundException (string message, string handler_name, string signal_name, 53 System.Reflection.EventInfo evnt, Type delegate_type) 54 : base ((message != null) ? message : "No handler " + handler_name + " found for signal " + signal_name, 55 null) 56 { 57 this.handler_name = handler_name; 58 this.signal_name = signal_name; 59 this.evnt = evnt; 60 this.delegate_type = delegate_type; 61 } 62 63 protected HandlerNotFoundException (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 64 : base (info, context) 65 { 66 handler_name = info.GetString ("HandlerName"); 67 signal_name = info.GetString ("SignalName"); 68 evnt = info.GetValue ("Event", typeof (System.Reflection.EventInfo)) as System.Reflection.EventInfo; 69 delegate_type = info.GetValue ("DelegateType", typeof (Type)) as Type; 70 } 71 72 public string HandlerName 73 { 74 get { 75 return handler_name; 76 } 77 } 78 79 public string SignalName 80 { 81 get { 82 return signal_name; 83 } 84 } 85 86 public System.Reflection.EventInfo Event 87 { 88 get { 89 return evnt; 90 } 91 } 92 93 public Type DelegateType 94 { 95 get { 96 return delegate_type; 97 } 98 } 99 100 public override void GetObjectData (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 101 { 102 base.GetObjectData (info, context); 103 info.AddValue ("HandlerName", handler_name); 104 info.AddValue ("SignalName", signal_name); 105 info.AddValue ("Event", evnt); 106 info.AddValue ("DelegateType", delegate_type); 107 } 108} 109 110 111[AttributeUsage (AttributeTargets.Field)] 112public class ObjectAttribute : Attribute 113{ 114 private string name; 115 private bool specified; 116 117 public ObjectAttribute (string name) 118 { 119 specified = true; 120 this.name = name; 121 } 122 123 public ObjectAttribute () 124 { 125 specified = false; 126 } 127 128 public string Name 129 { 130 get { return name; } 131 } 132 133 public bool Specified 134 { 135 get { return specified; } 136 } 137} 138 139public IntPtr GetRawObject(string name) { 140 IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name); 141 IntPtr raw_ret = gtk_builder_get_object(Handle, native_name); 142 GLib.Marshaller.Free (native_name); 143 return raw_ret; 144} 145 146public Builder (System.IO.Stream s) : this (s, null) 147{ 148} 149 150public Builder (System.IO.Stream s, string translation_domain) 151{ 152 if (s == null) 153 throw new ArgumentNullException ("s"); 154 155 int size = (int) s.Length; 156 byte[] buffer = new byte[size]; 157 s.Read (buffer, 0, size); 158 s.Close (); 159 160 AddFromString(System.Text.Encoding.UTF8.GetString (buffer)); 161 162 TranslationDomain = translation_domain; 163} 164 165public Builder (string resource_name) : this (resource_name, null) 166{ 167} 168 169public Builder (string resource_name, string translation_domain) : this (System.Reflection.Assembly.GetEntryAssembly (), resource_name, translation_domain) 170{ 171} 172 173public Builder (System.Reflection.Assembly assembly, string resource_name, string translation_domain) : this () 174{ 175 if (GetType() != typeof (Builder)) 176 throw new InvalidOperationException ("Cannot chain to this constructor from subclasses."); 177 178 if (assembly == null) 179 assembly = System.Reflection.Assembly.GetCallingAssembly (); 180 181 System.IO.Stream s = assembly.GetManifestResourceStream (resource_name); 182 if (s == null) 183 throw new ArgumentException ("Cannot get resource file '" + resource_name + "'", 184 "resource_name"); 185 186 int size = (int) s.Length; 187 byte[] buffer = new byte[size]; 188 s.Read (buffer, 0, size); 189 s.Close (); 190 191 AddFromString(System.Text.Encoding.UTF8.GetString (buffer)); 192 193 TranslationDomain = translation_domain; 194} 195 196public void Autoconnect (object handler) 197{ 198 BindFields (handler); 199 (new SignalConnector (this, handler)).ConnectSignals (); 200} 201 202public void Autoconnect (Type handler_class) 203{ 204 BindFields (handler_class); 205 (new SignalConnector (this, handler_class)).ConnectSignals (); 206} 207 208class SignalConnector 209{ 210 Builder builder; 211 Type handler_type; 212 object handler; 213 214 public SignalConnector (Builder builder, object handler) 215 { 216 this.builder = builder; 217 this.handler = handler; 218 handler_type = handler.GetType (); 219 } 220 221 public SignalConnector (Builder builder, Type handler_type) 222 { 223 this.builder = builder; 224 this.handler = null; 225 this.handler_type = handler_type; 226 } 227 228 [DllImport("libgtk-win32-2.0-0.dll", CallingConvention=CallingConvention.Cdecl)] 229 static extern void gtk_builder_connect_signals_full(IntPtr raw, GtkSharp.BuilderConnectFuncNative func, IntPtr user_data); 230 231 public void ConnectSignals() { 232 GtkSharp.BuilderConnectFuncWrapper func_wrapper = new GtkSharp.BuilderConnectFuncWrapper (ConnectFunc); 233 gtk_builder_connect_signals_full(builder.Handle, func_wrapper.NativeDelegate, IntPtr.Zero); 234 } 235 236 public void ConnectFunc (Builder builder, GLib.Object objekt, string signal_name, string handler_name, GLib.Object connect_object, GLib.ConnectFlags flags) 237 { 238 /* search for the event to connect */ 239 System.Reflection.MemberInfo[] evnts = objekt.GetType (). 240 FindMembers (System.Reflection.MemberTypes.Event, 241 System.Reflection.BindingFlags.Instance 242 | System.Reflection.BindingFlags.Static 243 | System.Reflection.BindingFlags.Public 244 | System.Reflection.BindingFlags.NonPublic, 245 SignalFilter, signal_name); 246 foreach (System.Reflection.EventInfo ei in evnts) { 247 bool connected = false; 248 System.Reflection.MethodInfo add = ei.GetAddMethod (); 249 System.Reflection.ParameterInfo[] addpi = add.GetParameters (); 250 if (addpi.Length == 1) { /* this should be always true, unless there's something broken */ 251 Type delegate_type = addpi[0].ParameterType; 252 253 /* look for an instance method */ 254 if (connect_object != null || handler != null) 255 try { 256 Delegate d = Delegate.CreateDelegate (delegate_type, connect_object != null ? connect_object : handler, handler_name); 257 add.Invoke (objekt, new object[] { d } ); 258 connected = true; 259 } catch (ArgumentException) { /* ignore if there is not such instance method */ 260 } 261 262 /* look for a static method if no instance method has been found */ 263 if (!connected && handler_type != null) 264 try { 265 Delegate d = Delegate.CreateDelegate (delegate_type, handler_type, handler_name); 266 add.Invoke (objekt, new object[] { d } ); 267 connected = true; 268 } catch (ArgumentException) { /* ignore if there is not such static method */ 269 } 270 271 if (!connected) { 272 string msg = ExplainError (ei.Name, delegate_type, handler_type, handler_name); 273 throw new HandlerNotFoundException (msg, handler_name, signal_name, ei, delegate_type); 274 } 275 } 276 } 277 } 278 279 static bool SignalFilter (System.Reflection.MemberInfo m, object filterCriteria) 280 { 281 string signame = (filterCriteria as string); 282 object[] attrs = m.GetCustomAttributes (typeof (GLib.SignalAttribute), false); 283 if (attrs.Length > 0) 284 { 285 foreach (GLib.SignalAttribute a in attrs) 286 { 287 if (signame == a.CName) 288 { 289 return true; 290 } 291 } 292 return false; 293 } 294 else 295 { 296 /* this tries to match the names when no attibutes are present. 297 It is only a fallback. */ 298 signame = signame.ToLower ().Replace ("_", ""); 299 string evname = m.Name.ToLower (); 300 return signame == evname; 301 } 302 } 303 304 static string GetSignature (System.Reflection.MethodInfo method) 305 { 306 if (method == null) 307 return null; 308 309 System.Reflection.ParameterInfo [] parameters = method.GetParameters (); 310 System.Text.StringBuilder sb = new System.Text.StringBuilder (); 311 sb.Append ('('); 312 foreach (System.Reflection.ParameterInfo info in parameters) { 313 sb.Append (info.ParameterType.ToString ()); 314 sb.Append (','); 315 } 316 if (sb.Length != 0) 317 sb.Length--; 318 319 sb.Append (')'); 320 return sb.ToString (); 321 } 322 323 static string GetSignature (Type delegate_type) 324 { 325 System.Reflection.MethodInfo method = delegate_type.GetMethod ("Invoke"); 326 return GetSignature (method); 327 } 328 329 const System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.NonPublic | 330 System.Reflection.BindingFlags.Public | 331 System.Reflection.BindingFlags.Static | 332 System.Reflection.BindingFlags.Instance; 333 static string GetSignature (Type klass, string method_name) 334 { 335 try { 336 System.Reflection.MethodInfo method = klass.GetMethod (method_name, flags); 337 return GetSignature (method); 338 } catch { 339 // May be more than one method with that name and none matches 340 return null; 341 } 342 } 343 344 345 static string ExplainError (string event_name, Type deleg, Type klass, string method) 346 { 347 if (deleg == null || klass == null || method == null) 348 return null; 349 350 System.Text.StringBuilder sb = new System.Text.StringBuilder (); 351 string expected = GetSignature (deleg); 352 string actual = GetSignature (klass, method); 353 if (actual == null) 354 return null; 355 sb.AppendFormat ("The handler for the event {0} should take '{1}', " + 356 "but the signature of the provided handler ('{2}') is '{3}'\n", 357 event_name, expected, method, actual); 358 return sb.ToString (); 359 } 360 361} 362 363 364void BindFields (object target) 365{ 366 BindFields (target, target.GetType ()); 367} 368 369void BindFields (Type type) 370{ 371 BindFields (null, type); 372} 373 374void BindFields (object target, Type type) 375{ 376 System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.DeclaredOnly; 377 if (target != null) 378 flags |= System.Reflection.BindingFlags.Instance; 379 else 380 flags |= System.Reflection.BindingFlags.Static; 381 382 do { 383 System.Reflection.FieldInfo[] fields = type.GetFields (flags); 384 if (fields == null) 385 return; 386 387 foreach (System.Reflection.FieldInfo field in fields) 388 { 389 object[] attrs = field.GetCustomAttributes (typeof (ObjectAttribute), false); 390 if (attrs == null || attrs.Length == 0) 391 continue; 392 // The widget to field binding must be 1:1, so only check 393 // the first attribute. 394 ObjectAttribute attr = (ObjectAttribute) attrs[0]; 395 GLib.Object gobject; 396 if (attr.Specified) 397 gobject = GetObject (attr.Name); 398 else 399 gobject = GetObject (field.Name); 400 401 if (gobject != null) 402 try { 403 field.SetValue (target, gobject, flags, null, null); 404 } catch (Exception e) { 405 Console.WriteLine ("Unable to set value for field " + field.Name); 406 throw e; 407 } 408 } 409 type = type.BaseType; 410 } 411 while (type != typeof(object) && type != null); 412} 413 414