// // UserTasksView.cs // // Author: // David Makovský // // Copyright (C) 2006 David Makovský // // 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 System.IO; using System.Collections; using Gtk; using MonoDevelop.Core; using MonoDevelop.Projects; using MonoDevelop.Ide; using MonoDevelop.Ide.Gui; using MonoDevelop.Components; namespace MonoDevelop.Ide.Tasks { internal class UserTasksView : ITaskListView { enum Columns { Priority, Completed, Description, UserTask, Foreground, Bold, Count } Button newButton; Button delButton; MonoDevelop.Ide.Gui.Components.PadTreeView view; ListStore store; CellRendererText cellRendDesc; Gdk.Color highPrioColor, normalPrioColor, lowPrioColor; Clipboard clipboard; bool solutionLoaded = false; bool updating; string[] priorities = { GettextCatalog.GetString ("High"), GettextCatalog.GetString ("Normal"), GettextCatalog.GetString ("Low")}; public UserTasksView () { highPrioColor = StringToColor ((string)PropertyService.Get ("Monodevelop.UserTasksHighPrioColor", "")); normalPrioColor = StringToColor ((string)PropertyService.Get ("Monodevelop.UserTasksNormalPrioColor", "")); lowPrioColor = StringToColor ((string)PropertyService.Get ("Monodevelop.UserTasksLowPrioColor", "")); store = new ListStore ( typeof (string), // priority typeof (bool), // completed typeof (string), // desc typeof (Task), // user task typeof (Gdk.Color), // foreground color typeof (int)); // font style view = new MonoDevelop.Ide.Gui.Components.PadTreeView (store); view.RulesHint = true; view.SearchColumn = (int)Columns.Description; view.Selection.Changed += new EventHandler (SelectionChanged); view.PopupMenu += new PopupMenuHandler (OnUserPopupMenu); view.ButtonPressEvent += new ButtonPressEventHandler (OnUserButtonPressed); TreeViewColumn col; CellRendererComboBox cellRendPriority = new CellRendererComboBox (); cellRendPriority.Values = priorities; cellRendPriority.Editable = true; cellRendPriority.Changed += new ComboSelectionChangedHandler (UserTaskPriorityEdited); col = view.AppendColumn (GettextCatalog.GetString ("Priority"), cellRendPriority, "text", Columns.Priority, "foreground-gdk", Columns.Foreground, "weight", Columns.Bold); col.Clickable = true; col.Resizable = true; TreeIterCompareFunc sortFunc = new TreeIterCompareFunc (PrioirtySortFunc); store.SetSortFunc ((int)Columns.Priority, sortFunc); col.Clicked += new EventHandler (UserTaskPriorityResort); CellRendererToggle cellRendCompleted = new CellRendererToggle (); cellRendCompleted.Toggled += new ToggledHandler (UserTaskCompletedToggled); cellRendCompleted.Activatable = true; col = view.AppendColumn (String.Empty, cellRendCompleted, "active", Columns.Completed); col.Clickable = true; col.Clicked += new EventHandler (UserTaskCompletedResort); cellRendDesc = view.TextRenderer; cellRendDesc.Editable = true; cellRendDesc.Edited += new EditedHandler (UserTaskDescEdited); col = view.AppendColumn (GettextCatalog.GetString ("Description"), cellRendDesc, "text", Columns.Description, "strikethrough", Columns.Completed, "foreground-gdk", Columns.Foreground, "weight", Columns.Bold); col.Clickable = true; col.Resizable = true; col.Clicked += new EventHandler (UserTaskDescResort); newButton = new Button (); newButton.Image = new Gtk.Image (Gtk.Stock.New, IconSize.Button); newButton.Label = GettextCatalog.GetString ("New Task"); newButton.ImagePosition = PositionType.Left; newButton.Clicked += new EventHandler (NewUserTaskClicked); newButton.TooltipText = GettextCatalog.GetString ("Create New Task"); delButton = new Button (new Gtk.Image (Gtk.Stock.Delete, IconSize.Button)); delButton.Clicked += new EventHandler (DeleteUserTaskClicked); delButton.TooltipText = GettextCatalog.GetString ("Delete Task"); TaskService.UserTasks.TasksChanged += (TaskEventHandler) DispatchService.GuiDispatch (new TaskEventHandler (UserTasksChanged)); TaskService.UserTasks.TasksAdded += (TaskEventHandler) DispatchService.GuiDispatch (new TaskEventHandler (UserTasksChanged)); TaskService.UserTasks.TasksRemoved += (TaskEventHandler) DispatchService.GuiDispatch (new TaskEventHandler (UserTasksChanged)); IdeApp.Workspace.FirstWorkspaceItemOpened += CombineOpened; IdeApp.Workspace.LastWorkspaceItemClosed += CombineClosed; PropertyService.PropertyChanged += (EventHandler) DispatchService.GuiDispatch (new EventHandler (OnPropertyUpdated)); ValidateButtons (); // Initialize with existing tags. UserTasksChanged (this, null); } void CombineOpened (object sender, EventArgs e) { solutionLoaded = true; ValidateButtons (); } void CombineClosed (object sender, EventArgs e) { solutionLoaded = true; ValidateButtons (); } void UserTasksChanged (object sender, TaskEventArgs e) { if (updating) return; store.Clear (); foreach (Task task in TaskService.UserTasks) { store.AppendValues (GettextCatalog.GetString (Enum.GetName (typeof (TaskPriority), task.Priority)), task.Completed, task.Description, task, GetColorByPriority (task.Priority), task.Completed ? (int)Pango.Weight.Light : (int)Pango.Weight.Bold); } ValidateButtons (); } void OnPropertyUpdated (object sender, PropertyChangedEventArgs e) { bool change = false; if (e.Key == "Monodevelop.UserTasksHighPrioColor" && e.NewValue != e.OldValue) { highPrioColor = StringToColor ((string)e.NewValue); change = true; } if (e.Key == "Monodevelop.UserTasksNormalPrioColor" && e.NewValue != e.OldValue) { normalPrioColor = StringToColor ((string)e.NewValue); change = true; } if (e.Key == "Monodevelop.UserTasksLowPrioColor" && e.NewValue != e.OldValue) { lowPrioColor = StringToColor ((string)e.NewValue); change = true; } if (change) { TreeIter iter; if (store.GetIterFirst (out iter)) { do { Task task = (Task) store.GetValue (iter, (int)Columns.UserTask); store.SetValue (iter, (int)Columns.Foreground, GetColorByPriority (task.Priority)); } while (store.IterNext (ref iter)); } } } void SelectionChanged (object sender, EventArgs e) { ValidateButtons (); } void ValidateButtons () { newButton.Sensitive = solutionLoaded; delButton.Sensitive = solutionLoaded && view.Selection.CountSelectedRows () > 0; } void NewUserTaskClicked (object obj, EventArgs e) { Task task = new Task (); task.WorkspaceObject = IdeApp.ProjectOperations.CurrentSelectedWorkspaceItem; updating = true; TaskService.UserTasks.Add (task); updating = false; TreeIter iter = store.AppendValues (GettextCatalog.GetString (Enum.GetName (typeof (TaskPriority), task.Priority)), task.Completed, task.Description, task, GetColorByPriority (task.Priority), task.Completed ? (int)Pango.Weight.Light : (int)Pango.Weight.Bold); view.Selection.SelectIter (iter); TreePath path = store.GetPath (iter); view.ScrollToCell (path, view.Columns[(int)Columns.Description], true, 0, 0); view.SetCursorOnCell (path, view.Columns[(int)Columns.Description], cellRendDesc, true); TaskService.SaveUserTasks (task.WorkspaceObject); } void DeleteUserTaskClicked (object obj, EventArgs e) { if (view.Selection.CountSelectedRows () > 0) { TreeIter iter; if (store.GetIter (out iter, view.Selection.GetSelectedRows ()[0])) { Task task = (Task) store.GetValue (iter, (int)Columns.UserTask); updating = true; TaskService.UserTasks.Remove (task); updating = false; store.Remove (ref iter); TaskService.SaveUserTasks (task.WorkspaceObject); } } } void UserTaskPriorityEdited (object o, ComboSelectionChangedArgs args) { Gtk.TreeIter iter; if (store.GetIterFromString (out iter, args.Path)) { Task task = (Task) store.GetValue (iter, (int)Columns.UserTask); if (args.Active == 0) { task.Priority = TaskPriority.High; } else if (args.Active == 1) { task.Priority = TaskPriority.Normal; } else { task.Priority = TaskPriority.Low; } store.SetValue (iter, (int)Columns.Priority, priorities [args.Active]); store.SetValue (iter, (int)Columns.Foreground, GetColorByPriority (task.Priority)); TaskService.SaveUserTasks (task.WorkspaceObject); } } int PrioirtySortFunc (TreeModel model, TreeIter iter1, TreeIter iter2) { TaskPriority prio1 = (TaskPriority) Enum.Parse (typeof (TaskPriority), (string)model.GetValue (iter1, (int)Columns.Priority)); TaskPriority prio2 = (TaskPriority) Enum.Parse (typeof (TaskPriority), (string)model.GetValue (iter2, (int)Columns.Priority)); if (prio1 == prio2) return 0; return prio1 < prio2 ? 1 : -1; } void UserTaskPriorityResort (object sender, EventArgs args) { TreeViewColumn col = view.Columns[(int)Columns.Priority]; foreach (TreeViewColumn c in view.Columns) { if (c != col) c.SortIndicator = false; } col.SortOrder = ReverseSortOrder (col); col.SortIndicator = true; store.SetSortColumnId ((int)Columns.Priority, col.SortOrder); } void UserTaskCompletedToggled (object o, ToggledArgs args) { Gtk.TreeIter iter; if (store.GetIterFromString (out iter, args.Path)) { bool val = (bool)store.GetValue (iter, (int)Columns.Completed); Task task = (Task) store.GetValue (iter, (int)Columns.UserTask); task.Completed = !val; store.SetValue (iter, (int)Columns.Completed, !val); store.SetValue (iter, (int)Columns.Bold, task.Completed ? (int)Pango.Weight.Light : (int)Pango.Weight.Bold); TaskService.SaveUserTasks (task.WorkspaceObject); } } void UserTaskCompletedResort (object sender, EventArgs args) { TreeViewColumn col = view.Columns[(int)Columns.Completed]; foreach (TreeViewColumn c in view.Columns) { if (c != col) c.SortIndicator = false; } col.SortOrder = ReverseSortOrder (col); col.SortIndicator = true; store.SetSortColumnId ((int)Columns.Completed, col.SortOrder); } void UserTaskDescEdited (object o, EditedArgs args) { Gtk.TreeIter iter; if (store.GetIterFromString (out iter, args.Path)) { Task task = (Task) store.GetValue (iter, (int)Columns.UserTask); task.Description = args.NewText; store.SetValue (iter, (int)Columns.Description, args.NewText); TaskService.SaveUserTasks (task.WorkspaceObject); } } void UserTaskDescResort (object sender, EventArgs args) { TreeViewColumn col = view.Columns[(int)Columns.Description]; foreach (TreeViewColumn c in view.Columns) { if (c != col) c.SortIndicator = false; } col.SortOrder = ReverseSortOrder (col); col.SortIndicator = true; store.SetSortColumnId ((int)Columns.Description, col.SortOrder); } Gdk.Color GetColorByPriority (TaskPriority prio) { switch (prio) { case TaskPriority.High: return highPrioColor; case TaskPriority.Normal: return normalPrioColor; default: return lowPrioColor; } } [GLib.ConnectBefore] void OnUserButtonPressed (object o, ButtonPressEventArgs args) { if (args.Event.Button == 3) ShowUserPopup (); } void OnUserPopupMenu (object o, PopupMenuArgs args) { ShowUserPopup (); } void ShowUserPopup () { Menu menu = new Menu (); menu.AccelGroup = new AccelGroup (); ImageMenuItem copy = new ImageMenuItem (Gtk.Stock.Copy, menu.AccelGroup); copy.Activated += new EventHandler (OnUserTaskCopied); menu.Append (copy); menu.Popup (null, null, null, 3, Gtk.Global.CurrentEventTime); menu.ShowAll (); } void OnUserTaskCopied (object o, EventArgs args) { Task task; TreeModel model; TreeIter iter; if (view.Selection.GetSelected (out model, out iter)) { task = (Task) model.GetValue (iter, (int)Columns.UserTask); } else return; // no one selected clipboard = Clipboard.Get (Gdk.Atom.Intern ("CLIPBOARD", false)); clipboard.Text = task.ToString (); clipboard = Clipboard.Get (Gdk.Atom.Intern ("PRIMARY", false)); clipboard.Text = task.ToString (); } static SortType ReverseSortOrder (TreeViewColumn col) { if (col.SortIndicator) { if (col.SortOrder == SortType.Ascending) return SortType.Descending; else return SortType.Ascending; } else { return SortType.Ascending; } } static Gdk.Color StringToColor (string colorStr) { string[] rgb = colorStr.Substring (colorStr.IndexOf (':') + 1).Split ('/'); if (rgb.Length != 3) return new Gdk.Color (0, 0, 0); Gdk.Color color = Gdk.Color.Zero; try { color.Red = UInt16.Parse (rgb[0], System.Globalization.NumberStyles.HexNumber); color.Green = UInt16.Parse (rgb[1], System.Globalization.NumberStyles.HexNumber); color.Blue = UInt16.Parse (rgb[2], System.Globalization.NumberStyles.HexNumber); } catch { // something went wrong, then use neutral black color color = new Gdk.Color (0, 0, 0); } return color; } #region ITaskListView members TreeView ITaskListView.Content { get { return view; } } Widget[] ITaskListView.ToolBarItems { get { return new Widget[] { newButton, delButton }; } } #endregion } }