123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- /*
- * $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.IO;
- using System.Xml;
- using Gtk;
- namespace Gdl
- {
- public class DockLayout
- {
- XmlDocument doc;
- XmlNode rootNode;
- ListStore itemsModel;
- ListStore layoutsModel;
- bool dirty = false;
- bool idleSavePending = false;
- Widget itemsUI, layoutsUI;
- DockMaster master = null;
- ArrayList layouts;
- protected Hashtable placeholders;
- bool loading;
- CheckButton locked_check;
- private const int NAME_COL = 0;
- private const int SHOW_COL = 1;
- private const int LOCK_COL = 2;
- private const int ITEM_COL = 3;
- public DockLayout (Dock dock)
- {
- layouts = new ArrayList ();
- this.Attach (dock.Master);
- BuildModels ();
- }
- public Widget ItemsUI {
- get {
- if (itemsUI == null)
- itemsUI = ConstructItemsUI ();
- return itemsUI;
- }
- }
- public ArrayList Layouts {
- get { return layouts; }
- }
- public Widget LayoutsUI {
- get {
- if (layoutsUI == null)
- layoutsUI = ConstructLayoutsUI ();
- return layoutsUI;
- }
- }
- public DockMaster Master {
- get { return master; }
- set { master = value; }
- }
- private XmlNode RootNode {
- get {
- if (rootNode == null && doc != null)
- rootNode = doc.SelectSingleNode ("/dock-layout");
- return rootNode;
- }
- }
- public Widget UI {
- get { return ConstructUI ();}
- }
- // true if the layouts have changed and need to be saved to a file
- public bool IsDirty {
- get { return dirty; }
- }
- public void Attach (DockMaster master)
- {
- if (master == null)
- return;
- master.LayoutChanged -= new EventHandler (OnLayoutChanged);
- if (itemsModel != null)
- itemsModel.Clear ();
- this.master = master;
- master.LayoutChanged += new EventHandler (OnLayoutChanged);
- UpdateItemsModel ();
- }
- public void DeleteLayout (string name)
- {
- // dont allow deletion of default layout
- if (name == null || name == "__default__")
- return;
- XmlNode node = FindLayout (name);
- if (node != null) {
- this.RootNode.RemoveChild (node);
- dirty = true;
- // notify dirty
- }
- }
- public void Dump ()
- {
- XmlTextWriter writer = new XmlTextWriter (Console.Out);
- writer.Formatting = Formatting.Indented;
- doc.WriteTo (writer);
- }
- public string[] GetLayouts (bool includeDefault)
- {
- return Layouts.ToArray (typeof (string)) as string[];
- }
- public bool LoadFromFile (string file)
- {
- if (doc != null) {
- doc = null;
- dirty = false;
- // notify dirty
- }
- if (File.Exists (file))
- {
- doc = new XmlDocument ();
- Stream s = File.OpenRead (file);
- try {
- doc.Load (s);
- } catch {
- Console.WriteLine ("WARNING: could not load dock layout XML");
- // FIXME: remove corrupt file?
- doc = null;
- }
- s.Close ();
- // minimum validation: test root element
- if (this.RootNode != null) {
- loading = true;
- foreach (XmlNode n in this.RootNode.ChildNodes)
- {
- if (n.Name == "layout")
- layouts.Add (n.Attributes["name"].Value);
- }
- UpdateLayoutsModel ();
- loading = false;
- return true;
- }
- else {
- doc = null;
- }
- }
- return false;
- }
- public bool LoadLayout (string name)
- {
- if (doc == null || master == null)
- return false;
- if (name == null || name.Length < 1)
- name = "__default__";
- XmlNode node = FindLayout (name);
- if (node == null)
- node = FindLayout (null);
- if (node == null)
- return false;
- try {
- loading = true;
- Load (node);
- } finally {
- loading = true;
- }
- return true;
- }
- public void RunManager ()
- {
- if (master == null)
- return;
- Widget container = ConstructUI ();
- if (container == null)
- return;
- Widget parent = master.Controller;
- if (parent != null)
- parent = parent.Toplevel;
- Dialog dialog = new Dialog ();
- dialog.Title = "Layout management";
- dialog.TransientFor = parent as Window;
- dialog.AddButton (Gtk.Stock.Close, Gtk.ResponseType.Close);
- dialog.SetDefaultSize (-1, 300);
- dialog.VBox.Add (container);
- dialog.Run ();
- dialog.Destroy ();
- }
- public void SaveLayout (string name)
- {
- if (master == null)
- return;
- if (doc == null)
- BuildDoc ();
- if (name == null || name.Length < 1)
- name = "__default__";
- // delete any previous node with the same name
- XmlNode node = FindLayout (name);
- if (node != null)
- this.RootNode.RemoveChild (node);
- // create the new node
- XmlElement element = doc.CreateElement ("layout");
- element.SetAttribute ("name", name);
- this.RootNode.AppendChild (element);
- // save the layout
- Save (element);
- dirty = true;
- // notify dirty
- }
- public bool SaveToFile (string file)
- {
- if (file == null)
- return false;
- // if there is still no xml doc, create an empty one
- if (doc == null)
- BuildDoc ();
- XmlTextWriter writer = new XmlTextWriter (file, System.Text.Encoding.UTF8);
- writer.Formatting = Formatting.Indented;
- doc.WriteTo (writer);
- writer.Flush ();
- writer.Close ();
- dirty = false;
- // notify dirty
- return true;
- }
- void BuildModels ()
- {
- // NAME, SHOW, LOCKED, ITEM
- itemsModel = new ListStore (typeof (string), typeof (bool), typeof (bool), typeof (DockItem));
- itemsModel.SetSortColumnId (NAME_COL, SortType.Ascending);
- layoutsModel = new ListStore (typeof (string), typeof (bool));
- layoutsModel.SetSortColumnId (NAME_COL, SortType.Ascending);
- }
- void BuildDoc ()
- {
- doc = new XmlDocument ();
- doc.CreateXmlDeclaration ("1.0", null, null);
- doc.AppendChild (doc.CreateElement ("dock-layout"));
- }
- XmlNode FindLayout (string name)
- {
- if (doc == null)
- return null;
- foreach (XmlNode n in doc.SelectNodes ("/dock-layout/layout"))
- {
- if (n.Attributes["name"].Value == name)
- return n;
- }
- return null;
- }
- void UpdateItemsModel ()
- {
- if (itemsModel == null || master == null)
- return;
- // build items list
- ArrayList items = new ArrayList ();
- foreach (object o in master.DockObjects) {
- if (o is DockItem)
- items.Add (o);
- }
- TreeIter iter;
- // update items model data after a layout load
- if (itemsModel.GetIterFirst (out iter)) {
- bool valid = true;
- walk_start:
- while (valid) {
- DockItem item = itemsModel.GetValue (iter, 3) as DockItem;
- if (item != null) {
- // look for the object in the items list
- for (int i = 0; i < items.Count; i ++)
- {
- // found, update data
- if (item == items[i]) {
- UpdateItemData (iter, item);
- items.RemoveAt (i);
- valid = itemsModel.IterNext (ref iter);
- goto walk_start;
- }
- }
- // FIXME: not found, skip it?
- valid = itemsModel.IterNext (ref iter);
- }
- else {
- // not a valid row
- valid = itemsModel.Remove (ref iter);
- }
- }
- }
- // add any remaining objects
- foreach (DockItem ditem in items)
- itemsModel.AppendValues (ditem.Name, ditem.IsAttached, ditem.Locked, ditem);
- }
- void UpdateItemData (TreeIter iter, DockItem item)
- {
- itemsModel.SetValue (iter, NAME_COL, item.Name);
- itemsModel.SetValue (iter, SHOW_COL, item.IsAttached);
- itemsModel.SetValue (iter, LOCK_COL, item.Locked);
- }
- void UpdateLayoutsModel ()
- {
- if (master == null || layoutsModel == null)
- return;
- // build layouts list
- layoutsModel.Clear ();
- foreach (string s in this.Layouts) {
- if (s != "__default__")
- layoutsModel.AppendValues (s, true);
- }
- }
- Notebook ConstructUI ()
- {
- Notebook notebook = new Notebook ();
- notebook.Show ();
- Widget child;
- child = ConstructItemsUI ();
- if (child != null)
- notebook.AppendPage (child, new Label ("Items"));
- child = ConstructLayoutsUI ();
- if (child != null)
- notebook.AppendPage (child, new Label ("Layouts"));
- notebook.CurrentPage = 0;
- return notebook;
- }
- Widget ConstructItemsUI ()
- {
- Glade.XML gui = LoadInterface ("items_vbox");
- if (gui == null)
- return null;
- Gtk.VBox container = gui.GetWidget ("items_vbox") as VBox;
- locked_check = gui.GetWidget ("locked_check") as CheckButton;
- Gtk.TreeView items_list = gui.GetWidget ("items_list") as TreeView;
- locked_check.Toggled += new EventHandler (AllLockedToggledCb);
- if (master != null) {
- master.NotifyLocked += new EventHandler (MasterLockedNotifyCb);
- // force update now
- MasterLockedNotifyCb (master, EventArgs.Empty);
- }
- // set models
- items_list.Model = itemsModel;
- // construct list views
- CellRendererToggle renderer = new CellRendererToggle ();
- renderer.Toggled += new ToggledHandler (ShowToggledCb);
- TreeViewColumn column = new TreeViewColumn ("Visible", renderer, "active", 1);
- items_list.AppendColumn (column);
- items_list.AppendColumn ("Item", new CellRendererText (), "text", 0);
- return container;
- }
- Widget ConstructLayoutsUI ()
- {
- Glade.XML gui = LoadInterface ("layouts_vbox");
- if (gui == null)
- return null;
- Gtk.VBox container = gui.GetWidget ("layouts_vbox") as VBox;
- Gtk.TreeView layouts_list = gui.GetWidget ("layouts_list") as TreeView;
- layouts_list.Model = layoutsModel;
- CellRendererText renderer = new CellRendererText ();
- renderer.Edited += new EditedHandler (CellEditedCb);
- TreeViewColumn column = new TreeViewColumn ("Name", renderer, "text", 0, "editable", 1);
- layouts_list.AppendColumn (column);
- return container;
- }
- Glade.XML LoadInterface (string topWidget)
- {
- return new Glade.XML (null, "layout.glade", topWidget, null);
- }
- DockObject SetupObject (XmlNode node)
- {
- DockObject obj = null;
- if (node.Name == "notebook") {
- DockNotebook dn = new DockNotebook ();
- dn.Bind (master);
- dn.FromXml (node);
- return dn;
- }
- if (node.Name == "paned") {
- DockPaned dp = new DockPaned ();
- dp.Bind (master);
- dp.FromXml (node);
- return dp;
- }
- string name = null;
- if (node.Attributes["name"] != null)
- name = node.Attributes["name"].Value;
- if (name != null && name.Length > 0) {
- obj = master.GetObject (name);
- }
- else {
- Console.WriteLine ("While loading layout: don't know how to create a dock object whose nick is '{0}'", name);
- }
- if (obj != null)
- obj.FromXml (node);
- return obj;
- }
- void RecursiveBuild (XmlNode parentNode, DockObject parent)
- {
- if (master == null || parentNode == null)
- return;
- DockObject obj;
- // FIXME: if parent is null, we should build toplevels
- //if (parent == null)
- foreach (XmlNode node in parentNode.ChildNodes)
- {
- obj = SetupObject (node);
- if (obj != null) {
- obj.Freeze ();
- // recurse here to catch placeholders
- RecursiveBuild (node, obj);
- // placeholders are later attached to the parent
- if (obj is DockPlaceholder)
- obj.Detach (false);
- // apply "after" parameters
- obj.FromXmlAfter (node);
- // add the object to the parent
- if (parent != null) {
- if (obj is DockPlaceholder) {
- ((DockPlaceholder) obj).Attach (parent);
- }
- else if (parent.IsCompound) {
- parent.Add (obj);
- if (parent.Visible)
- obj.Show ();
- }
- }
- else {
- if (master.Controller != obj && master.Controller.Visible)
- obj.Show ();
- }
- // call reduce just in case child is missing
- if (obj.IsCompound)
- obj.Reduce ();
- obj.Thaw ();
- }
- }
- }
- void ForeachDetach (DockObject obj)
- {
- obj.Detach (true);
- }
- void ForeachToplevelDetach (DockObject obj)
- {
- DockObject child;
- foreach (Widget w in obj.Children) {
- child = w as DockObject;
- if (w != null)
- ForeachDetach (child);
- }
- }
- void Load (XmlNode node)
- {
- if (node == null)
- return;
- // start by detaching all items from the toplevels
- foreach (DockObject o in master.TopLevelDocks)
- ForeachToplevelDetach (o);
- RecursiveBuild (node, null);
- }
- void ForeachObjectSave (DockObject obj, XmlNode parent)
- {
- if (obj == null)
- return;
- XmlElement element = obj.ToXml (doc);
- parent.AppendChild (element);
- // FIXME: save placeholders for the object
- if (!(obj is DockPlaceholder)) {
- //ArrayList list = placeholders[obj] as ArrayList;
- //foreach (DockObject child in list)
- // ForeachObjectSave (child, element);
- }
- // recurse the object if appropriate
- if (obj.IsCompound) {
- DockObject child;
- foreach (Widget w in obj.Children)
- {
- child = w as DockObject;
- if (child != null)
- ForeachObjectSave (child, element);
- }
- }
- }
- void AddPlaceholder (DockObject obj)
- {
- if (obj is DockPlaceholder) {
- // FIXME: add the current placeholder to the list of placeholders for that host
- }
- }
- void Save (XmlNode node)
- {
- if (master == null || node == null)
- return;
- // build the placeholder's hash: the hash keeps lists of
- // placeholders associated to each object, so that we can save the
- // placeholders when we are saving the object (since placeholders
- // don't show up in the normal widget hierarchy)
- placeholders = new Hashtable ();
- foreach (DockObject obj in master.DockObjects)
- AddPlaceholder (obj);
- // save the layout recursively
- foreach (DockObject o in master.TopLevelDocks)
- ForeachObjectSave (o, node);
- }
- bool IdleSave ()
- {
- SaveLayout (null);
- idleSavePending = false;
- return false;
- }
- void OnLayoutChanged (object sender, EventArgs a)
- {
- if (loading) return;
- UpdateItemsModel ();
- if (!idleSavePending) {
- GLib.Idle.Add (new GLib.IdleHandler (IdleSave));
- idleSavePending = true;
- }
- }
- protected void LoadLayoutCb (object sender, EventArgs a)
- {
- TreeModel model;
- TreeIter iter;
- if (((TreeView) sender).Selection.GetSelected (out model, out iter))
- LoadLayout ((string) model.GetValue (iter, NAME_COL));
- }
- protected void DeleteLayoutCb (object sender, EventArgs a)
- {
- TreeModel model;
- TreeIter iter;
- if (((TreeView) sender).Selection.GetSelected (out model, out iter)) {
- DeleteLayout ((string) model.GetValue (iter, NAME_COL));
- ((ListStore)model).Remove (ref iter);
- }
- }
- void ShowToggledCb (object sender, ToggledArgs a)
- {
- TreeIter iter;
- if (itemsModel.GetIterFromString (out iter, a.Path)) {
- bool show = (bool) itemsModel.GetValue (iter, SHOW_COL);
- DockItem item = itemsModel.GetValue (iter, ITEM_COL) as DockItem;
- if (show)
- item.HideItem ();
- else
- item.ShowItem ();
- UpdateItemsModel ();
- }
- }
- void AllLockedToggledCb (object sender, EventArgs a)
- {
- bool locked = ((CheckButton) sender).Active;
- if (master != null)
- master.Locked = locked ? 1 : 0;
- }
- void MasterLockedNotifyCb (object sender, EventArgs a)
- {
- if (master.Locked == -1) {
- locked_check.Inconsistent = true;
- }
- else {
- locked_check.Inconsistent = false;
- locked_check.Active = (master.Locked == 1);
- }
- }
- void CellEditedCb (object sender, EditedArgs a)
- {
- TreeIter iter;
- layoutsModel.GetIterFromString (out iter, a.Path);
- string name = (string) layoutsModel.GetValue (iter, NAME_COL);
- XmlNode node = FindLayout (name);
- if (node == null)
- return;
- node.Attributes["name"].Value = a.NewText;
- layoutsModel.SetValue (iter, NAME_COL, a.NewText);
- layoutsModel.SetValue (iter, SHOW_COL, true);
- SaveLayout (a.NewText);
- }
- }
- }
|