// // Copyright (C) 2008-2009 Jordi Mas i Hernandez, jmas@softcatala.org // // 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 Gtk; using System.IO; using System.Text; using Gdk; using System.ComponentModel; using System.Collections.Generic; using Mono.Unix; using Mistelix.DataModel; using Mistelix.Core; using Mistelix.Dialogs; namespace Mistelix.Widgets { // // Displays the project elements that we can drag into the authoring view // public class ProjectElementView : IconView, IDisposable { const int COL_ELEMENT = 0; const int COL_DISPLAY_NAME = 1; const int COL_PIXBUF = 2; ListStore store; Project project; BackgroundWorker thumbnailing; Pixbuf def_image; private static TargetEntry [] tag_target_table = new TargetEntry [] { new TargetEntry ("application/x-mistelix-item", 0, (uint) 2), }; public ProjectElementView (Project project) { this.project = project; // TODO: Only one element dropped? SelectionMode = SelectionMode.Multiple; store = CreateStore (); LoadElements (); TextColumn = COL_DISPLAY_NAME; PixbufColumn = COL_PIXBUF; // Drag DragBegin += HandleDragBegin; DragEnd += HandleDragEnd; DragDataGet += HandleDragDataGet; // Project element view as drag source Gtk.Drag.SourceSet (this, Gdk.ModifierType.Button1Mask | Gdk.ModifierType.Button3Mask, tag_target_table, DragAction.Copy | DragAction.Move); Model = store; def_image = Gtk.IconTheme.Default.LoadIcon ("gtk-new", ThumbnailSizeManager.Current.Width, (Gtk.IconLookupFlags) 0); ItemActivated += new ItemActivatedHandler (OnItemActivated); ButtonPressEvent += new ButtonPressEventHandler (OnButtonPressed); KeyPressEvent += OnKeyPressed; } public Project Project { get { return project; } set { project = value;} } ~ProjectElementView () { Dispose (false); } public override void Dispose () { Dispose (true); System.GC.SuppressFinalize (this); } protected virtual void Dispose (bool disposing) { Logger.Debug ("ProjectElementView.Disposing"); ClearElements (); def_image.Dispose (); store.Dispose (); if (thumbnailing != null) thumbnailing.Dispose (); } void HandleDragDataGet (object sender, DragDataGetArgs args) { Logger.Debug ("ProjectElementView.HandleDragDataGet. Sender {0}, args {1}", sender, args.Info); TreeIter iter; TreePath[] items = SelectedItems; IntList list = new IntList (); VisibleProjectElement element; for (int i = 0; i < items.Length; i++) { store.GetIter (out iter, items [i]); element = (VisibleProjectElement) store.GetValue (iter, COL_ELEMENT); list.Add (element.id); } switch (args.Info) { case 2: { Byte [] data = Encoding.UTF8.GetBytes (list.ToString ()); Atom [] targets = args.Context.Targets; args.SelectionData.Set (targets[0], 3, data); return; } default: Logger.Debug ("ProjectElementView.Drop cancelled"); break; } args.RetVal = true; } void HandleDragBegin (object sender, DragBeginArgs args) { Logger.Debug ("ProjectElementView.HandleDragBegin"); } void HandleDragEnd (object sender, DragEndArgs args) { args.RetVal = true; } ListStore CreateStore () { // TODO: Instead of storing the fullname as the first element we should store an indexer to the project element (see also the last element) ListStore store = new ListStore (typeof (VisibleProjectElement), typeof (string), typeof (Gdk.Pixbuf)); return store; } static void DoWork (object sender, DoWorkEventArgs e) { ListStore store = (ListStore) e.Argument; store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter) { VisibleProjectElement element = (VisibleProjectElement) store.GetValue (iter, COL_ELEMENT); Gdk.Pixbuf im; try { im = element.Thumbnail; } catch (Exception ex) { Logger.Error ("ProjectElementView.Dowork. Exception: " + ex.Message); return false; } Application.Invoke (delegate { store.SetValue (iter, COL_PIXBUF, im); } ); return false; }); } void ClearElements () { store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter) { Gdk.Pixbuf im = (Gdk.Pixbuf) store.GetValue (iter, COL_PIXBUF); im.Dispose (); return false; }); store.Clear (); } public void UpdateElement (ProjectElement element) { store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter) { ProjectElement stored; stored = (ProjectElement) store.GetValue (iter, COL_ELEMENT); if (stored != element) return false; store.SetValue (iter, COL_ELEMENT, element); store.SetValue (iter, COL_PIXBUF, GetThumbnail (element)); return true; }); } Gdk.Pixbuf GetThumbnail (ProjectElement element) { Gdk.Pixbuf thumbnail; try { VisibleProjectElement visible = (VisibleProjectElement) element; thumbnail = visible.Thumbnail; } catch { thumbnail = def_image; } return thumbnail; } public void AddElement (VisibleProjectElement element) { store.AppendValues (element, element.Name, GetThumbnail (element)); } public void LoadElements () { ClearElements (); if (project == null) return; if (thumbnailing != null) thumbnailing.Dispose (); thumbnailing = new BackgroundWorker (); thumbnailing.DoWork += new DoWorkEventHandler (DoWork); VisibleProjectElement element; for (int i = 0; i < project.Elements.Count; i++) { element = (VisibleProjectElement) project.Elements[i]; if (element == null) { Logger.Debug ("ProjectElementView.FillStore. Ignoring {0}", project.Elements[i]); continue; } store.AppendValues (element, element.Name, def_image); } Logger.Debug ("ProjectElementView.FillStore. Elements {0}", project.Elements.Count); thumbnailing.RunWorkerAsync (store); } void OnItemActivated (object sender, ItemActivatedArgs args) { TreeIter iter; VisibleProjectElement current; store.GetIter (out iter, args.Path); current = (VisibleProjectElement) store.GetValue (iter, COL_ELEMENT); ItemActivate (current); } void ItemActivate (VisibleProjectElement current) { if (current.GetType () != typeof (SlideShow)) return; AddSlideDialogRunner.Create (project); AddSlideDialogRunner.Dialog.LoadSlideShow ((SlideShow) current); if (AddSlideDialogRunner.Run () == ResponseType.Ok) { for (int i = 0; i < project.Elements.Count; i++) { if (current == project.Elements[i]) { project.Elements[i] = AddSlideDialogRunner.Dialog.GenerateSlideShow (); UpdateElement (project.Elements[i]); break; } } } AddSlideDialogRunner.ProcessResponse (); } [GLib.ConnectBefore] void OnButtonPressed (object o, ButtonPressEventArgs args) { ExtendedMenu menu; if (args.Event.Button != 3) return; menu = new ExtendedMenu (); menu.AddItem (Catalog.GetString ("Open element"), OnOpenElement); menu.AddItem (Catalog.GetString ("Delete element from project"), OnDeleteElements); menu.Popup (args); args.RetVal = true; } protected override bool OnExposeEvent (Gdk.EventExpose args) { if (project == null || project.Elements.Count > 0) return base.OnExposeEvent (args); // See: http://www.mail-archive.com/mono-list@lists.ximian.com/msg26065.html using (Cairo.Context cr = Gdk.CairoHelper.Create (args.Window)) { int winWidth, winHeight, w, h; args.Window.GetSize (out winWidth, out winHeight); Pango.Layout layout = new Pango.Layout (this.PangoContext); layout.Width = winWidth * (int) Pango.Scale.PangoScale; layout.SetMarkup (Catalog.GetString ("Once the project has elements you can use the contextual menu to work with them")); layout.GetPixelSize (out w, out h); Gdk.GC light = Style.DarkGC (StateType.Normal); args.Window.DrawLayout (light, (winWidth - w) /2, winHeight / 2, layout); layout.Dispose (); } return true; } void OnOpenElement (object obj, EventArgs e) { TreePath[] items = SelectedItems; if (items.Length <= 0) return; ActivateItem (items[0]); } void OnDeleteElements (object obj, EventArgs e) { TreeIter iter; TreePath[] items = SelectedItems; VisibleProjectElement item; Logger.Debug ("ProjectElementView.OnDeleteElement {0} items", items.Length); for (int i = 0; i < items.Length; i++) { store.GetIter (out iter, items [i]); item = (VisibleProjectElement) store.GetValue (iter, COL_ELEMENT); project.RemoveElement (item); store.Remove (ref iter); } } [GLib.ConnectBefore()] void OnKeyPressed (object sender, Gtk.KeyPressEventArgs args) { if (args.Event.Key == Gdk.Key.Delete || args.Event.Key == Gdk.Key.KP_Delete) { args.RetVal = true; OnDeleteElements (sender, EventArgs.Empty); } } } }