OSDN Git Service

The initial (but fully working) implementation of Plug-in contributed Context sensiti...
authorDouglas R. Miles <logicmoo@gmail.com>
Sun, 13 Sep 2009 12:45:52 +0000 (12:45 +0000)
committerDouglas R. Miles <logicmoo@gmail.com>
Sun, 13 Sep 2009 12:45:52 +0000 (12:45 +0000)
git-svn-id: https://radegast.googlecode.com/svn/trunk@234 f7a694da-4d33-11de-9ad6-1127a62b9fcd

Radegast/Core/Contexts/AvatarProfileAction.cs [new file with mode: 0644]
Radegast/Core/Contexts/ContextAction.cs [new file with mode: 0644]
Radegast/Core/Contexts/ContextActionsManager.cs [new file with mode: 0644]
Radegast/Core/Contexts/DeRezObjectAction.cs [new file with mode: 0644]
Radegast/Core/Contexts/IContextAction.cs [new file with mode: 0644]
Radegast/Core/Contexts/RezInventoryObjectAction.cs [new file with mode: 0644]
Radegast/Core/RadegastInstance.cs
Radegast/GUI/Consoles/TabsConsole.cs

diff --git a/Radegast/Core/Contexts/AvatarProfileAction.cs b/Radegast/Core/Contexts/AvatarProfileAction.cs
new file mode 100644 (file)
index 0000000..ee0cc13
--- /dev/null
@@ -0,0 +1,31 @@
+using System;\r
+using OpenMetaverse;\r
+using System.Windows.Forms;\r
+\r
+namespace Radegast\r
+{\r
+    public class AvatarProfileAction : ContextAction\r
+    {\r
+        public AvatarProfileAction(RadegastInstance inst)\r
+            : base(inst)\r
+        {\r
+            Label = "Profile";\r
+            ContextType = typeof(Avatar);\r
+        }\r
+        public override bool IsEnabled(object target)\r
+        {\r
+            return true;\r
+        }\r
+        public override void OnInvoke(object sender, EventArgs e, object target)\r
+        {\r
+            UUID id = ToUUID(target);\r
+            if (id == UUID.Zero) id = ToUUID(sender);\r
+            if (id == UUID.Zero)\r
+            {\r
+                DebugLog("cannot find avatar" + target);\r
+                return;\r
+            }\r
+            (new frmProfile(instance, instance.getAvatarName(id), id)).Show();\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/Radegast/Core/Contexts/ContextAction.cs b/Radegast/Core/Contexts/ContextAction.cs
new file mode 100644 (file)
index 0000000..f1b3888
--- /dev/null
@@ -0,0 +1,201 @@
+using System;\r
+using System.Drawing;\r
+using System.Windows.Forms;\r
+using OpenMetaverse;\r
+\r
+namespace Radegast\r
+{\r
+    public class ContextAction : IContextAction\r
+    {\r
+        public Type ContextType;\r
+        public virtual string Label { get; set; }\r
+        public EventHandler Handler;\r
+        protected RadegastInstance instance;\r
+        public bool Enabled { get; set; }\r
+        public virtual object DeRef(object o)\r
+        {\r
+            if (o is Control)\r
+            {\r
+                Control control = (Control) o;\r
+                if (control.Tag != null) return control.Tag;\r
+                if (!string.IsNullOrEmpty(control.Text)) return control.Text;\r
+                if (!string.IsNullOrEmpty(control.Name)) return control.Name;\r
+            }\r
+            else if (o is ListViewItem)\r
+            {\r
+                ListViewItem control = (ListViewItem) o;\r
+                if (control.Tag != null) return control.Tag;\r
+                if (!string.IsNullOrEmpty(control.Name)) return control.Name;\r
+                if (!string.IsNullOrEmpty(control.Text)) return control.Text;\r
+            }\r
+            return o;\r
+        }\r
+        protected ContextActionsManager ContextActionManager\r
+        {\r
+            get { return Instance.ContextActionManager; }\r
+        }\r
+        public virtual RadegastInstance Instance\r
+        {\r
+            get\r
+            {\r
+                return instance;\r
+            }\r
+            set\r
+            {\r
+                if (instance == value)\r
+                    return;\r
+                instance = value;\r
+            }\r
+        }\r
+\r
+        protected virtual GridClient Client\r
+        {\r
+            get\r
+            {\r
+                return Instance.Client;\r
+            }\r
+        }\r
+\r
+        public ContextAction(RadegastInstance inst)\r
+        {\r
+            Enabled = true;\r
+            instance = inst;\r
+        }\r
+\r
+        public virtual bool IsEnabled(object target)\r
+        {\r
+            return Enabled && Contributes(target);\r
+        }\r
+\r
+        public virtual ToolStripItem GetToolItem(object target)\r
+        {\r
+            return new ToolStripMenuItem(\r
+                LabelFor(target), (Image) null,\r
+                (sender, e) => TryCatch(() => OnInvoke(sender, e, target)))\r
+                       {\r
+                           Enabled = IsEnabled(target),\r
+                       };\r
+        }\r
+\r
+        protected void TryCatch(MethodInvoker func)\r
+        {\r
+            try\r
+            {\r
+                func();\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                DebugLog("Exception: " + e);\r
+            }\r
+        }\r
+\r
+\r
+        public virtual string LabelFor(object target)\r
+        {\r
+            return Label;\r
+        }\r
+\r
+        public virtual Button GetButton(object target)\r
+        {\r
+            Button button = new Button { Text = LabelFor(target), Enabled = IsEnabled(target) };\r
+            button.Click += (sender, e) => TryCatch(() => OnInvoke(sender, e, target));\r
+            return button;\r
+        }\r
+\r
+        public virtual bool TypeContributes(Type o)\r
+        {\r
+            return ContextType.IsAssignableFrom(o);\r
+        }\r
+\r
+        public virtual bool Contributes(Object o)\r
+        {\r
+            if (o==null) return false;\r
+            object oo = DeRef(o);\r
+            return (oo != o && Contributes(oo)) || TypeContributes(o.GetType());\r
+        }\r
+\r
+        public virtual void OnInvoke(object sender, EventArgs e, object target)\r
+        {\r
+            if (Handler != null) Handler(DeRef(target ?? sender), e);\r
+        }\r
+\r
+        public virtual void IContextAction(RadegastInstance instance)\r
+        {\r
+            Instance = instance;\r
+        }\r
+\r
+        public virtual void Dispose()\r
+        {           \r
+        }\r
+\r
+        public Primitive ToPrimitive(object target)\r
+        {\r
+            Primitive thePrim = ((target is Primitive) ? (Primitive)target : null);\r
+            if (thePrim != null) return thePrim;\r
+            object oo = DeRef(target);\r
+            if (oo != target)\r
+            {\r
+                thePrim = ToAvatar(oo);\r
+                if (thePrim != null) return thePrim;\r
+            }\r
+            UUID uuid = ((target is UUID) ? (UUID)target : UUID.Zero);\r
+            if (uuid != UUID.Zero)\r
+                thePrim = Client.Network.CurrentSim.ObjectsPrimitives.Find(prim => (prim.ID == uuid));\r
+            return thePrim;\r
+        }\r
+\r
+        public Avatar ToAvatar(object target)\r
+        {\r
+            Primitive thePrim = ((target is Primitive) ? (Primitive)target : null);\r
+            if (thePrim != null) return (Avatar)thePrim;\r
+            object oo = DeRef(target);\r
+            if (oo != target)\r
+            {\r
+                thePrim = ToAvatar(oo);\r
+                if (thePrim != null) return (Avatar)thePrim;\r
+            }\r
+            UUID uuid = ((target is UUID) ? (UUID)target : UUID.Zero);\r
+            if (uuid != UUID.Zero)\r
+                thePrim = Client.Network.CurrentSim.ObjectsAvatars.Find(prim => (prim.ID == uuid));\r
+            return (Avatar)thePrim;\r
+        }\r
+\r
+        public UUID ToUUID(object target)\r
+        {\r
+            UUID uuid = ((target is UUID) ? (UUID)target : UUID.Zero);\r
+            if (target is FriendInfo)\r
+            {\r
+                return ((FriendInfo) target).UUID;\r
+            }\r
+            if (target is GroupMember)\r
+            {\r
+                return ((GroupMember)target).ID;\r
+            }\r
+            if (uuid != UUID.Zero) return uuid;\r
+            object oo = DeRef(target);\r
+            if (oo != target)\r
+            {\r
+                uuid = ToUUID(oo);\r
+                if (uuid != UUID.Zero) return uuid;\r
+            }\r
+            string str = ((target is string) ? (string)target : null);\r
+            if (string.IsNullOrEmpty(str))\r
+            {\r
+                if (UUID.TryParse(str, out uuid))\r
+                {\r
+                    return uuid;\r
+                }\r
+            }\r
+            Primitive prim = ToPrimitive(target);\r
+            if (prim != null) return prim.ID;\r
+            Avatar avatar = ToAvatar(target);\r
+            if (avatar != null) return avatar.ID;\r
+            return uuid;\r
+        }\r
+\r
+        public void DebugLog(string s)\r
+        {\r
+            instance.TabConsole.DisplayNotificationInChat(string.Format("ContextAction {0}: {1}", Label, s));\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/Radegast/Core/Contexts/ContextActionsManager.cs b/Radegast/Core/Contexts/ContextActionsManager.cs
new file mode 100644 (file)
index 0000000..26959bc
--- /dev/null
@@ -0,0 +1,213 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Drawing;\r
+using System.Windows.Forms;\r
+using OpenMetaverse;\r
+\r
+namespace Radegast\r
+{\r
+    public class ContextActionsManager : IDisposable\r
+    {\r
+        List<IContextAction> contextEventHandlers = new List<IContextAction>();\r
+        private readonly RadegastInstance instance;\r
+        public ContextActionsManager(RadegastInstance instance)\r
+        {\r
+            this.instance = instance;\r
+        }\r
+\r
+        /// <summary>\r
+        ///             AddContextMenu(typeof(Object), "Clueless Object!",\r
+        ///                   (obj, hand)\r
+        ///                   => Console.WriteLine("I am an Object!: {0} {1} {2}", obj, hand, obj.GetType()));\r
+        /// </summary>\r
+        /// <param name="libomvType"></param>\r
+        /// <param name="label"></param>\r
+        /// <param name="handler"></param>\r
+        public void AddContextMenu(Type libomvType, String label, EventHandler handler)\r
+        {\r
+            AddContextMenu(new ContextAction(instance)\r
+                               {\r
+                                   Label = label,\r
+                                   Handler = handler,\r
+                                   ContextType = libomvType\r
+                               });\r
+        }\r
+\r
+        public void AddContextMenu(IContextAction handler)\r
+        {\r
+            lock (contextEventHandlers)\r
+            {\r
+                handler.IContextAction(instance);\r
+                contextEventHandlers.Add(handler);\r
+            }\r
+        }\r
+\r
+        internal void AddContributions(ToolStripDropDown strip, Object o)\r
+        {\r
+            AddContributions(strip, o.GetType(), o);\r
+        }\r
+\r
+        public void AddContributions(ToolStripDropDown strip, List<ToolStripItem> items)\r
+        {\r
+            if (items==null || items.Count == 0) return; \r
+            foreach(var i in strip.Items)\r
+            {\r
+               if (i is ToolStripItem)\r
+               {\r
+                   ToolStripItem item = (ToolStripItem) i;\r
+                   if (string.IsNullOrEmpty(item.Text)) continue;\r
+                   ToolStripItem dup = items.Find((o)=> !string.IsNullOrEmpty(o.Text) && o.Text.ToLower() == item.Text.ToLower());\r
+                   if (dup!=null)\r
+                       items.Remove(dup);\r
+               }\r
+            }\r
+            if (items.Count == 0) return; \r
+            strip.Items.AddRange(items.ToArray());\r
+            strip.Closing += ((sender, args) => items.ForEach((o) => strip.Items.Remove(o)));\r
+        }\r
+\r
+        internal void AddContributions(ToolStripDropDown strip, Type type, Object obj, params Control[] controls)\r
+        {\r
+            List<ToolStripItem> items = new List<ToolStripItem>();\r
+            GleanContributions(strip, type, obj, controls);\r
+            if (strip.Parent != null) GleanContributions(strip, type, obj, strip.Parent);\r
+            foreach (IContextAction i in contextEventHandlers)\r
+            {\r
+                if (!i.TypeContributes(type) && !i.Contributes(obj)) continue;\r
+                items.Add(i.GetToolItem(obj));\r
+            }\r
+            items.Sort(CompareItems);\r
+            if (strip.Items.Count > 0) items.Insert(0, new ToolStripSeparator());\r
+            //if (!instance.advancedDebugging) return;\r
+            if (items.Count > 1) items.Add(new ToolStripSeparator());\r
+            string newVariable = obj.GetType() == type\r
+                                     ? type.Name\r
+                                     : string.Format("{0} -> {1}", obj.GetType().Name, type.Name);\r
+            items.Add(new ToolStripMenuItem(newVariable, null,\r
+                                            (sender, e) =>\r
+                                            instance.TabConsole.DisplayNotificationInChat(\r
+                                                string.Format(" sender={0}\ntarget={1}", ToString(sender), ToString(obj)))\r
+\r
+                          )\r
+            {\r
+                Enabled = true,\r
+                ToolTipText = "" + obj\r
+            });\r
+\r
+            AddContributions(strip, items);\r
+        }\r
+\r
+        private string ToString(object sender)\r
+        {\r
+            string t = sender.GetType().Name + ":";\r
+            if (sender is Control)\r
+            {\r
+                Control control = (Control)sender;\r
+                return string.Format("{0}{1} {2} {3}", t, control.Text, control.Name, ToString(control.Tag));\r
+            }\r
+            if (sender is ListViewItem)\r
+            {\r
+                ListViewItem control = (ListViewItem)sender;\r
+                return string.Format("{0}{1} {2} {3}", t, control.Text, control.Name, ToString(control.Tag));\r
+            }\r
+            return t + sender;\r
+        }\r
+\r
+        public void GleanContributions(ToolStripDropDown strip, Type type, Object obj, params Control[] controls)\r
+        {\r
+            List<ToolStripItem> items = new List<ToolStripItem>();\r
+            foreach (Control control in controls) GleanContributions(items, type, control, obj);                \r
+            if (obj is Control)\r
+            {\r
+                Control control1 = (Control) obj;\r
+                GleanContributions(items, type, control1.Parent, obj);\r
+            }\r
+            if (items.Count == 0) return;\r
+            items.Sort(CompareItems);\r
+            if (strip.Items.Count > 0) items.Insert(0, new ToolStripSeparator());\r
+            AddContributions(strip, items);\r
+        }\r
+\r
+        public void GleanContributions(List<ToolStripItem> items, Type type, Control control, Object obj)\r
+        {\r
+            if (control == null) return;\r
+            if (control is Button)\r
+            {\r
+                Button button = (Button) control;\r
+                string newVariable = obj.GetType() == type\r
+                                         ? type.Name\r
+                                         : string.Format("{0} -> {1}", obj.GetType().Name, type.Name);\r
+                items.Add(new ToolStripMenuItem(button.Text, null,\r
+                                                (sender, e) =>\r
+                                                    {\r
+                                                        button.PerformClick();\r
+                                                        Logger.DebugLog(String.Format("Button: {0} {1} {2} {3}",\r
+                                                                                      newVariable, e, sender, obj));\r
+                                                    })\r
+                              {\r
+                                  Enabled = button.Enabled,\r
+                                  ToolTipText = "" + obj\r
+                              });\r
+                return;\r
+            }\r
+            foreach (object v in control.Controls)\r
+                GleanContributions(items, type, (Control) v, obj);\r
+        }\r
+\r
+        static int CompareItems(ToolStripItem i1, ToolStripItem i2)\r
+        {\r
+            if (i1 == i2) return 0;\r
+            if (i1 is ToolStripSeparator)\r
+                return (i2 is ToolStripSeparator) ? 0 : -1;\r
+            int i = string.Compare(i1.Text, i2.Text);\r
+            return i == 0 ? i1.GetHashCode().CompareTo(i2.GetHashCode()) : i;\r
+        }\r
+\r
+        public void Dispose()\r
+        {\r
+            lock (contextEventHandlers)\r
+            {\r
+                foreach (IContextAction handler in contextEventHandlers)\r
+                {\r
+                    try\r
+                    {\r
+                        handler.Dispose();\r
+                    }\r
+                    catch (Exception) { }\r
+                }\r
+                contextEventHandlers.Clear();\r
+            }\r
+\r
+        }\r
+        public void LoadType(Type type)\r
+        {\r
+            if (typeof(IContextAction).IsAssignableFrom(type) && type != typeof(ContextAction))\r
+            {\r
+                try\r
+                {\r
+                    var c = type.GetConstructor(new Type[] { typeof(RadegastInstance) });\r
+                    if (c != null)\r
+                    {\r
+                        IContextAction plug = (IContextAction)c.Invoke(new object[] { instance });\r
+                        AddContextMenu(plug);\r
+                        return;\r
+                    }\r
+                    c = type.GetConstructor(Type.EmptyTypes);\r
+                    if (c != null)\r
+                    {\r
+                        IContextAction plug = (IContextAction)c.Invoke(new object[0]);\r
+                        AddContextMenu(plug);\r
+                        return;\r
+                    }\r
+                }\r
+                catch (Exception ex)\r
+                {\r
+                    Logger.Log("ERROR in Radegast Command: " + type + " because " + ex.Message + " " + ex.StackTrace,\r
+                               Helpers.LogLevel.Debug);\r
+                    throw ex;\r
+                }\r
+                return;\r
+            }\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/Radegast/Core/Contexts/DeRezObjectAction.cs b/Radegast/Core/Contexts/DeRezObjectAction.cs
new file mode 100644 (file)
index 0000000..f7be86f
--- /dev/null
@@ -0,0 +1,30 @@
+using System;\r
+using OpenMetaverse;\r
+\r
+namespace Radegast\r
+{\r
+    public class DeRezObjectAction : ContextAction\r
+    {\r
+        public DeRezObjectAction(RadegastInstance inst)\r
+            : base(inst)\r
+        {\r
+            Label = "DeRez..";\r
+            ContextType = typeof(Primitive);\r
+        }\r
+\r
+        public override void OnInvoke(object sender, EventArgs e, object target)\r
+        {\r
+            Primitive thePrim = ToPrimitive(target) ?? ToPrimitive(sender);\r
+            if (thePrim == null)\r
+            {\r
+                DebugLog("Not found prim: " + sender + " " +target);\r
+                return;\r
+            }\r
+            DebugLog("Found prim: " + thePrim);\r
+            Client.Inventory.RequestDeRezToInventory(\r
+                thePrim.LocalID, DeRezDestination.AgentInventoryTake,\r
+                Client.Inventory.FindFolderForType(AssetType.TrashFolder),\r
+                UUID.Random());\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/Radegast/Core/Contexts/IContextAction.cs b/Radegast/Core/Contexts/IContextAction.cs
new file mode 100644 (file)
index 0000000..64ac337
--- /dev/null
@@ -0,0 +1,17 @@
+using System;\r
+using System.Windows.Forms;\r
+\r
+namespace Radegast\r
+{\r
+    public interface IContextAction : IDisposable\r
+    {\r
+        void IContextAction(RadegastInstance instance);\r
+        ToolStripItem GetToolItem(object target);\r
+        Button GetButton(object target);\r
+        bool IsEnabled(object target);\r
+        string LabelFor(object target);\r
+        bool TypeContributes(Type o);\r
+        bool Contributes(Object o);\r
+        void OnInvoke(object sender, EventArgs e, object target);\r
+    }\r
+}
\ No newline at end of file
diff --git a/Radegast/Core/Contexts/RezInventoryObjectAction.cs b/Radegast/Core/Contexts/RezInventoryObjectAction.cs
new file mode 100644 (file)
index 0000000..820678a
--- /dev/null
@@ -0,0 +1,22 @@
+using System;\r
+using OpenMetaverse;\r
+\r
+namespace Radegast\r
+{\r
+    public class RezInventoryObjectAction : ContextAction\r
+    {\r
+        public RezInventoryObjectAction(RadegastInstance inst)\r
+            : base(inst)\r
+        {\r
+            Label = "Rez..";\r
+            ContextType = typeof(InventoryObject);\r
+        }\r
+        public override void OnInvoke(object sender, EventArgs e, object target)\r
+        {\r
+            Client.Inventory.RequestRezFromInventory(\r
+                Client.Network.CurrentSim,\r
+                Client.Self.SimRotation, Client.Self.SimPosition,\r
+                (InventoryItem) (target ?? sender));\r
+        }\r
+    }\r
+}
\ No newline at end of file
index 95703e7..7f626c8 100644 (file)
@@ -135,6 +135,11 @@ namespace Radegast
         /// </summary>\r
         public CommandsManager CommandsManager { get { return commandsManager; } }\r
 \r
+        /// <summary>\r
+        /// Radegast ContextAction manager for context sensitive actions\r
+        /// </summary>\r
+        public ContextActionsManager ContextActionManager { get; private set; }\r
+\r
         private SleekMovement movement;\r
         /// <summary>\r
         /// Allows key emulation for moving avatar around\r
@@ -155,6 +160,7 @@ namespace Radegast
             state = new StateManager(this);\r
             mediaManager = new MediaManager(this);\r
             commandsManager = new CommandsManager(this);\r
+            ContextActionManager = new ContextActionsManager(this);\r
             movement = new SleekMovement(client);\r
 \r
             InitializeLoggingAndConfig();\r
@@ -224,6 +230,8 @@ namespace Radegast
             movement = null;\r
             commandsManager.Dispose();\r
             commandsManager = null;\r
+            ContextActionManager.Dispose();\r
+            ContextActionManager = null;\r
             mediaManager.Dispose();\r
             mediaManager = null;\r
             state.Dispose();\r
@@ -292,6 +300,7 @@ namespace Radegast
                     try\r
                     {\r
                         commandsManager.LoadType(type);\r
+                        ContextActionManager.LoadType(type);\r
                     }\r
                     catch (Exception ex)\r
                     {\r
index 6dab114..6c789c1 100644 (file)
@@ -452,6 +452,16 @@ namespace Radegast
             tab = null;\r
         }\r
 \r
+\r
+        public void AddContextMenu(Type libomvType, String label, EventHandler handler)\r
+        {\r
+            instance.ContextActionManager.AddContextMenu(libomvType, label, handler);\r
+        }\r
+        public void AddContextMenu(ContextAction handler)\r
+        {\r
+            instance.ContextActionManager.AddContextMenu(handler);\r
+        }\r
+\r
         public void AddTab(SleekTab tab)\r
         {\r
             ToolStripButton button = (ToolStripButton)tstTabs.Items.Add(tab.Label);\r