[tasque/viewmodel: 35/78] Outsource tray logic from Application.cs



commit 82b1dbd600d7fbc354860b6df55683b8eda6ac4a
Author: Antonius Riha <antoniusriha gmail com>
Date:   Mon Jul 30 16:15:10 2012 +0200

    Outsource tray logic from Application.cs
    
    * AppIndicator.cs: Tray icon for Ubuntu's Unity desktop. This
    should fix the bug, that the tray icon isn't displayed in Unity. (Though
    the fix is not yet complete: need to change build settings, to only use
    this if appindicator-sharp is present.)
    * StatusIcon.cs: Fallback systray for non-Unity desktops
    * GtkTrayBase.cs: Common base class of the above two.
    * TrayModelcs: The viewmodel that provides all the data for the
    tray to work.
    * Tasque.Gtk.csproj: IMPORTANT: Currently there is no check if
    appinidicator-sharp is present on the build machine. This must be added
    for the build to work on systems where appindicator is not available.
    
    Note: AppIndicator tray and StatusIcon tray work a little different:
    Toggling the main window in AppIndicator is done via a menu item
    (due to a limitation of AppIndicator API),
    whereas StatusIcon toggles via clicking the icon.

 src/Tasque.Gtk/AppIndicatorTray.cs   |   59 +++++++++++++++++++
 src/Tasque.Gtk/Application.cs        |   23 +-------
 src/Tasque.Gtk/GtkApplicationBase.cs |   59 -------------------
 src/Tasque.Gtk/GtkTrayBase.cs        |  105 ++++++++++++++++++++++++++++++++++
 src/Tasque.Gtk/StatusIconTray.cs     |   61 ++++++++++++++++++++
 src/Tasque.Gtk/Tasque.Gtk.csproj     |    7 ++
 src/libtasqueui/Legacy/TrayModel.cs  |   18 ++++++-
 7 files changed, 250 insertions(+), 82 deletions(-)
---
diff --git a/src/Tasque.Gtk/AppIndicatorTray.cs b/src/Tasque.Gtk/AppIndicatorTray.cs
new file mode 100644
index 0000000..ee2ea24
--- /dev/null
+++ b/src/Tasque.Gtk/AppIndicatorTray.cs
@@ -0,0 +1,59 @@
+// 
+// AppIndicatorTray.cs
+//  
+// Author:
+//       Antonius Riha <antoniusriha gmail com>
+// 
+// Copyright (c) 2012 Antonius Riha
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using Gtk;
+using AppIndicator;
+using Tasque.UIModel.Legacy;
+
+namespace Tasque
+{
+	public class AppIndicatorTray : GtkTrayBase
+	{
+		public AppIndicatorTray (TrayModel viewModel) : base (viewModel)
+		{
+			var appIndicator = new ApplicationIndicator ("TasqueTray", ViewModel.IconName,
+			                                             AppIndicator.Category.ApplicationStatus);
+			appIndicator.Status = Status.Active;
+			
+			viewModel.ToggleTaskWindow.Executed += delegate { UpdateToggleTaskWindowActionLabel (); };
+			
+			var menu = Menu;
+			var toggleTaskWindowMenuItem = new MenuItem ();
+			ToggleTaskWindowAction.ConnectProxy (toggleTaskWindowMenuItem);
+			UpdateToggleTaskWindowActionLabel ();
+			menu.Insert (toggleTaskWindowMenuItem, 0);
+			menu.Insert (new SeparatorMenuItem (), 1);
+			menu.ShowAll ();
+			
+			appIndicator.Menu = menu;
+		}
+		
+		void UpdateToggleTaskWindowActionLabel ()
+		{
+			ToggleTaskWindowAction.Label = ViewModel.IsTaskWindowVisible ? "Hide Task Window"
+				: "Show Task Window";
+		}
+	}
+}
diff --git a/src/Tasque.Gtk/Application.cs b/src/Tasque.Gtk/Application.cs
index f610c47..d54964b 100644
--- a/src/Tasque.Gtk/Application.cs
+++ b/src/Tasque.Gtk/Application.cs
@@ -111,16 +111,6 @@ namespace Tasque
 			}
 		}
 
