123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- /*
- * $Id$
- *
- * Copyright (C) 2004 Todd Berman <tberman@off.net>
- * Copyright (C) 2004 Jeroen Zwartepoorte <jeroen@xs4all.nl>
- * Copyright (C) 2005 John Luke <john.luke@gmail.com>
- *
- * based on work by:
- * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
- using System;
- using System.Collections;
- using System.Reflection;
- using System.Xml;
- using Gtk;
- namespace Gdl
- {
- public delegate void PropertyChangedHandler (object o, string name);
- public class DockObject : Container
- {
- private DockObjectFlags flags = DockObjectFlags.Automatic;
- private int freezeCount = 0;
- private DockMaster master;
- private string name;
- private string longName;
- private string stockid;
- private bool reducePending;
- private PropertyInfo[] publicProps;
- Hashtable afterProps;
- Hashtable beforeProps;
- public event DetachedHandler Detached;
- public event DockedHandler Docked;
- public event PropertyChangedHandler PropertyChanged;
- protected DockObject (IntPtr raw) : base (raw) { }
- protected DockObject () : base () { }
- public DockObjectFlags DockObjectFlags {
- get {
- return flags;
- }
- set {
- flags = value;
- EmitPropertyEvent ("DockObjectFlags");
- }
- }
- public bool InDetach {
- get {
- return ((flags & DockObjectFlags.InDetach) != 0);
- }
- }
- public bool InReflow {
- get {
- return ((flags & DockObjectFlags.InReflow) != 0);
- }
- }
- public bool IsAttached {
- get {
- return ((flags & DockObjectFlags.Attached) != 0);
- }
- }
- public bool IsAutomatic {
- get {
- return ((flags & DockObjectFlags.Automatic) != 0);
- }
- }
- public bool IsBound {
- get {
- return master != null;
- }
- }
- public virtual bool IsCompound {
- get {
- return true;
- }
- }
- public bool IsFrozen {
- get {
- return freezeCount > 0;
- }
- }
- public string LongName {
- get {
- return longName;
- }
- set {
- longName = value;
- EmitPropertyEvent ("LongName");
- }
- }
- public DockMaster Master {
- get {
- return master;
- }
- set {
- if (value != null)
- Bind (master);
- else
- Unbind ();
- EmitPropertyEvent ("Master");
- }
- }
- [Export]
- public new string Name {
- get {
- return name;
- }
- set {
- name = value;
- EmitPropertyEvent ("Name");
- }
- }
- public DockObject ParentObject {
- get {
- Widget parent = Parent;
- while (parent != null && !(parent is DockObject)) {
- parent = parent.Parent;
- }
- return parent != null ? (DockObject)parent : null;
- }
- }
- public string StockId {
- get {
- return stockid;
- }
- set {
- stockid = value;
- EmitPropertyEvent ("StockId");
- }
- }
- private PropertyInfo[] PublicProps {
- get {
- if (publicProps == null)
- publicProps = this.GetType ().GetProperties (BindingFlags.Public | BindingFlags.Instance);
- return publicProps;
- }
- }
- void SetPropertyValue (string property, string val, bool after)
- {
- if (afterProps == null) {
- afterProps = new Hashtable ();
- beforeProps = new Hashtable ();
- foreach (PropertyInfo pp in PublicProps) {
- if (pp.IsDefined (typeof (AfterAttribute), true))
- afterProps [pp.Name.ToLower ()] = pp;
- else
- beforeProps [pp.Name.ToLower ()] = pp;
- }
- }
- property = property.ToLower ();
- PropertyInfo p = after ? (PropertyInfo) afterProps [property] : (PropertyInfo) beforeProps [property];
- if (p != null)
- SetPropertyValue (p, property, val);
- }
- void SetPropertyValue (PropertyInfo pi, string property, string val)
- {
- if (pi.PropertyType.IsEnum)
- pi.SetValue (this, Enum.Parse (pi.PropertyType, val, true), null);
- else if (pi.PropertyType == typeof (bool))
- pi.SetValue (this, val == "no" ? false : true, null);
- else if (pi.PropertyType == typeof (int))
- pi.SetValue (this, int.Parse (val), null);
- else
- pi.SetValue (this, val, null);
- }
- public void FromXml (XmlNode node)
- {
- foreach (XmlAttribute att in node.Attributes)
- SetPropertyValue (att.Name, att.Value, false);
- }
- public void FromXmlAfter (XmlNode node)
- {
- foreach (XmlAttribute att in node.Attributes)
- SetPropertyValue (att.Name, att.Value, true);
- }
- static string GetXmlName (Type t)
- {
- switch (t.ToString ()) {
- case "Gdl.Dock":
- return "dock";
- case "Gdl.DockItem":
- return "item";
- case "Gdl.DockNotebook":
- return "notebook";
- case "Gdl.DockPaned":
- return "paned";
- default:
- return "object";
- }
- }
- public XmlElement ToXml (XmlDocument doc)
- {
- Type t = this.GetType ();
- XmlElement element = doc.CreateElement (GetXmlName (t));
- // get object exported attributes
- ArrayList exported = new ArrayList ();
- foreach (PropertyInfo p in PublicProps) {
- if (p.IsDefined (typeof (ExportAttribute), true))
- exported.Add (p);
- }
- foreach (PropertyInfo p in exported) {
- if (p.PropertyType.IsSubclassOf (typeof (System.Enum)))
- element.SetAttribute (p.Name.ToLower (), p.GetValue (this, null).ToString ().ToLower ());
- else if (p.PropertyType == typeof (bool))
- element.SetAttribute (p.Name.ToLower (), ((bool) p.GetValue (this, null)) ? "yes" : "no");
- else if (p.GetValue (this, null) != null)
- element.SetAttribute (p.Name.ToLower (), p.GetValue (this, null).ToString ());
- }
- return element;
- }
- protected override void OnDestroyed ()
- {
- if (IsCompound) {
- /* detach our dock object children if we have some, and even
- if we are not attached, so they can get notification */
- Freeze ();
- foreach (DockObject child in Children)
- child.Detach (true);
- reducePending = false;
- Thaw ();
- }
- if (IsAttached)
- /* detach ourselves */
- Detach (false);
- if (Master != null)
- /* finally unbind us */
- Unbind ();
- base.OnDestroyed ();
- }
- protected override void OnShown ()
- {
- if (IsCompound)
- foreach (Widget child in Children)
- child.Show ();
- base.OnShown ();
- }
- protected override void OnHidden ()
- {
- if (IsCompound)
- foreach (Widget child in Children)
- child.Hide ();
- base.OnHidden ();
- }
- public virtual void OnDetached (bool recursive)
- {
- /* detach children */
- if (recursive && IsCompound) {
- foreach (DockObject child in Children) {
- child.Detach (recursive);
- }
- }
- /* detach the object itself */
- flags &= ~(DockObjectFlags.Attached);
- DockObject parent = ParentObject;
- if (Parent != null && Parent is Container)
- ((Container)Parent).Remove (this);
- if (parent != null)
- parent.Reduce ();
- }
- public virtual void OnReduce ()
- {
- if (!IsCompound)
- return;
- DockObject parent = ParentObject;
- Widget[] children = Children;
- if (children.Length <= 1) {
- if (parent != null)
- parent.Freeze ();
- Freeze ();
- Detach (false);
- foreach (Widget widget in children) {
- DockObject child = widget as DockObject;
- child.flags |= DockObjectFlags.InReflow;
- child.Detach (false);
- if (parent != null)
- parent.Add (child);
- child.flags &= ~(DockObjectFlags.InReflow);
- }
- reducePending = false;
- Thaw ();
- if (parent != null)
- parent.Thaw ();
- }
- }
- public virtual bool OnDockRequest (int x, int y, ref DockRequest request)
- {
- return false;
- }
- public virtual void OnDocked (DockObject requestor, DockPlacement position, object data)
- {
- }
- public virtual bool OnReorder (DockObject child, DockPlacement new_position, object data)
- {
- return false;
- }
- public virtual void OnPresent (DockObject child)
- {
- Show ();
- }
- public virtual bool OnChildPlacement (DockObject child, ref DockPlacement placement)
- {
- return false;
- }
- public bool ChildPlacement (DockObject child, ref DockPlacement placement)
- {
- if (!IsCompound)
- return false;
- return OnChildPlacement (child, ref placement);
- }
- public void Detach (bool recursive)
- {
- if (!IsAttached)
- return;
- /* freeze the object to avoid reducing while detaching children */
- Freeze ();
- DockObjectFlags |= DockObjectFlags.InDetach;
- OnDetached (recursive);
- DetachedHandler handler = Detached;
- if (handler != null)
- handler (this, new DetachedArgs (recursive));
- DockObjectFlags &= ~(DockObjectFlags.InDetach);
- Thaw ();
- }
- public void Dock (DockObject requestor, DockPlacement position, object data)
- {
- if (requestor == null || requestor == this)
- return;
- if (master == null) {
- Console.WriteLine ("Dock operation requested in a non-bound object {0}.", this);
- Console.WriteLine ("This might break.");
- }
- if (!requestor.IsBound)
- requestor.Bind (Master);
- if (requestor.Master != Master) {
- Console.WriteLine ("Cannot dock {0} to {1} as they belong to different masters.",
- requestor, this);
- return;
- }
- /* first, see if we can optimize things by reordering */
- if (position != DockPlacement.None) {
- DockObject parent = ParentObject;
- if (OnReorder (requestor, position, data) ||
- (parent != null && parent.OnReorder (requestor, position, data)))
- return;
- }
- /* freeze the object, since under some conditions it might
- be destroyed when detaching the requestor */
- Freeze ();
- /* detach the requestor before docking */
- if (requestor.IsAttached)
- requestor.Detach (false);
- /* notify interested parties that an object has been docked. */
- if (position != DockPlacement.None) {
- OnDocked (requestor, position, data);
- DockedHandler handler = Docked;
- if (handler != null) {
- DockedArgs args = new DockedArgs (requestor, position);
- handler (this, args);
- }
- }
- Thaw ();
- }
- public void Present (DockObject child)
- {
- if (ParentObject != null)
- /* chain the call to our parent */
- ParentObject.Present (this);
- OnPresent (child);
- }
- public void Reduce ()
- {
- if (IsFrozen) {
- reducePending = true;
- return;
- }
- OnReduce ();
- }
- public void Freeze ()
- {
- freezeCount++;
- }
- public void Thaw ()
- {
- if (freezeCount < 0) {
- Console.WriteLine ("DockObject.Thaw: freezeCount < 0");
- return;
- }
- freezeCount--;
- if (freezeCount == 0 && reducePending) {
- reducePending = false;
- Reduce ();
- }
- }
- public void Bind (DockMaster master)
- {
- if (master == null) {
- Console.WriteLine ("Passed master is null");
- Console.WriteLine (System.Environment.StackTrace);
- return;
- }
- if (this.master == master) {
- Console.WriteLine ("Passed master is this master");
- return;
- }
- if (this.master != null) {
- Console.WriteLine ("Attempt to bind an already bound object");
- return;
- }
- master.Add (this);
- this.master = master;
- EmitPropertyEvent ("Master");
- }
- public void Unbind ()
- {
- if (IsAttached)
- Detach (true);
- if (master != null) {
- DockMaster _master = master;
- master = null;
- _master.Remove (this);
- EmitPropertyEvent ("Master");
- }
- }
- protected void EmitPropertyEvent (string name)
- {
- // Make a local assignment of the handler here to prevent
- // any race conditions if the PropertyChanged value changes
- // to null after the != null check.
- PropertyChangedHandler handler = PropertyChanged;
- if (handler != null)
- handler (this, name);
- }
- }
- }
|