-		public UIManager UIManager
-		{
-			get { return uiManager; }
-		}
-
-		public StatusIcon Tray
-		{
-			get { return trayIcon; }
-		}
-
 		public static Preferences Preferences
 		{
 			get { return Application.Instance.preferences; }
@@ -585,18 +575,7 @@ namespace Tasque
 			TaskWindow.ToggleWindowVisible ();
 		}
 
-		private void OnTrayIconPopupMenu (object sender, EventArgs args)
-		{
-			Menu popupMenu = (Menu) uiManager.GetWidget ("/TrayIconMenu");
-
-			bool backendItemsSensitive = (backend != null && backend.Initialized);
-			
-			uiManager.GetAction ("/TrayIconMenu/NewTaskAction").Sensitive = backendItemsSensitive;
-			uiManager.GetAction ("/TrayIconMenu/RefreshAction").Sensitive = backendItemsSensitive;
-
-			popupMenu.ShowAll(); // shows everything
-			popupMenu.Popup();
-		}		
+		
 
 		public static void Main(string[] args)
 		{
diff --git a/src/Tasque.Gtk/GtkApplicationBase.cs b/src/Tasque.Gtk/GtkApplicationBase.cs
index ef3c955..c175bfa 100644
--- a/src/Tasque.Gtk/GtkApplicationBase.cs
+++ b/src/Tasque.Gtk/GtkApplicationBase.cs
@@ -108,65 +108,6 @@ namespace Tasque
 				RemoteInstanceKnocked (this, EventArgs.Empty);
 		}
 		
-		void RegisterUIManager ()
-		{
-			ActionGroup trayActionGroup = new ActionGroup ("Tray");
-//			trayActionGroup.Add (new ActionEntry [] {
-//				new ActionEntry ("NewTaskAction",
-//				                 Stock.New,
-//				                 Catalog.GetString ("New Task ..."),
-//				                 null,
-//				                 null,
-//				                 OnNewTask),
-//				
-//				new ActionEntry ("ShowTasksAction",
-//				                 null,
-//				                 Catalog.GetString ("Show Tasks ..."),
-//				                 null,
-//				                 null,
-//				                 OnShowTaskWindow),
-//
-//				new ActionEntry ("AboutAction",
-//				                 Stock.About,
-//				                 OnAbout),
-//				
-//				new ActionEntry ("PreferencesAction",
-//				                 Stock.Preferences,
-//				                 OnPreferences),
-//				
-//				new ActionEntry ("RefreshAction",
-//				                 Stock.Execute,
-//				                 Catalog.GetString ("Refresh Tasks ..."),
-//				                 null,
-//				                 null,
-//				                 OnRefreshAction),
-//				
-//				new ActionEntry ("QuitAction",
-//				                 Stock.Quit,
-//				                 OnQuit)
-//			});
-			
-			uiManager = new UIManager ();
-			uiManager.AddUiFromString (MenuXml);
-			uiManager.InsertActionGroup (trayActionGroup, 0);
-		}
-		
-		UIManager uiManager;
-		const string MenuXml = @"
-<ui>
-	<popup name=""TrayIconMenu"">
-		<menuitem action=""NewTaskAction""/>
-		<separator/>
-		<menuitem action=""PreferencesAction""/>
-		<menuitem action=""AboutAction""/>
-		<separator/>
-		<menuitem action=""RefreshAction""/>
-		<separator/>
-		<menuitem action=""QuitAction""/>
-	</popup>
-</ui>
-";
-		
 		string confDir;
 	}
 }
diff --git a/src/Tasque.Gtk/GtkTrayBase.cs b/src/Tasque.Gtk/GtkTrayBase.cs
new file mode 100644
index 0000000..54ec74c
--- /dev/null
+++ b/src/Tasque.Gtk/GtkTrayBase.cs
@@ -0,0 +1,105 @@
+// 
+// GtkTrayBase.cs
+//  
+// Author:
+//       Antonius Riha <antoniusriha gmail com>
+// 
+// Copyright (c) 2012 Antonius Riha
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Mono.Unix;
+using Gtk;
+using Tasque.UIModel.Legacy;
+
+namespace Tasque
+{
+	public class GtkTrayBase
+	{
+		public GtkTrayBase (TrayModel viewModel)
+		{
+			if (viewModel == null)
+				throw new ArgumentNullException ("viewModel");
+			ViewModel = viewModel;
+			
+			var newTask = viewModel.NewTask;
+			newTask.CanExecuteChanged += delegate {
+				UIManager.GetAction ("/TrayIconMenu/NewTaskAction").Sensitive = newTask.CanExecute;
+			};
+			
+			var refresh = viewModel.Refresh;
+			refresh.CanExecuteChanged += delegate {
+				UIManager.GetAction ("/TrayIconMenu/RefreshAction").Sensitive = refresh.CanExecute;
+			};
+		}
+		
+		protected Menu Menu { get { return (Menu)UIManager.GetWidget ("/TrayIconMenu"); } }
+		
+		protected Gtk.Action ToggleTaskWindowAction { get; private set; }
+		
+		protected UIManager UIManager {
+			get {
+				if (uiManager == null)
+					RegisterUIManager ();
+				return uiManager;
+			}
+		}
+		
+		protected TrayModel ViewModel { get; private set; }
+		
+		void RegisterUIManager ()
+		{
+			ActionGroup trayActionGroup = new ActionGroup ("Tray");
+			trayActionGroup.Add (new ActionEntry [] {
+				new ActionEntry ("NewTaskAction", Stock.New, Catalog.GetString ("New Task ..."),
+				                 null, null, delegate { ViewModel.NewTask.Execute (); }),
+				new ActionEntry ("AboutAction", Stock.About, delegate { ViewModel.ShowAbout.Execute (); }),
+				new ActionEntry ("PreferencesAction", Stock.Preferences,
+				                 delegate { ViewModel.ShowPreferences.Execute (); }),
+				new ActionEntry ("RefreshAction", Stock.Execute, Catalog.GetString ("Refresh Tasks ..."),
+				                 null, null, delegate { ViewModel.Refresh.Execute (); }),
+				new ActionEntry ("QuitAction", Stock.Quit, delegate { ViewModel.Quit.Execute (); })
+			});
+			
+			ToggleTaskWindowAction = new Gtk.Action ("ToggleTaskWindowAction", null);
+			ToggleTaskWindowAction.ActionGroup = trayActionGroup;
+			ToggleTaskWindowAction.Activated += delegate { ViewModel.ToggleTaskWindow.Execute (); };
+			
+			uiManager = new UIManager ();
+			uiManager.AddUiFromString (MenuXml);
+			uiManager.InsertActionGroup (trayActionGroup, 0);
+		}
+		
+		UIManager uiManager;
+		const string MenuXml = @"
+<ui>
+	<popup name=""TrayIconMenu"">
+		<menuitem action=""NewTaskAction""/>
+		<separator/>
+		<menuitem action=""PreferencesAction""/>
+		<menuitem action=""AboutAction""/>
+		<separator/>
+		<menuitem action=""RefreshAction""/>
+		<separator/>
+		<menuitem action=""QuitAction""/>
+	</popup>
+</ui>
+";
+	}
+}
diff --git a/src/Tasque.Gtk/StatusIconTray.cs b/src/Tasque.Gtk/StatusIconTray.cs
new file mode 100644
index 0000000..d1ee86d
--- /dev/null
+++ b/src/Tasque.Gtk/StatusIconTray.cs
@@ -0,0 +1,61 @@
+// 
+// StatusIconTray.cs
+//  
+// Author:
+//       Antonius Riha <antoniusriha gmail com>
+// 
+// Copyright (c) 2012 Antonius Riha
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using Gtk;
+using Tasque.UIModel.Legacy;
+
+namespace Tasque
+{
+	public class StatusIconTray : GtkTrayBase
+	{
+		public StatusIconTray (TrayModel viewModel) : base (viewModel)
+		{
+			tray = new StatusIcon (Utilities.GetIcon (ViewModel.IconName));
+			tray.Visible = true;
+			tray.Activate += HandleActivate;
+			tray.PopupMenu += HandlePopupMenu;
+		}
+
+		void HandleActivate (object sender, System.EventArgs e)
+		{
+			
+		}
+
+		void HandlePopupMenu (object sender, PopupMenuArgs e)
+		{
+			var popupMenu = Menu;
+			
+			//TODO: incorp this logic into viewmodel
+//			bool backendItemsSensitive = (backend != null && backend.Initialized);
+//			uiManager.GetAction ("/TrayIconMenu/NewTaskAction").Sensitive = backendItemsSensitive;
+//			uiManager.GetAction ("/TrayIconMenu/RefreshAction").Sensitive = backendItemsSensitive;
+			
+			popupMenu.ShowAll(); // shows everything
+			tray.PresentMenu (popupMenu, (uint)e.Args [0], (uint)e.Args [1]);			
+		}
+		
+		StatusIcon tray;
+	}
+}
diff --git a/src/Tasque.Gtk/Tasque.Gtk.csproj b/src/Tasque.Gtk/Tasque.Gtk.csproj
index 1edd6c6..fca2ffe 100644
--- a/src/Tasque.Gtk/Tasque.Gtk.csproj
+++ b/src/Tasque.Gtk/Tasque.Gtk.csproj
@@ -93,6 +93,10 @@
       <Package>ndesk-dbus-glib-1.0</Package>
     </Reference>
     <Reference Include="WindowsBase" />
+    <Reference Include="appindicator-sharp, Version=0.2.0.0, Culture=neutral, PublicKeyToken=bcae265d1c7ab4c2">
+      <Private>False</Private>
+      <Package>appindicator-sharp-0.1</Package>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <None Include="..\..\data\sounds\notify.wav">
@@ -122,6 +126,9 @@
     <Compile Include="TaskWindow.cs" />
     <Compile Include="Utilities.cs" />
     <Compile Include="GtkApplicationBase.cs" />
+    <Compile Include="AppIndicatorTray.cs" />
+    <Compile Include="StatusIconTray.cs" />
+    <Compile Include="GtkTrayBase.cs" />
   </ItemGroup>
   <ItemGroup Condition=" '$(Configuration)' == 'GtkWinDebug' or '$(Configuration)' == 'GtkWinRelease' ">
     <Compile Include="GtkWinApplication.cs" />
diff --git a/src/libtasqueui/Legacy/TrayModel.cs b/src/libtasqueui/Legacy/TrayModel.cs
index 561fbd1..d5234e9 100644
--- a/src/libtasqueui/Legacy/TrayModel.cs
+++ b/src/libtasqueui/Legacy/TrayModel.cs
@@ -24,6 +24,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 using System;
+
 namespace Tasque.UIModel.Legacy
 {
 	public class TrayModel : ViewModelBase
@@ -31,6 +32,21 @@ namespace Tasque.UIModel.Legacy
 		public TrayModel ()
 		{
 		}
+		
+		public string IconName { get; private set; }
+		
+		public bool IsTaskWindowVisible { get; private set; }
+		
+		public UICommand NewTask { get { throw new NotImplementedException (); } }
+		
+		public UICommand Quit { get { throw new NotImplementedException (); } }
+		
+		public UICommand Refresh { get { throw new NotImplementedException (); } }
+		
+		public UICommand ShowAbout { get { throw new NotImplementedException (); } }
+		
+		public UICommand ShowPreferences { get { throw new NotImplementedException (); } }
+		
+		public UICommand ToggleTaskWindow { get { throw new NotImplementedException (); } }
 	}
 }
-



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]