[Monodevelop-patches-list] r1060 - in branches/MonoDevelop-playground: . src/Plugins src/Plugins/FileBrowser src/Plugins/Services

commit-watcher at mono-cvs.ximian.com commit-watcher at mono-cvs.ximian.com
Sun Feb 29 04:47:46 EST 2004


Author: jzwart
Date: 2004-02-29 04:47:46 -0500 (Sun, 29 Feb 2004)
New Revision: 1060

Added:
   branches/MonoDevelop-playground/src/Plugins/FileBrowser/
   branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowser.cs
   branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowserPlugin.cs
   branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowserWidgetFactory.cs
   branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileIconLoader.cs
   branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileScout.cs
   branches/MonoDevelop-playground/src/Plugins/FileBrowser/Makefile.am
   branches/MonoDevelop-playground/src/Plugins/FileBrowser/filebrowser.plugin.in
   branches/MonoDevelop-playground/src/Plugins/Services/
   branches/MonoDevelop-playground/src/Plugins/Services/AbstractService.cs
   branches/MonoDevelop-playground/src/Plugins/Services/DefaultProperties.cs
   branches/MonoDevelop-playground/src/Plugins/Services/FileUtilityService.cs
   branches/MonoDevelop-playground/src/Plugins/Services/IMessageService.cs
   branches/MonoDevelop-playground/src/Plugins/Services/IProperties.cs
   branches/MonoDevelop-playground/src/Plugins/Services/IResourceService.cs
   branches/MonoDevelop-playground/src/Plugins/Services/IService.cs
   branches/MonoDevelop-playground/src/Plugins/Services/IStringTagProvider.cs
   branches/MonoDevelop-playground/src/Plugins/Services/IXmlConvertable.cs
   branches/MonoDevelop-playground/src/Plugins/Services/Makefile.am
   branches/MonoDevelop-playground/src/Plugins/Services/PropertyEventArgs.cs
   branches/MonoDevelop-playground/src/Plugins/Services/PropertyFileLoadException.cs
   branches/MonoDevelop-playground/src/Plugins/Services/PropertyService.cs
   branches/MonoDevelop-playground/src/Plugins/Services/ResourceNotFoundException.cs
   branches/MonoDevelop-playground/src/Plugins/Services/ResourceService.cs
   branches/MonoDevelop-playground/src/Plugins/Services/ServiceManager.cs
   branches/MonoDevelop-playground/src/Plugins/Services/ServicesPlugin.cs
   branches/MonoDevelop-playground/src/Plugins/Services/StringParserService.cs
   branches/MonoDevelop-playground/src/Plugins/Services/UnknownPropertyNodeException.cs
   branches/MonoDevelop-playground/src/Plugins/Services/services.plugin.in
Modified:
   branches/MonoDevelop-playground/configure.in
   branches/MonoDevelop-playground/src/Plugins/Makefile.am
Log:
Make the FileBrowser work again. Refactored most of the services into
src/Plugins/Services. Expect a rewrite of some portions eventually.


Modified: branches/MonoDevelop-playground/configure.in
===================================================================
--- branches/MonoDevelop-playground/configure.in	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/configure.in	2004-02-29 09:47:46 UTC (rev 1060)
@@ -88,7 +88,9 @@
 src/Makefile
 src/StartUp/Makefile
 src/Plugins/Makefile
+src/Plugins/Services/Makefile
 src/Plugins/Workbench/Makefile
+src/Plugins/FileBrowser/Makefile
 monodevelop
 ])
 


Property changes on: branches/MonoDevelop-playground/src/Plugins/FileBrowser
___________________________________________________________________
Name: svn:ignore
   + Makefile
Makefile.in
filebrowser.plugin
filebrowser.dll


Added: branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowser.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowser.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowser.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,155 @@
+//
+// Author: John Luke  <jluke at cfl.rr.com>
+// License: LGPL
+//
+
+using System;
+using System.IO;
+using Gtk;
+using GtkSharp;
+
+using MonoDevelop.Services;
+
+namespace MonoDevelop.FileBrowser
+{
+	public class FileBrowser : ScrolledWindow
+	{
+		private static GLib.GType gtype;
+		private Gtk.TreeView tv;
+		private ListStore store;
+		private string currentDir;
+		private bool ignoreHidden = true;
+		private string[] files;
+		private bool init = false;
+		PropertyService PropertyService = (PropertyService) ServiceManager.Services.GetService (typeof (PropertyService));
+
+		public FileBrowser () : base (GType)
+		{
+			this.VscrollbarPolicy = PolicyType.Automatic;
+			this.HscrollbarPolicy = PolicyType.Automatic;
+
+			IProperties p = (IProperties) PropertyService.GetProperty ("SharpDevelop.UI.SelectStyleOptions", new DefaultProperties ());
+			ignoreHidden = !p.GetProperty ("ICSharpCode.SharpDevelop.Gui.FileScout.ShowHidden", false);
+
+			tv = new Gtk.TreeView ();
+			tv.RulesHint = true;
+			tv.AppendColumn ("Directories", new CellRendererText (), "text", 0);
+			store = new ListStore (typeof (string));
+			currentDir = Environment.GetEnvironmentVariable ("HOME");
+			Populate ();
+			tv.Model = store;
+
+			tv.RowActivated += new RowActivatedHandler (OnRowActivated);
+			tv.Selection.Changed += new EventHandler (OnSelectionChanged);
+
+			this.Add (tv);
+			this.ShowAll ();
+			init = true;
+		}
+
+		// jba 23 feb 04 - reneabled this property to make the file browser obey the
+		// ignoreHidden property from the visual style option panel
+		public bool IgnoreHidden
+		{
+			get { return ignoreHidden; }
+			set {
+				/* for some reasont his code crashes (NullReferenceException on the Populate() call
+				if (ignoreHidden != value) {
+					ignoreHidden = value; 
+					// redraw folder list
+					System.Console.WriteLine("before poplate call");
+					Populate ();
+				}
+				*/
+				
+				ignoreHidden = value;
+			}
+		}
+
+		public Gtk.TreeView TreeView
+		{
+			get { return tv; }
+		}
+
+		public string CurrentDir
+		{
+			get { return System.IO.Path.GetFullPath (currentDir); }
+			set { currentDir = value;
+				  Populate (); }
+		}
+
+		public string[] Files
+		{
+			get {
+				if (files == null) {
+					return new string [0];
+				}
+				return files; 
+			}
+		}
+
+		public static new GLib.GType GType
+		{
+			get
+			{
+				if (gtype == GLib.GType.Invalid)
+					gtype = RegisterGType (typeof (FileBrowser));
+
+				return gtype;
+			}
+		}
+
+		void Populate ()
+		{
+			store.Clear ();
+			// seems unnecessary
+			store.AppendValues (".");
+
+			if (currentDir != "/")
+				store.AppendValues ("..");
+
+			DirectoryInfo di = new DirectoryInfo (currentDir);
+			DirectoryInfo[] dirs = di.GetDirectories ();
+	
+			foreach (DirectoryInfo d in dirs)
+			{
+				if (ignoreHidden)
+				{
+					if (!d.Name.StartsWith ("."))
+						store.AppendValues (d.Name);
+				}
+				else
+				{
+					store.AppendValues (d.Name);
+				}
+			}
+			if (init == true)
+				tv.Selection.SelectPath (new Gtk.TreePath ("0"));
+		}
+
+		private void OnSelectionChanged (object o, EventArgs args)
+		{
+			TreeIter iter;
+			TreeModel model;
+			if (tv.Selection.GetSelected (out model, out iter))
+			{
+				string selection = (string) store.GetValue (iter, 0);
+				files = Directory.GetFiles (System.IO.Path.Combine (currentDir, selection));
+			}
+		}
+
+		private void OnRowActivated (object o, RowActivatedArgs args)
+		{
+			TreeIter iter;
+			store.GetIter (out iter, args.Path);
+			string file = (string) store.GetValue (iter, 0);
+			string newDir = System.IO.Path.Combine (currentDir, file);
+			if (Directory.Exists (newDir))
+			{
+				currentDir = newDir;
+				Populate ();
+			}
+		}
+	}
+}
+

Added: branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowserPlugin.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowserPlugin.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowserPlugin.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,65 @@
+//
+// FileScoutPlugin.cs: Registers the FileScout class with the plugin loader.
+//
+// Author:
+//   Jeroen Zwartepoorte <jeroen at xs4all.nl>
+//
+// (C) Copyright Jeroen Zwartepoorte 2004
+//
+
+using System;
+using Gtk;
+using log4net;
+using MonoDevelop.Workbench;
+
+namespace MonoDevelop.FileBrowser {
+	class FileBrowserPlugin : BasePlugin {
+		private static readonly ILog log = LogManager.GetLogger (typeof (FileBrowserPlugin));
+	
+		public override string Author {
+			get {
+				return "Jeroen Zwartepoorte";
+			}
+		}
+		
+		public override string Copyright {
+			get {
+				return "GPL";
+			}
+		}
+		
+		public override string Description {
+			get {
+				return "Treeview displaying folders & files";
+			}
+		}
+		
+		public override string Name {
+			get {
+				return "FileScout";
+			}
+		}
+		
+		public override string Url {
+			get {
+				return "http://www.xs4all.nl/~jeroen/";
+			}
+		}
+		
+		public override string Version {
+			get {
+				return "1.0";
+			}
+		}
+	
+		public override bool InitializePlugin (byte major, byte minor)
+		{
+			Workbench.Workbench.AddWidgetFactory (new FileBrowserWidgetFactory ());
+			return true;
+		}
+		
+		public override void FinalizePlugin ()
+		{
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowserWidgetFactory.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowserWidgetFactory.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileBrowserWidgetFactory.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,48 @@
+//
+// FileBrowserWidgetFactory.cs: Factory for creating the FileBrowser widget.
+//
+// Author:
+//   Jeroen Zwartepoorte <jeroen at xs4all.nl>
+//
+// (C) Copyright Jeroen Zwartepoorte 2004
+//
+
+using System;
+using log4net;
+using Gtk;
+using MonoDevelop.Workbench;
+
+namespace MonoDevelop.FileBrowser {
+class FileBrowserWidgetFactory : IWorkbenchWidgetFactory {
+	private static readonly ILog log = LogManager.GetLogger (typeof (FileBrowserWidgetFactory));
+
+	public string WidgetName {
+		get {
+			return "ContentPane";
+		}
+	}
+
+	public string WidgetTitle {
+		get {
+			return "Content pane";
+		}
+	}
+	
+	public Gdk.Pixbuf WidgetIcon {
+		get {
+			return null;
+		}
+	}
+	
+	public bool Dockable {
+		get {
+			return true;
+		}
+	}
+
+	public Widget CreateWidget (Workbench workbench)
+	{
+		return new FileBrowser ();
+	}
+}
+}

Added: branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileIconLoader.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileIconLoader.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileIconLoader.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,56 @@
+using System;
+using System.Collections;
+
+using Gtk;
+using Gnome;
+
+namespace MonoDevelop.FileBrowser
+{
+	public class FileIconLoader
+	{
+		static IconTheme iconTheme;
+		static ThumbnailFactory thumbnailFactory;
+		static Hashtable iconHash;
+
+		static FileIconLoader ()
+		{
+			iconTheme = new IconTheme ();
+			thumbnailFactory = new ThumbnailFactory (ThumbnailSize.Normal);
+			iconHash = new Hashtable ();
+		}
+
+		private FileIconLoader ()
+		{
+		}
+
+		public static Gdk.Pixbuf GetPixbufForFile (string filename, int width, int height)
+		{
+			Gnome.IconLookupResultFlags result;
+			string icon;
+			try {
+				icon = Gnome.Icon.LookupSync (iconTheme, thumbnailFactory, filename, "", Gnome.IconLookupFlags.None, out result);
+			} catch {
+				icon = "gnome-fs-regular";
+			}
+			Gdk.Pixbuf pix = GetPixbufForType (icon);
+			return pix.ScaleSimple (height, width, Gdk.InterpType.Bilinear);
+		}
+
+		public static Gdk.Pixbuf GetPixbufForType (string type)
+		{
+			Gdk.Pixbuf bf = (Gdk.Pixbuf) iconHash [type];
+			if (bf == null) {
+				string p_filename = "gnome-fs-regular";
+				IconInfo info = null;
+				try {
+					info = iconTheme.LookupIcon (type, 24, 0);
+				} catch {
+					return new Gdk.Pixbuf ("../data/resources/icons/gnome-fs-regular.png");
+				}
+				bf = new Gdk.Pixbuf (info == null ? p_filename : info.Filename);
+				iconHash [type] = bf;
+			}
+			return bf;
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileScout.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileScout.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/FileBrowser/FileScout.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,435 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+using System.Resources;
+
+using MonoDevelop.Services;
+
+namespace MonoDevelop.FileBrowser
+{
+	public class FileList : Gtk.TreeView
+	{
+		private FileSystemWatcher watcher;
+		private ItemCollection Items;
+		private Gtk.ListStore store;
+		private Gtk.Menu popmenu = null;
+		
+		public FileList()
+		{
+			Items = new ItemCollection(this);
+			ResourceManager resources = new ResourceManager("ProjectComponentResources", this.GetType().Module.Assembly);
+			FileUtilityService fileUtilityService = (FileUtilityService)ServiceManager.Services.GetService(typeof(FileUtilityService));
+			
+			store = new Gtk.ListStore (typeof (string),
+						   typeof (string),
+						   typeof (string),
+						   typeof (FileListItem),
+						   typeof (Gdk.Pixbuf));
+			Model = store;
+
+			HeadersVisible = true;
+			HeadersClickable = true;
+			Reorderable = true;
+			RulesHint = true;
+
+			Gtk.TreeViewColumn name_column = new Gtk.TreeViewColumn ();
+			name_column.Title = "File";
+			
+			Gtk.TreeViewColumn size_column = new Gtk.TreeViewColumn ();
+			size_column.Title = "Size";
+
+			Gtk.TreeViewColumn modi_column = new Gtk.TreeViewColumn ();
+			modi_column.Title = "Last modified";
+
+			Gtk.CellRendererPixbuf pix_render = new Gtk.CellRendererPixbuf ();
+			name_column.PackStart (pix_render, false);
+			name_column.AddAttribute (pix_render, "pixbuf", 4);
+			
+			Gtk.CellRendererText render1 = new Gtk.CellRendererText ();
+			name_column.PackStart (render1, false);
+			name_column.AddAttribute (render1, "text", 0);
+			
+			Gtk.CellRendererText render2 = new Gtk.CellRendererText ();
+			size_column.PackStart (render2, false);
+			size_column.AddAttribute (render2, "text", 1);
+			
+			Gtk.CellRendererText render3 = new Gtk.CellRendererText ();
+			modi_column.PackStart (render3, false);
+			modi_column.AddAttribute (render3, "text", 2);
+				
+			//listView.AppendColumn (complete_column);
+			AppendColumn(name_column);
+			AppendColumn(size_column);
+			AppendColumn(modi_column);
+
+//			menu = new MagicMenus.PopupMenu();
+//			menu.MenuCommands.Add(new MagicMenus.MenuCommand("Delete file", new EventHandler(deleteFiles)));
+//			menu.MenuCommands.Add(new MagicMenus.MenuCommand("Rename", new EventHandler(renameFile)));
+			
+			watcher = new FileSystemWatcher ();
+			
+			if(watcher != null) {
+				watcher.NotifyFilter = NotifyFilters.FileName;
+				watcher.EnableRaisingEvents = false;
+				
+				watcher.Renamed += new RenamedEventHandler(fileRenamed);
+				watcher.Deleted += new FileSystemEventHandler(fileDeleted);
+				watcher.Created += new FileSystemEventHandler(fileCreated);
+				watcher.Changed += new FileSystemEventHandler(fileChanged);
+			}
+		}
+		
+		internal void ItemAdded(FileListItem item) {
+			store.AppendValues(item.Text, item.Size, item.LastModified, item, item.Icon);
+		}
+		
+		void ItemRemoved(FileListItem item) {
+			// TODO
+		}
+		
+		internal void Clear() {
+			store.Clear();
+		}
+		
+		void fileDeleted(object sender, FileSystemEventArgs e)
+		{
+			foreach(FileListItem fileItem in Items)
+			{
+				if(fileItem.FullName.ToLower() == e.FullPath.ToLower()) {
+					Items.Remove(fileItem);
+					break;
+				}
+			}
+		}
+		
+		void fileChanged(object sender, FileSystemEventArgs e)
+		{
+			foreach(FileListItem fileItem in Items)
+			{
+				if(fileItem.FullName.ToLower() == e.FullPath.ToLower()) {
+					
+					FileInfo info = new FileInfo(e.FullPath);
+					
+					fileItem.Size = Math.Round((double)info.Length / 1024).ToString() + " KB";
+					fileItem.LastModified = info.LastWriteTime.ToString();
+					break;
+				}
+			}
+		}
+		
+		void fileCreated(object sender, FileSystemEventArgs e)
+		{
+			FileInfo info = new FileInfo(e.FullPath);
+			
+			FileListItem fileItem = Items.Add(new FileListItem(e.FullPath,
+				Math.Round((double)info.Length / 1024).ToString() + " KB",
+				info.LastWriteTime.ToString())
+			);
+			
+			Items.Add(fileItem);
+		}
+		
+		void fileRenamed(object sender, RenamedEventArgs e)
+		{
+			foreach(FileListItem fileItem in Items)
+			{
+				if(fileItem.FullName.ToLower() == e.OldFullPath.ToLower()) {
+					fileItem.FullName = e.FullPath;
+					//fileItem.Text = e.Name;
+					break;
+				}
+			}
+		}
+		
+		void renameFile(object sender, EventArgs e)
+		{
+		/*
+			if(SelectedItems.Count == 1) {
+				//SelectedItems[0].BeginEdit();
+			}
+		*/
+		}
+		
+		void deleteFiles(object sender, EventArgs e)
+		{
+			IMessageService messageService =(IMessageService)ServiceManager.Services.GetService(typeof(IMessageService));
+			
+			if (messageService.AskQuestion("Are you sure ?", "Delete files")) {
+				/*foreach(FileListItem fileItem in SelectedItems)
+				{
+					try {
+						File.Delete(fileItem.FullName);
+					} catch(Exception ex) {
+						messageService.ShowError(ex, "Couldn't delete file '" + Path.GetFileName(fileItem.FullName) + "'");
+						break;
+					}
+				}*/
+			}
+		}
+		
+		public class FileListItem
+		{
+			string fullname;
+			string text;
+			string size;
+			string lastModified;
+			Gdk.Pixbuf icon;
+			
+			public string FullName {
+				get {
+					return fullname;
+				} 
+				set {
+					fullname = System.IO.Path.GetFullPath(value);
+					text = System.IO.Path.GetFileName(fullname);
+				}
+			}
+			
+			public String Text {
+				get {
+					return text;
+				}
+			}
+			
+			public string Size {
+				get {
+					return size;
+				}
+				set {
+					size = value;
+				}
+			}
+			
+			public string LastModified {
+				get {
+					return lastModified;
+				}
+				set {
+					lastModified = value;
+				}
+			}
+
+			public Gdk.Pixbuf Icon {
+				get {
+					return icon;
+				}
+				set {
+					icon = value;
+				}
+			}
+			
+			public FileListItem(string fullname, string size, string lastModified) 
+			{
+				this.size = size;
+				this.lastModified = lastModified;
+				//FIXME: This is because //home/blah is not the same as /home/blah according to Icon.LookupSync, if we get weird behaviours, lets look at this again, see if we still need it.
+				FullName = fullname.Substring (1);
+				icon = FileIconLoader.GetPixbufForFile (FullName, 24, 24);
+			}
+
+			public FileListItem (string name)
+			{
+				FileInfo fi = new FileInfo (name);
+				this.size = Math.Round ((double) fi.Length / 1024).ToString () + " KB";
+				this.lastModified = fi.LastWriteTime.ToString ();
+				FullName = System.IO.Path.GetFullPath (name); 
+				icon = FileIconLoader.GetPixbufForFile (FullName, 24, 24);
+			}
+		}
+		
+		class ItemCollection {
+			FileList parent;
+			ArrayList list = new ArrayList();
+			
+			public ItemCollection(FileList parent) {
+				this.parent = parent;
+			}
+			
+			public FileListItem Add(FileListItem item) {
+				list.Add(item);
+				parent.ItemAdded(item);
+				return item;
+			}
+			
+			public void Remove(FileListItem item) {
+				parent.ItemRemoved(item);
+				list.Remove(item);
+			}
+			
+			public void Clear() {
+				list.Clear();
+				parent.Clear();
+			}
+			
+			public IEnumerator GetEnumerator() {
+				ArrayList copy = (ArrayList)list.Clone();
+				return copy.GetEnumerator();
+			}
+		}
+	}
+	
+	public class FileScout : Gtk.VPaned
+	{
+		ResourceService resourceService = (ResourceService)ServiceManager.Services.GetService(typeof(ResourceService));
+		public Gtk.Widget Control {
+			get {
+				return this;
+			}
+		}
+		
+		public void BringToFront() {
+			// TODO
+		}
+		
+		public string Title {
+			get {
+				return resourceService.GetString("MainWindow.Windows.FileScoutLabel");
+			}
+		}
+		
+		/*public string Icon {
+			get {
+				return MonoDevelop.Gui.Stock.OpenFolderBitmap;
+			}
+		}*/
+		
+		public void RedrawContent()
+		{
+			//OnTitleChanged(null);
+			//OnIconChanged(null);
+		}
+		
+		FileList   filelister = new FileList();
+		FileBrowser fb = new FileBrowser ();
+		Gtk.Entry pathEntry;
+		PropertyService PropertyService = (PropertyService) ServiceManager.Services.GetService (typeof (PropertyService));
+
+		public FileScout()
+		{
+			fb.TreeView.Selection.Changed += new EventHandler (OnDirChanged);
+			filelister.RowActivated += new Gtk.RowActivatedHandler(FileSelected);
+
+			Gtk.Frame treef  = new Gtk.Frame();
+			Gtk.VBox utilVBox = new Gtk.VBox (false, 0);
+			Gtk.HBox hbox = new Gtk.HBox (false, 6);
+			pathEntry = new Gtk.Entry (fb.CurrentDir);
+			pathEntry.Activated += new EventHandler (OnPathEntryActivated);
+			hbox.PackStart (pathEntry);
+			Gtk.Button homeButton = new Gtk.Button ();
+			Gdk.Pixbuf pix = FileIconLoader.GetPixbufForType ("gnome-home");
+			homeButton.Add (new Gtk.Image (pix.ScaleSimple (20, 20, Gdk.InterpType.Bilinear)));
+			homeButton.Relief = Gtk.ReliefStyle.None;
+			homeButton.Clicked += new EventHandler (OnHomeClicked);
+			hbox.PackStart (homeButton, false, false, 0);
+			utilVBox.PackStart (hbox, false, true, 0);
+			utilVBox.PackStart (fb);
+			treef.Add(utilVBox);
+			
+			Gtk.ScrolledWindow listsw = new Gtk.ScrolledWindow ();
+			listsw.Add(filelister);
+			Gtk.Frame listf  = new Gtk.Frame();
+			listf.Add(listsw);
+			
+			Pack1(treef, true, true);
+			Pack2(listf, true, true);
+
+			fb.TreeView.Selection.SelectPath (new Gtk.TreePath ("0"));
+		}
+
+		void OnHomeClicked (object sender, EventArgs args)
+		{
+			fb.CurrentDir = Environment.GetEnvironmentVariable ("HOME");
+			OnDirChanged (sender, args);
+		}
+
+		void OnPathEntryActivated (object sender, EventArgs args)
+		{
+			if (Directory.Exists (pathEntry.Text.Trim ()))
+			{
+				fb.CurrentDir = pathEntry.Text;
+				OnDirChanged (sender, args);
+			}
+		}
+		
+		void OnDirChanged(object sender, EventArgs args) 
+		{
+			pathEntry.Text = fb.CurrentDir;
+			filelister.Clear ();
+
+			PropertyService p = (PropertyService)ServiceManager.Services.GetService(typeof(PropertyService));
+			bool ignoreHidden = !p.GetProperty ("ICSharpCode.SharpDevelop.Gui.FileScout.ShowHidden", false);
+			fb.IgnoreHidden = ignoreHidden;
+
+			foreach (string f in fb.Files)
+			{
+				if (!(System.IO.Path.GetFileName (f)).StartsWith ("."))
+				{
+					FileList.FileListItem it = new FileList.FileListItem (f);
+					filelister.ItemAdded (it);
+				}
+				else
+				{
+					if (!ignoreHidden)
+					{
+						FileList.FileListItem it = new FileList.FileListItem (f);
+						filelister.ItemAdded (it);
+					
+					}
+				}
+			}
+		}
+
+		void FileSelected(object sender, Gtk.RowActivatedArgs e)
+		{
+			Console.WriteLine ("FileScout.FileSelected FIXME");
+			/*IProjectService projectService = (IProjectService)ICSharpCode.Core.Services.ServiceManager.Services.GetService(typeof(IProjectService));
+			IFileService    fileService    = (IFileService)ICSharpCode.Core.Services.ServiceManager.Services.GetService(typeof(IFileService));
+			FileUtilityService fileUtilityService = (FileUtilityService)ServiceManager.Services.GetService(typeof(FileUtilityService));
+
+			Gtk.TreeIter iter;
+			if (filelister.Model.GetIterFirst(out iter) == false) {
+				return;
+			}
+			do {
+				if (filelister.Selection.IterIsSelected(iter) == false) {
+					continue;
+				} 
+				FileList.FileListItem item = (FileList.FileListItem)filelister.Model.GetValue(iter, 3);
+				switch (System.IO.Path.GetExtension(item.FullName)) {
+					case ".cmbx":
+					case ".prjx":
+						projectService.OpenCombine(item.FullName);
+						break;
+					default:
+						Console.WriteLine (item.FullName);
+						fileService.OpenFile(item.FullName);
+						break;
+				}
+			} while (filelister.Model.IterNext(out iter) == true);*/
+		}
+/*
+		protected virtual void OnTitleChanged(EventArgs e)
+		{
+			if (TitleChanged != null) {
+				TitleChanged(this, e);
+			}
+		}
+		protected virtual void OnIconChanged(EventArgs e)
+		{
+			if (IconChanged != null) {
+				IconChanged(this, e);
+			}
+		}
+		*/
+		public event EventHandler TitleChanged;
+		public event EventHandler IconChanged;
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/FileBrowser/Makefile.am
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/FileBrowser/Makefile.am	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/FileBrowser/Makefile.am	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,35 @@
+filebrowserdir = $(libdir)/monodevelop
+filebrowserassembly = $(filebrowserdir)/filebrowser.dll
+filebrowser_DATA = filebrowser.dll
+plugindir = $(monodevelop_plugin_dir)
+plugin_DATA = filebrowser.plugin
+CLEANFILES = filebrowser.dll filebrowser.plugin
+CSC = mcs
+
+filebrowser_sources = \
+	FileBrowser.cs \
+	FileBrowserPlugin.cs \
+	FileBrowserWidgetFactory.cs \
+	FileIconLoader.cs \
+	FileScout.cs
+
+filebrowser_assemblies = \
+	-r:../../StartUp/monodevelop.exe \
+	-r:log4net.dll \
+	-r:gtk-sharp.dll \
+	-r:gdk-sharp.dll \
+	-r:glib-sharp.dll \
+	-r:gnome-sharp.dll \
+	-r:../../../build/bin/gdl-sharp.dll \
+	-r:../Services/services.dll \
+	-r:../Workbench/workbench.dll
+
+filebrowser.dll: $(filebrowser_sources)
+	$(CSC) -debug -t:library -out:filebrowser.dll $(filebrowser_sources) $(filebrowser_assemblies)
+
+filebrowser.plugin: filebrowser.plugin.in
+	sed -e 's^\@assembly\@^$(filebrowserassembly)^g' < $(srcdir)/filebrowser.plugin.in > filebrowser.plugin
+
+EXTRA_DIST = \
+	$(filebrowser_sources) \
+	filebrowser.plugin.in

Added: branches/MonoDevelop-playground/src/Plugins/FileBrowser/filebrowser.plugin.in
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/FileBrowser/filebrowser.plugin.in	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/FileBrowser/filebrowser.plugin.in	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin version="1.0">
+	<assembly>@assembly@</assembly>
+	<class name="MonoDevelop.FileBrowser.FileBrowserPlugin"/>
+</plugin>

Modified: branches/MonoDevelop-playground/src/Plugins/Makefile.am
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Makefile.am	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Makefile.am	2004-02-29 09:47:46 UTC (rev 1060)
@@ -1 +1 @@
-SUBDIRS = Workbench
+SUBDIRS = Services Workbench FileBrowser


Property changes on: branches/MonoDevelop-playground/src/Plugins/Services
___________________________________________________________________
Name: svn:ignore
   + Makefile
Makefile.in
services.dll
services.plugin


Added: branches/MonoDevelop-playground/src/Plugins/Services/AbstractService.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/AbstractService.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/AbstractService.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,42 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	public class AbstractService : IService
+	{
+		public virtual void InitializeService()
+		{
+			OnInitialize(EventArgs.Empty);
+		}
+		
+		
+		public virtual void UnloadService()
+		{
+			OnUnload(EventArgs.Empty);
+		}
+		
+		protected virtual void OnInitialize(EventArgs e)
+		{
+			if (Initialize != null) {
+				Initialize(this, e);
+			}
+		}
+		
+		protected virtual void OnUnload(EventArgs e)
+		{
+			if (Unload != null) {
+				Unload(this, e);
+			}
+		}
+		
+		public event EventHandler Initialize;
+		public event EventHandler Unload;
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/DefaultProperties.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/DefaultProperties.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/DefaultProperties.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,286 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Diagnostics;
+using System.Xml;
+using System.Reflection;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// Default <code>IProperties</code> implementation, should
+	/// be enough for most cases :)
+	/// </summary>
+	public class DefaultProperties : IProperties
+	{
+		Hashtable properties = new Hashtable();
+		
+		/// <summary>
+		/// Gets a property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		public object GetProperty(string key, object defaultvalue)
+		{
+			if (!properties.ContainsKey(key)) {
+				if (defaultvalue != null) {
+					properties[key] = defaultvalue;
+				}
+				return defaultvalue;
+			}
+			
+			object obj = properties[key];
+			
+			// stored an XmlElement in properties node ->
+			// set a FromXmlElement of the defaultvalue type at this propertyposition.
+			if (defaultvalue is IXmlConvertable && obj is XmlElement) {
+				obj = properties[key] = ((IXmlConvertable)defaultvalue).FromXmlElement((XmlElement)((XmlElement)obj).FirstChild);
+			}
+			return obj;
+		}
+		
+		/// <summary>
+		/// Gets a property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>null</code>, if the property wasn't found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		public object GetProperty(string key)
+		{
+			return GetProperty(key, (object)null);
+		}
+		
+		/// <summary>
+		/// Gets a <code>int</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		public int GetProperty(string key, int defaultvalue)
+		{
+			return int.Parse(GetProperty(key, (object)defaultvalue).ToString());
+		}
+		
+		/// <summary>
+		/// Gets a <code>bool</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		public bool GetProperty(string key, bool defaultvalue)
+		{
+			return bool.Parse(GetProperty(key, (object)defaultvalue).ToString());
+		}
+
+		/// <summary>
+		/// Gets a <code>short</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		public short GetProperty(string key, short defaultvalue)
+		{
+			return short.Parse(GetProperty(key, (object)defaultvalue).ToString());
+		}
+
+		/// <summary>
+		/// Gets a <code>byte</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		public byte GetProperty(string key, byte defaultvalue)
+		{
+			return byte.Parse(GetProperty(key, (object)defaultvalue).ToString());
+		}
+		
+		/// <summary>
+		/// Gets a <code>string</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		public string GetProperty(string key, string defaultvalue)
+		{
+			return GetProperty(key, (object)defaultvalue).ToString();
+		}
+		
+		/// <summary>
+		/// Gets a <code>enum</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		public System.Enum GetProperty(string key, System.Enum defaultvalue)
+		{
+			return (System.Enum)Enum.Parse(defaultvalue.GetType(), GetProperty(key, (object)defaultvalue).ToString());
+		}
+		
+		/// <summary>
+		/// Sets the property <code>key</code> to the value <code>val</code>.
+		/// If <code>val</code> is null, the property will be taken out from the
+		/// properties.
+		/// </summary>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="val">
+		/// The value of the property.
+		/// </param>
+		public void SetProperty(string key, object val)
+		{
+			object oldValue = properties[key];
+			if (!val.Equals(oldValue)) {
+				properties[key] = val;
+				OnPropertyChanged(new PropertyEventArgs(this, key, oldValue, val));
+			}
+		}
+		
+		public DefaultProperties()
+		{
+		}
+		
+		protected void SetValueFromXmlElement(XmlElement element)
+		{
+			XmlNodeList nodes = element.ChildNodes;
+			foreach (XmlElement el in nodes) {
+				if (el.Name == "Property") {
+					properties[el.Attributes["key"].InnerText] = el.Attributes["value"].InnerText;
+				} else if (el.Name == "XmlConvertableProperty") {
+					properties[el.Attributes["key"].InnerText] = el;
+				} else {
+					throw new UnknownPropertyNodeException(el.Name);
+				}
+			}
+		}
+		
+		/// <summary>
+		/// Converts a <code>XmlElement</code> to an <code>DefaultProperties</code>
+		/// </summary>
+		/// <returns>
+		/// A new <code>DefaultProperties</code> object 
+		/// </returns>
+		public virtual object FromXmlElement(XmlElement element)
+		{
+			DefaultProperties defaultProperties = new DefaultProperties();
+			defaultProperties.SetValueFromXmlElement(element);
+			return defaultProperties;
+		}
+		
+		/// <summary>
+		/// Converts the <code>DefaultProperties</code> object to a <code>XmlElement</code>
+		/// </summary>
+		/// <returns>
+		/// A new <code>XmlElement</code> object which represents the state
+		/// of the <code>DefaultProperties</code> object.
+		/// </returns>
+		public virtual XmlElement ToXmlElement(XmlDocument doc)
+		{
+			XmlElement propertiesnode  = doc.CreateElement("Properties");
+			
+			foreach (DictionaryEntry entry in properties) {
+				if (entry.Value != null) {
+					if (entry.Value is XmlElement) { // write unchanged XmlElement back
+						propertiesnode.AppendChild(doc.ImportNode((XmlElement)entry.Value, true));
+					} else if (entry.Value is IXmlConvertable) { // An Xml convertable object
+						XmlElement convertableNode = doc.CreateElement("XmlConvertableProperty");
+						
+						XmlAttribute key = doc.CreateAttribute("key");
+						key.InnerText = entry.Key.ToString();
+						convertableNode.Attributes.Append(key);
+						
+						convertableNode.AppendChild(((IXmlConvertable)entry.Value).ToXmlElement(doc));
+						
+						propertiesnode.AppendChild(convertableNode);
+					} else {
+						XmlElement el = doc.CreateElement("Property");
+						
+						XmlAttribute key   = doc.CreateAttribute("key");
+						key.InnerText      = entry.Key.ToString();
+						el.Attributes.Append(key);
+	
+						XmlAttribute val   = doc.CreateAttribute("value");
+						val.InnerText      = entry.Value.ToString();
+						el.Attributes.Append(val);
+						
+						propertiesnode.AppendChild(el);
+					}
+				}
+			}
+			return propertiesnode;
+		}
+		
+		/// <summary>
+		/// Returns a new instance of <code>IProperties</code> which has
+		/// the same properties.
+		/// </summary>
+		public IProperties Clone()
+		{
+			DefaultProperties df = new DefaultProperties();
+			df.properties = (Hashtable)properties.Clone();
+			return df;
+		}
+		
+		protected virtual void OnPropertyChanged(PropertyEventArgs e)
+		{
+			if (PropertyChanged != null) {
+				PropertyChanged(this, e);
+			}
+		}
+		
+		public event PropertyEventHandler PropertyChanged;
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/FileUtilityService.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/FileUtilityService.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/FileUtilityService.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,442 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+#define LINUX
+
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Reflection;
+using System.Resources;
+using System.Diagnostics;
+using System.Xml;
+
+namespace MonoDevelop.Services
+{
+	public enum FileErrorPolicy {
+		Inform,
+		ProvideAlternative
+	}
+	
+	public enum FileOperationResult {
+		OK,
+		Failed,
+		SavedAlternatively
+	}
+	
+	public delegate void FileOperationDelegate();
+	
+	public delegate void NamedFileOperationDelegate(string fileName);
+	
+	/// <summary>
+	/// A utility class related to file utilities.
+	/// </summary>
+	public class FileUtilityService : AbstractService
+	{
+		readonly static char[] separators = { Path.DirectorySeparatorChar, Path.VolumeSeparatorChar, Path.AltDirectorySeparatorChar };
+		readonly static char[] dir_sep = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
+		string sharpDevelopRootPath;
+		
+		public string SharpDevelopRootPath {
+			get {
+				return sharpDevelopRootPath;
+			}
+		}
+		
+		public FileUtilityService()
+		{
+			sharpDevelopRootPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar + "..";
+		}
+		
+		public override void InitializeService()
+		{
+			base.InitializeService();
+		}
+		
+		public override void UnloadService()
+		{
+			base.UnloadService();
+		}
+
+		public StringCollection SearchDirectory(string directory, string filemask, bool searchSubdirectories)
+		{
+			StringCollection collection = new StringCollection();
+			SearchDirectory(directory, filemask, collection, searchSubdirectories);
+			return collection;
+		}
+		
+		public StringCollection SearchDirectory(string directory, string filemask)
+		{
+			return SearchDirectory(directory, filemask, true);
+		}
+		
+		/// <summary>
+		/// Finds all files which are valid to the mask <code>filemask</code> in the path
+		/// <code>directory</code> and all subdirectories (if searchSubdirectories
+		/// is true. The found files are added to the StringCollection 
+		/// <code>collection</code>.
+		/// </summary>
+		void SearchDirectory(string directory, string filemask, StringCollection collection, bool searchSubdirectories)
+		{
+			try {
+				string[] file = Directory.GetFiles(directory, filemask);
+				foreach (string f in file) {
+					collection.Add(f);
+				}
+				
+				if (searchSubdirectories) {
+					string[] dir = Directory.GetDirectories(directory);
+					foreach (string d in dir) {
+						SearchDirectory(d, filemask, collection, searchSubdirectories);
+					}
+				}
+			} catch (Exception e) {
+				IMessageService messageService =(IMessageService)ServiceManager.Services.GetService(typeof(IMessageService));
+				messageService.ShowError(e, "Can't access directory " + directory);
+			}
+		}
+		
+		/// <summary>
+		/// Converts a given absolute path and a given base path to a path that leads
+		/// from the base path to the absoulte path. (as a relative path)
+		/// </summary>
+		public string AbsoluteToRelativePath(string baseDirectoryPath, string absPath)
+		{
+			if (! Path.IsPathRooted (absPath))
+				return absPath;
+			
+			absPath = Path.GetFullPath (absPath);
+			baseDirectoryPath = Path.GetFullPath (baseDirectoryPath);
+			
+			string[] bPath = baseDirectoryPath.Split (separators);
+			string[] aPath = absPath.Split (separators);
+			int indx = 0;
+			for(; indx < Math.Min(bPath.Length, aPath.Length); ++indx){
+				if(!bPath[indx].Equals(aPath[indx]))
+					break;
+			}
+			
+			if (indx == 0) {
+				return absPath;
+			}
+			
+			string erg = "";
+			
+			if(indx == bPath.Length) {
+				erg += "." + Path.DirectorySeparatorChar;
+			} else {
+				for (int i = indx; i < bPath.Length; ++i) {
+					erg += ".." + Path.DirectorySeparatorChar;
+				}
+			}
+			erg += String.Join(Path.DirectorySeparatorChar.ToString(), aPath, indx, aPath.Length-indx);
+			
+			return erg;
+		}
+		
+		/// <summary>
+		/// Converts a given relative path and a given base path to a path that leads
+		/// to the relative path absoulte.
+		/// </summary>
+		public string RelativeToAbsolutePath(string baseDirectoryPath, string relPath)
+		{			
+			return Path.GetFullPath (baseDirectoryPath + Path.DirectorySeparatorChar + relPath);
+		}
+		
+		/// <summary>
+		/// This method checks the file fileName if it is valid.
+		/// </summary>
+		public bool IsValidFileName(string fileName)
+		{
+			// Fixme: 260 is the hardcoded maximal length for a path on my Windows XP system
+			//        I can't find a .NET property or method for determining this variable.
+			if (fileName == null || fileName.Length == 0 || fileName.Length >= 260) {
+				return false;
+			}
+			
+			// platform independend : check for invalid path chars
+			foreach (char invalidChar in Path.InvalidPathChars) {
+				if (fileName.IndexOf(invalidChar) >= 0) {
+					return false;
+				}
+			}
+			
+			// platform dependend : Check for invalid file names (DOS)
+			// this routine checks for follwing bad file names :
+			// CON, PRN, AUX, NUL, COM1-9 and LPT1-9
+			
+			string nameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
+			if (nameWithoutExtension != null) {
+				nameWithoutExtension = nameWithoutExtension.ToUpper();
+			}
+			
+			if (nameWithoutExtension == "CON" ||
+			    nameWithoutExtension == "PRN" ||
+			    nameWithoutExtension == "AUX" ||
+			    nameWithoutExtension == "NUL") {
+		    	
+		    	return false;
+		    }
+			    
+		    char ch = nameWithoutExtension.Length == 4 ? nameWithoutExtension[3] : '\0';
+			
+			return !((nameWithoutExtension.StartsWith("COM") ||
+			          nameWithoutExtension.StartsWith("LPT")) &&
+			          Char.IsDigit(ch));
+		}
+		
+		public bool TestFileExists(string filename)
+		{
+			if (!File.Exists(filename)) {
+				IResourceService resourceService = (IResourceService)ServiceManager.Services.GetService(typeof(IResourceService));
+				StringParserService stringParserService = (StringParserService)ServiceManager.Services.GetService(typeof(StringParserService));
+				
+				IMessageService messageService =(IMessageService)ServiceManager.Services.GetService(typeof(IMessageService));
+				messageService.ShowWarning(stringParserService.Parse(resourceService.GetString("Fileutility.CantFindFileError"), new string[,] { {"FILE",  filename} }));
+				return false;
+			}
+			return true;
+		}
+		
+		public bool IsDirectory(string filename)
+		{
+			if (!Directory.Exists(filename)) {
+				return false;
+			}
+			FileAttributes attr = File.GetAttributes(filename);
+			return (attr & FileAttributes.Directory) != 0;
+		}
+		
+		/// <summary>
+		/// Returns directoryName + "\\" (Win32) when directoryname doesn't end with
+		/// "\\"
+		/// </summary>
+		public string GetDirectoryNameWithSeparator(string directoryName)
+		{
+			if (directoryName == null) return "";
+			
+			if (directoryName.EndsWith(Path.DirectorySeparatorChar.ToString())) {
+				return directoryName;
+			}
+			return directoryName + Path.DirectorySeparatorChar;
+		}
+		
+		// Observe SAVE functions
+		public FileOperationResult ObservedSave(FileOperationDelegate saveFile, string fileName, string message, FileErrorPolicy policy)
+		{
+			Debug.Assert(IsValidFileName(fileName));
+#if !LINUX			
+			try {
+				saveFile();
+				return FileOperationResult.OK;
+			} catch (Exception e) {
+				switch (policy) {
+					case FileErrorPolicy.Inform:
+						using (SaveErrorInformDialog informDialog = new SaveErrorInformDialog(fileName, message, "Error while saving", e)) {
+							informDialog.ShowDialog();
+						}
+						break;
+					case FileErrorPolicy.ProvideAlternative:
+						using (SaveErrorChooseDialog chooseDialog = new SaveErrorChooseDialog(fileName, message, "Error while saving", e, false)) {
+							switch (chooseDialog.ShowDialog()) {
+								case DialogResult.OK: // choose location (never happens here)
+								break;
+								case DialogResult.Retry:
+									return ObservedSave(saveFile, fileName, message, policy);
+								case DialogResult.Ignore:
+									return FileOperationResult.Failed;
+							}
+						}
+						break;
+				}
+			}
+#else
+			try {
+				saveFile();
+				return FileOperationResult.OK;
+			} catch (Exception e) {
+				Console.WriteLine("Error while saving : " + e.ToString());
+			}
+	
+#endif
+			return FileOperationResult.Failed;
+		}
+		
+		public FileOperationResult ObservedSave(FileOperationDelegate saveFile, string fileName, FileErrorPolicy policy)
+		{
+			IResourceService resourceService = (IResourceService)ServiceManager.Services.GetService(typeof(IResourceService));
+			return ObservedSave(saveFile,
+			                    fileName,
+			                    resourceService.GetString("ICSharpCode.Services.FileUtilityService.CantSaveFileStandardText"),
+			                    policy);
+		}
+		
+		public FileOperationResult ObservedSave(FileOperationDelegate saveFile, string fileName)
+		{
+			return ObservedSave(saveFile, fileName, FileErrorPolicy.Inform);
+		}
+		
+		public FileOperationResult ObservedSave(NamedFileOperationDelegate saveFileAs, string fileName, string message, FileErrorPolicy policy)
+		{
+			Debug.Assert(IsValidFileName(fileName));
+#if !LINUX
+			try {
+				fileName = System.IO.Path.GetFullPath (fileName);
+				saveFileAs(fileName);
+				return FileOperationResult.OK;
+			} catch (Exception e) {
+				switch (policy) {
+					case FileErrorPolicy.Inform:
+						using (SaveErrorInformDialog informDialog = new SaveErrorInformDialog(fileName, message, "Error while saving", e)) {
+							informDialog.ShowDialog();
+						}
+						break;
+					case FileErrorPolicy.ProvideAlternative:
+						restartlabel:
+							using (SaveErrorChooseDialog chooseDialog = new SaveErrorChooseDialog(fileName, message, "Error while saving", e, true)) {
+								switch (chooseDialog.ShowDialog()) {
+									case DialogResult.OK:
+										using (SaveFileDialog fdiag = new SaveFileDialog()) {
+											fdiag.OverwritePrompt = true;
+											fdiag.AddExtension    = true;
+											fdiag.CheckFileExists = false;
+											fdiag.CheckPathExists = true;
+											fdiag.Title           = "Choose alternate file name";
+											fdiag.FileName        = fileName;
+											if (fdiag.ShowDialog() == DialogResult.OK) {
+												return ObservedSave(saveFileAs, fdiag.FileName, message, policy);
+											} else {
+												goto restartlabel;
+											}
+										}
+										case DialogResult.Retry:
+											return ObservedSave(saveFileAs, fileName, message, policy);
+									case DialogResult.Ignore:
+										return FileOperationResult.Failed;
+								}
+							}
+							break;
+				}
+			}
+#else
+			try {
+				saveFileAs(fileName);
+				return FileOperationResult.OK;
+			} catch (Exception e) {
+				Console.WriteLine("Error while saving as : " + e.ToString());
+			}
+#endif
+			return FileOperationResult.Failed;
+		}
+		
+		public FileOperationResult ObservedSave(NamedFileOperationDelegate saveFileAs, string fileName, FileErrorPolicy policy)
+		{
+			IResourceService resourceService = (IResourceService)ServiceManager.Services.GetService(typeof(IResourceService));
+			return ObservedSave(saveFileAs,
+			                    fileName,
+			                    resourceService.GetString("ICSharpCode.Services.FileUtilityService.CantSaveFileStandardText"),
+			                    policy);
+		}
+		
+		public FileOperationResult ObservedSave(NamedFileOperationDelegate saveFileAs, string fileName)
+		{
+			return ObservedSave(saveFileAs, fileName, FileErrorPolicy.Inform);
+		}
+		
+		// Observe LOAD functions
+		public FileOperationResult ObservedLoad(FileOperationDelegate saveFile, string fileName, string message, FileErrorPolicy policy)
+		{
+			Debug.Assert(IsValidFileName(fileName));
+#if !LINUX
+			try {
+				saveFile();
+				return FileOperationResult.OK;
+			} catch (Exception e) {
+				switch (policy) {
+					case FileErrorPolicy.Inform:
+						using (SaveErrorInformDialog informDialog = new SaveErrorInformDialog(fileName, message, "Error while loading", e)) {
+							informDialog.ShowDialog();
+						}
+						break;
+					case FileErrorPolicy.ProvideAlternative:
+						using (SaveErrorChooseDialog chooseDialog = new SaveErrorChooseDialog(fileName, message, "Error while loading", e, false)) {
+							switch (chooseDialog.ShowDialog()) {
+								case DialogResult.OK: // choose location (never happens here)
+								break;
+								case DialogResult.Retry:
+									return ObservedLoad(saveFile, fileName, message, policy);
+								case DialogResult.Ignore:
+									return FileOperationResult.Failed;
+							}
+						}
+						break;
+				}
+			}
+#else
+			try {
+				saveFile();
+				return FileOperationResult.OK;
+			} catch (Exception e) {
+				Console.WriteLine("Error while loading " + e.ToString());
+			}
+#endif
+			return FileOperationResult.Failed;
+		}
+		
+		public FileOperationResult ObservedLoad(FileOperationDelegate saveFile, string fileName, FileErrorPolicy policy)
+		{
+			IResourceService resourceService = (IResourceService)ServiceManager.Services.GetService(typeof(IResourceService));
+			return ObservedLoad(saveFile,
+			                    fileName,
+			                    resourceService.GetString("ICSharpCode.Services.FileUtilityService.CantLoadFileStandardText"),
+			                    policy);
+		}
+		
+		public FileOperationResult ObservedLoad(FileOperationDelegate saveFile, string fileName)
+		{
+			return ObservedSave(saveFile, fileName, FileErrorPolicy.Inform);
+		}
+		
+		class LoadWrapper
+		{
+			NamedFileOperationDelegate saveFileAs;
+			string fileName;
+			
+			public LoadWrapper(NamedFileOperationDelegate saveFileAs, string fileName)
+			{
+				this.saveFileAs = saveFileAs;
+				this.fileName   = fileName;
+			}
+			
+			public void Invoke()
+			{
+				saveFileAs(fileName);
+			}
+		}
+		
+		public FileOperationResult ObservedLoad(NamedFileOperationDelegate saveFileAs, string fileName, string message, FileErrorPolicy policy)
+		{
+			return ObservedLoad(new FileOperationDelegate(new LoadWrapper(saveFileAs, fileName).Invoke), fileName, message, policy);
+		}
+		
+		public FileOperationResult ObservedLoad(NamedFileOperationDelegate saveFileAs, string fileName, FileErrorPolicy policy)
+		{
+			IResourceService resourceService = (IResourceService)ServiceManager.Services.GetService(typeof(IResourceService));
+			return ObservedLoad(saveFileAs,
+			                    fileName,
+			                    resourceService.GetString("ICSharpCode.Services.FileUtilityService.CantLoadFileStandardText"),
+			                    policy);
+		}
+		
+		public FileOperationResult ObservedLoad(NamedFileOperationDelegate saveFileAs, string fileName)
+		{
+			return ObservedLoad(saveFileAs, fileName, FileErrorPolicy.Inform);
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/IMessageService.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/IMessageService.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/IMessageService.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,42 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// This interface must be implemented by all services.
+	/// </summary>
+	public interface IMessageService
+	{
+		void ShowError(Exception ex);
+		void ShowError(string message);
+		void ShowError(Exception ex, string message);
+		void ShowErrorFormatted(string formatstring, params string[] formatitems);
+		
+		void ShowWarning(string message);
+		void ShowWarningFormatted(string formatstring, params string[] formatitems);
+		
+		void ShowMessage(string message);
+		void ShowMessage(string message, string caption);
+		void ShowMessageFormatted(string formatstring, params string[] formatitems);
+		void ShowMessageFormatted(string caption, string formatstring, params string[] formatitems);
+		
+		/// <summary>
+		/// returns the number of the chosen button
+		/// </summary>
+		int  ShowCustomDialog(string caption, 
+		                      string dialogText,
+		                      params string[] buttontexts);
+		
+		bool AskQuestion(string question);
+		bool AskQuestionFormatted(string formatstring, params string[] formatitems);
+		bool AskQuestion(string question, string caption);
+		bool AskQuestionFormatted(string caption, string formatstring, params string[] formatitems);
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/IProperties.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/IProperties.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/IProperties.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,165 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Diagnostics;
+using System.Xml;
+using System.Reflection;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// The <code>IProperties</code> interface defines a set of properties
+	/// </summary>
+	public interface IProperties : IXmlConvertable
+	{
+		/// <summary>
+		/// Gets a property out of the collection. The defaultvalue must either 
+		/// have a cast to a string (and back) or implement the 
+		/// <code>IXmlConcertable</code> interface.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't
+		/// found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		object GetProperty(string key, object defaultvalue);
+		
+		/// <summary>
+		/// Gets a property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>null</code>, if the property wasn't 
+		/// found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		object GetProperty(string key);
+		
+		/// <summary>
+		/// Gets a <code>int</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't
+		/// found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		int GetProperty(string key, int defaultvalue);
+		
+		/// <summary>
+		/// Gets a <code>bool</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't
+		/// found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		bool GetProperty(string key, bool defaultvalue);
+
+		/// <summary>
+		/// Gets a <code>short</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't
+		/// found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		short GetProperty(string key, short defaultvalue);
+
+		/// <summary>
+		/// Gets a <code>byte</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't
+		/// found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		byte GetProperty(string key, byte defaultvalue);
+
+		/// <summary>
+		/// Gets a <code>string</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't
+		/// found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		string GetProperty(string key, string defaultvalue);
+		
+		/// <summary>
+		/// Gets a <code>enum</code> property out of the collection.
+		/// </summary>
+		/// <returns>
+		/// The property, or <code>defaultvalue</code>, if the property wasn't found.
+		/// </returns>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="defaultvalue">
+		/// The default value of the property.
+		/// </param>
+		System.Enum GetProperty(string key, System.Enum defaultvalue);
+		
+		/// <summary>
+		/// Sets the property <code>key</code> to the value <code>val</code>.
+		/// If <code>val</code> is null, the property will be taken out from the
+		/// properties.
+		/// </summary>
+		/// <param name="key">
+		/// The name of the property.
+		/// </param>
+		/// <param name="val">
+		/// The value of the property.
+		/// </param>
+		void SetProperty(string key, object val);
+		
+		/// <summary>
+		/// Returns a new instance of <code>IProperties</code> which has 
+		/// the same properties.
+		/// </summary>
+		IProperties Clone();
+		
+		/// <summary>
+		/// The property changed event handler, it is called
+		/// when a property has changed.
+		/// </summary>
+		event PropertyEventHandler PropertyChanged;
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/IResourceService.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/IResourceService.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/IResourceService.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,18 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// This interface must be implemented by all services.
+	/// </summary>
+	public interface IResourceService
+	{
+		string GetString(string name);
+		
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/IService.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/IService.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/IService.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,30 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// This interface must be implemented by all services.
+	/// </summary>
+	public interface IService
+	{
+		/// <summary>
+		/// This method is called after the services are loaded.
+		/// </summary>
+		void InitializeService();
+		
+		/// <summary>
+		/// This method is called before the service is unloaded.
+		/// </summary>
+		void UnloadService();
+		
+		event EventHandler Initialize;
+		event EventHandler Unload;
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/IStringTagProvider.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/IStringTagProvider.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/IStringTagProvider.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,18 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+namespace MonoDevelop.Services
+{
+	public interface IStringTagProvider 
+	{
+		string[] Tags {
+			get;
+		}
+		
+		string Convert(string tag);
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/IXmlConvertable.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/IXmlConvertable.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/IXmlConvertable.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,37 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System.Xml;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// If you want define own, complex options you can implement this interface
+	/// and save it in the main Option class, your class will be saved as xml in
+	/// the global properties.
+	/// Use your class like any other property. (the conversion will be transparent)
+	/// </summary>
+	public interface IXmlConvertable
+	{
+		/// <summary>
+		/// Converts a <code>XmlElement</code> to an <code>IXmlConvertable</code>
+		/// </summary>
+		/// <returns>
+		/// A new <code>IXmlConvertable</code> object 
+		/// </returns>
+		object FromXmlElement(XmlElement element);
+		
+		/// <summary>
+		/// Converts the <code>IXmlConvertable</code> object to a <code>XmlElement</code>
+		/// </summary>
+		/// <returns>
+		/// A new <code>XmlElement</code> object which represents the state
+		/// of the <code>IXmlConvertable</code> object.
+		/// </returns>
+		XmlElement ToXmlElement(XmlDocument doc);
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/Makefile.am
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/Makefile.am	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/Makefile.am	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,44 @@
+servicesdir = $(libdir)/monodevelop
+servicesassembly = $(servicesdir)/services.dll
+services_DATA = services.dll
+plugindir = $(monodevelop_plugin_dir)
+plugin_DATA = services.plugin
+CLEANFILES = services.dll services.plugin
+CSC = mcs
+
+services_sources = \
+	AbstractService.cs \
+	DefaultProperties.cs \
+	FileUtilityService.cs \
+	IMessageService.cs \
+	IProperties.cs \
+	IResourceService.cs \
+	IService.cs \
+	IStringTagProvider.cs \
+	IXmlConvertable.cs \
+	PropertyEventArgs.cs \
+	PropertyFileLoadException.cs \
+	PropertyService.cs \
+	ResourceNotFoundException.cs \
+	ResourceService.cs \
+	ServiceManager.cs \
+	ServicesPlugin.cs \
+	StringParserService.cs \
+	UnknownPropertyNodeException.cs
+
+services_assemblies = \
+	-r:../../StartUp/monodevelop.exe \
+	-r:log4net.dll \
+	-r:gtk-sharp.dll \
+	-r:gdk-sharp.dll \
+	-r:glib-sharp.dll
+
+services.dll: $(services_sources)
+	$(CSC) -debug -t:library -out:services.dll $(services_sources) $(services_assemblies)
+
+services.plugin: services.plugin.in
+	sed -e 's^\@assembly\@^$(servicesassembly)^g' < $(srcdir)/services.plugin.in > services.plugin
+
+EXTRA_DIST = \
+	$(services_sources) \
+	services.plugin.in

Added: branches/MonoDevelop-playground/src/Plugins/Services/PropertyEventArgs.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/PropertyEventArgs.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/PropertyEventArgs.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,65 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	public delegate void PropertyEventHandler(object sender, PropertyEventArgs e);
+	
+	public class PropertyEventArgs : EventArgs
+	{
+		IProperties properties;
+		string      key;
+		object      newValue;
+		object      oldValue;
+		
+		/// <returns>
+		/// returns the changed property object
+		/// </returns>
+		public IProperties Properties {
+			get {
+				return properties;
+			}
+		}
+		
+		/// <returns>
+		/// The key of the changed property
+		/// </returns>
+		public string Key {
+			get {
+				return key;
+			}
+		}
+		
+		/// <returns>
+		/// The new value of the property
+		/// </returns>
+		public object NewValue {
+			get {
+				return newValue;
+			}
+		}
+		
+		/// <returns>
+		/// The new value of the property
+		/// </returns>
+		public object OldValue {
+			get {
+				return oldValue;
+			}
+		}
+		
+		public PropertyEventArgs(IProperties properties, string key, object oldValue, object newValue)
+		{
+			this.properties = properties;
+			this.key        = key;
+			this.oldValue   = oldValue;
+			this.newValue   = newValue;
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/PropertyFileLoadException.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/PropertyFileLoadException.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/PropertyFileLoadException.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,21 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// Is thrown when no property file could be loaded.
+	/// </summary>
+	public class PropertyFileLoadException : Exception
+	{
+		public PropertyFileLoadException() : base("couldn't load global property file")
+		{
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/PropertyService.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/PropertyService.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/PropertyService.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,164 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Text;
+using System.Xml;
+using System.Reflection;
+
+namespace MonoDevelop.Services
+{ 
+	/// <summary>
+	/// This class handles the Global Properties for the IDE, all what can be configured should be
+	/// loaded/saved by this class. It is a bit like a Singleton with static delegation instead
+	/// of returning a static reference to a <code>IProperties</code> object.
+	/// </summary>
+	public class PropertyService : DefaultProperties, IService
+	{
+		
+		readonly static string propertyFileName    = "MonoDevelopProperties.xml";
+		readonly static string propertyFileVersion = "1.1";
+		
+		readonly static string propertyXmlRootNodeName  = "SharpDevelopProperties";
+		
+		static string dataDirectory;
+		
+		static PropertyService()
+		{
+			string confDataDirectory = System.Configuration.ConfigurationSettings.AppSettings["DataDirectory"];
+			
+			if (confDataDirectory != null) {
+				dataDirectory = confDataDirectory;
+			} else {
+				dataDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + 
+				                                       Path.DirectorySeparatorChar + ".." +
+				                                       Path.DirectorySeparatorChar + "data";
+			}
+
+			configDirectory = Environment.GetEnvironmentVariable ("XDG_CONFIG_HOME");
+			if (configDirectory == null || configDirectory == "")
+				configDirectory = System.IO.Path.Combine (Environment.GetEnvironmentVariable ("HOME"), ".config");
+
+			configDirectory = System.IO.Path.Combine (configDirectory, "MonoDevelop");
+			configDirectory += System.IO.Path.DirectorySeparatorChar;
+		}
+
+		static string configDirectory;
+		/// <summary>
+		/// returns the path of the default application configuration directory
+		/// </summary>
+		public string ConfigDirectory {
+			get {
+				return configDirectory;
+			}
+		}
+		
+		public string DataDirectory {
+			get {
+				return dataDirectory;
+			}
+		}
+		
+		public PropertyService()
+		{
+			try {
+				LoadProperties();
+			} catch (PropertyFileLoadException) {
+				//System.Windows.Forms.MessageBox.Show("Can't load property file", "Warning"); // don't use message service --> cyclic dependency
+			}
+		}
+		
+		void WritePropertiesToFile(string fileName)
+		{
+			XmlDocument doc = new XmlDocument();
+			doc.LoadXml("<?xml version=\"1.0\"?>\n<" + propertyXmlRootNodeName + " fileversion = \"" + propertyFileVersion + "\" />");
+			
+			doc.DocumentElement.AppendChild(ToXmlElement(doc));
+			
+			FileUtilityService fileUtilityService = (FileUtilityService)ServiceManager.Services.GetService(typeof(FileUtilityService));
+			fileUtilityService.ObservedSave(new NamedFileOperationDelegate(doc.Save), fileName, FileErrorPolicy.ProvideAlternative);
+		}
+		
+		bool LoadPropertiesFromStream(string filename)
+		{
+			try {
+				XmlDocument doc = new XmlDocument();
+				doc.Load(filename);
+				
+				if (doc.DocumentElement.Attributes["fileversion"].InnerText != propertyFileVersion) {
+					return false;
+				}
+				SetValueFromXmlElement(doc.DocumentElement["Properties"]);
+			} catch (Exception e) {
+				//Console.WriteLine("Exception while load properties from stream :\n " + e.ToString());
+				return false;
+			}
+			return true;
+		}
+		
+		/// <summary>
+		/// Loads the global properties from the current users application data folder, or
+		/// if it doesn't exists or couldn't read them it reads the default properties out
+		/// of the application folder.
+		/// </summary>
+		/// <exception cref="PropertyFileLoadException">
+		/// Is thrown when no property file could be loaded.
+		/// </exception>
+		void LoadProperties()
+		{
+			if (!Directory.Exists(configDirectory)) {
+				Directory.CreateDirectory(configDirectory);
+			}
+			
+			if (!LoadPropertiesFromStream(configDirectory + propertyFileName)) {
+				if (!LoadPropertiesFromStream(DataDirectory + Path.DirectorySeparatorChar + "options" + Path.DirectorySeparatorChar + propertyFileName)) {
+					throw new PropertyFileLoadException();
+				}
+			}
+		}
+		
+		/// <summary>
+		/// Saves the current global property state to a file in the users application data folder.
+		/// </summary>
+		public void SaveProperties()
+		{
+			WritePropertiesToFile(configDirectory + propertyFileName);
+		}
+		
+		// IService implementation:
+		public virtual void InitializeService()
+		{
+			OnInitialize(EventArgs.Empty);
+		}
+		
+		public virtual void UnloadService()
+		{
+			// save properties on exit
+			SaveProperties();
+			OnUnload(EventArgs.Empty);
+		}
+		
+		protected virtual void OnInitialize(EventArgs e)
+		{
+			if (Initialize != null) {
+				Initialize(this, e);
+			}
+		}
+		
+		protected virtual void OnUnload(EventArgs e)
+		{
+			if (Unload != null) {
+				Unload(this, e);
+			}
+		}
+		
+		public event EventHandler Initialize;
+		public event EventHandler Unload;			
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/ResourceNotFoundException.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/ResourceNotFoundException.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/ResourceNotFoundException.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,22 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// Is thrown when the GlobalResource manager can't find a requested
+	/// resource.
+	/// </summary>
+	public class ResourceNotFoundException : Exception
+	{
+		public ResourceNotFoundException(string resource) : base("Resource not found : " + resource)
+		{
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/ResourceService.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/ResourceService.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/ResourceService.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,376 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//   license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Threading;
+using System.Resources;
+using System.Diagnostics;
+using System.Reflection;
+using System.Xml;
+using System.Runtime.InteropServices;
+
+using Gdk;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// This Class contains two ResourceManagers, which handle string and image resources
+	/// for the application. It do handle localization strings on this level.
+	/// </summary>
+	public class ImageButton : Gtk.Button
+	{
+		public ImageButton (string stock, string label)
+		{
+			Gtk.HBox hbox1 = new Gtk.HBox(false,0);
+			hbox1.PackStart(new Gtk.Image(stock, Gtk.IconSize.Button), false, true, 0);
+			hbox1.PackStart(new Gtk.Label(label), true, true, 0);
+			this.Add(hbox1);
+		}
+	}
+	
+	public class ResourceService : AbstractService, IResourceService
+	{
+		readonly static string uiLanguageProperty = "CoreProperties.UILanguage";
+		
+		readonly static string stringResources  = "StringResources";
+		readonly static string imageResources   = "BitmapResources";
+		
+		static string resourceDirctory;
+		
+		static ResourceService()
+		{
+			PropertyService propertyService = (PropertyService)ServiceManager.Services.GetService(typeof(PropertyService));
+			resourceDirctory = propertyService.DataDirectory + Path.DirectorySeparatorChar + "resources";
+
+			iconFactory = new Gtk.IconFactory ();
+
+			// FIXME: remove this when all MonoDevelop is using Gtk+
+			// stock icons
+			stockMappings = new Hashtable ();
+			//MonoDevelop.Gui.Stock.Init ();
+			iconFactory.AddDefault ();
+		}
+		
+		Hashtable userStrings = null;
+		Hashtable userIcons   = null;
+		
+		ResourceManager strings = null;
+		ResourceManager icon    = null;
+		
+		Hashtable localStrings = null;
+		Hashtable localIcons   = null;
+		
+		void ChangeProperty(object sender, PropertyEventArgs e)
+		{
+			if (e.Key == uiLanguageProperty && e.OldValue != e.NewValue) {
+				LoadLanguageResources();
+			} 
+		}
+		
+		void LoadLanguageResources()
+		{
+			PropertyService propertyService = (PropertyService)ServiceManager.Services.GetService(typeof(PropertyService));
+			string language = propertyService.GetProperty(uiLanguageProperty, Thread.CurrentThread.CurrentUICulture.Name);
+			
+			localStrings = Load(stringResources, language);
+			if (localStrings == null && language.IndexOf('-') > 0) {
+				localStrings = Load(stringResources, language.Split(new char[] {'-'})[0]);
+			}
+			
+			localIcons = Load(imageResources, language);
+			if (localIcons == null && language.IndexOf('-') > 0) {
+				localIcons = Load(imageResources, language.Split(new char[] {'-'})[0]);
+			}
+		}
+		
+		public override void InitializeService()
+		{
+			base.InitializeService();
+			PropertyService propertyService = (PropertyService)ServiceManager.Services.GetService(typeof(PropertyService));
+			propertyService.PropertyChanged += new PropertyEventHandler(ChangeProperty);
+			
+			LoadLanguageResources();
+		}
+		
+		// core service : Can't use Initialize, because all other stuff needs this service before initialize is called.
+		public ResourceService()
+		{
+			strings = new ResourceManager(stringResources, Assembly.GetCallingAssembly());
+			icon    = new ResourceManager(imageResources,  Assembly.GetCallingAssembly());
+			
+			if (System.Configuration.ConfigurationSettings.AppSettings["UserStrings"] != null) {
+				userStrings = Load(resourceDirctory +  Path.DirectorySeparatorChar + System.Configuration.ConfigurationSettings.AppSettings["UserStrings"]);
+			}
+			if (System.Configuration.ConfigurationSettings.AppSettings["UserIcons"] != null) {
+				userIcons   = Load(resourceDirctory +  Path.DirectorySeparatorChar + System.Configuration.ConfigurationSettings.AppSettings["UserIcons"]);
+			}
+		}
+		
+		/// <summary>
+		/// The LoadFont routines provide a safe way to load fonts.
+		/// </summary>
+		/// <param name="fontName">The name of the font to load.</param>
+		/// <param name="size">The size of the font to load.</param>
+		/// <returns>
+		/// The font to load or the menu font, if the requested font couldn't be loaded.
+		/// </returns>
+		/*public Font LoadFont(string fontName, int size)
+		{
+			return LoadFont(fontName, size, FontStyle.Regular);
+		}*/
+		
+		/// <summary>
+		/// The LoadFont routines provide a safe way to load fonts.
+		/// </summary>
+		/// <param name="fontName">The name of the font to load.</param>
+		/// <param name="size">The size of the font to load.</param>
+		/// <param name="style">The <see cref="System.Drawing.FontStyle"/> of the font</param>
+		/// <returns>
+		/// The font to load or the menu font, if the requested font couldn't be loaded.
+		/// </returns>
+		/*public Font LoadFont(string fontName, int size, FontStyle style)
+		{
+			try {
+				return new Font(fontName, size, style);
+			} catch (Exception) {
+				//return SystemInformation.MenuFont;
+				return null;
+			}
+		}*/
+		
+		/// <summary>
+		/// The LoadFont routines provide a safe way to load fonts.
+		/// </summary>
+		/// <param name="fontName">The name of the font to load.</param>
+		/// <param name="size">The size of the font to load.</param>
+		/// <param name="unit">The <see cref="System.Drawing.GraphicsUnit"/> of the font</param>
+		/// <returns>
+		/// The font to load or the menu font, if the requested font couldn't be loaded.
+		/// </returns>
+		/*public Font LoadFont(string fontName, int size, GraphicsUnit unit)
+		{
+			return LoadFont(fontName, size, FontStyle.Regular, unit);
+		}*/
+		
+		/// <summary>
+		/// The LoadFont routines provide a safe way to load fonts.
+		/// </summary>
+		/// <param name="fontName">The name of the font to load.</param>
+		/// <param name="size">The size of the font to load.</param>
+		/// <param name="style">The <see cref="System.Drawing.FontStyle"/> of the font</param>
+		/// <param name="unit">The <see cref="System.Drawing.GraphicsUnit"/> of the font</param>
+		/// <returns>
+		/// The font to load or the menu font, if the requested font couldn't be loaded.
+		/// </returns>
+
+		//FIXME: Convert to Pango.FontDescription
+		/*public Font LoadFont(string fontName, int size, FontStyle style, GraphicsUnit unit)
+		{
+			//try {
+				return new Font(fontName, size, style);
+			//} catch (Exception) {
+				//return new Gtk.Label ("-").Style.FontDescription;
+			//}
+		}*/
+		
+		Hashtable Load(string fileName)
+		{
+			if (File.Exists(fileName)) {
+				Hashtable resources = new Hashtable();
+				ResourceReader rr = new ResourceReader(fileName);
+				foreach (DictionaryEntry entry in rr) {
+					resources.Add(entry.Key, entry.Value);
+				}
+				rr.Close();
+				return resources;
+			}
+			return null;
+		}
+		Hashtable Load(string name, string language)
+		{
+			return Load(resourceDirctory + Path.DirectorySeparatorChar + name + "." + language + ".resources");
+			
+		}
+		
+		/// <summary>
+		/// Returns a string from the resource database, it handles localization
+		/// transparent for the user.
+		/// </summary>
+		/// <returns>
+		/// The string in the (localized) resource database.
+		/// </returns>
+		/// <param name="name">
+		/// The name of the requested resource.
+		/// </param>
+		/// <exception cref="ResourceNotFoundException">
+		/// Is thrown when the GlobalResource manager can't find a requested resource.
+		/// </exception>
+		public string GetString(string name)
+		{
+			if (name.StartsWith ("${")) {
+				name = name.Substring (6);
+				name = name.Substring (0, name.Length - 1);
+			}
+			if (this.userStrings != null && this.userStrings[name] != null) {
+				return userStrings[name].ToString();
+			}
+			if (localStrings != null && localStrings[name] != null) {
+				return localStrings[name].ToString();
+			}
+			
+			string s = strings.GetString(name);
+			
+			if (s == null) {
+				throw new ResourceNotFoundException("string >" + name + "<");
+			}
+			
+			return s;
+		}
+		
+		// use P/Invoke to be able to pass some NULL parameters
+		[DllImport("libgtk-win32-2.0-0.dll")]
+		static extern IntPtr
+		gtk_icon_set_render_icon (IntPtr raw, IntPtr style, int direction,
+		                          int state, int size, IntPtr widget,
+		                          string detail);
+
+		/// <summary>
+		/// Returns a icon from the resource database, it handles localization
+		/// transparent for the user. In the resource database can be a bitmap
+		/// instead of an icon in the dabase. It is converted automatically.
+		/// </summary>
+		/// <returns>
+		/// The icon in the (localized) resource database.
+		/// </returns>
+		/// <param name="name">
+		/// The name of the requested icon.
+		/// </param>
+		/// <exception cref="ResourceNotFoundException">
+		/// Is thrown when the GlobalResource manager can't find a requested resource.
+		/// </exception>
+
+		public Gdk.Pixbuf GetIcon (string name)
+		{
+			return GetIcon (name, Gtk.IconSize.Button);
+		}
+		
+		public Gdk.Pixbuf GetIcon (string name, Gtk.IconSize size)
+		{
+			string stockid = GetStockId (name);
+			if (stockid != null) {
+				Gtk.IconSet iconset = Gtk.IconFactory.LookupDefault (stockid);
+				if (iconset != null) {
+					// use P/Invoke to be able to pass some NULL parameters
+					IntPtr raw_ret = gtk_icon_set_render_icon
+						(iconset.Handle,
+						 Gtk.Widget.DefaultStyle.Handle,
+						 (int) Gtk.TextDirection.None,
+						 (int) Gtk.StateType.Normal,
+						 (int) size,
+						 IntPtr.Zero, null);
+					return (Gdk.Pixbuf) GLib.Object.GetObject(raw_ret);
+				}
+			}
+			
+			// throw GLib.GException as the old code?
+			return null;
+		}
+		
+		/// <summary>
+		/// Returns a bitmap from the resource database, it handles localization
+		/// transparent for the user. 
+		/// </summary>
+		/// <returns>
+		/// The bitmap in the (localized) resource database.
+		/// </returns>
+		/// <param name="name">
+		/// The name of the requested bitmap.
+		/// </param>
+		/// <exception cref="ResourceNotFoundException">
+		/// Is thrown when the GlobalResource manager can't find a requested resource.
+		/// </exception>
+
+		public Gdk.Pixbuf GetBitmap (string name)
+		{
+			return GetBitmap (name, Gtk.IconSize.Button);
+		}
+
+		public Gdk.Pixbuf GetBitmap(string name, Gtk.IconSize size)
+		{
+			// Try stock icons first
+			Gdk.Pixbuf pix = GetIcon (name, size);
+			if (pix == null) {
+				// Try loading directly from disk then
+				pix = new Gdk.Pixbuf("../data/resources/icons/" + name);
+			}
+			return pix;
+		}
+
+		public Gtk.Image GetImage (string name, Gtk.IconSize size)
+		{
+			string stock = GetStockId (name);
+			if (stock != null)
+				return new Gtk.Image (stock, size);
+			return new Gtk.Image (GetBitmap (name));
+		}
+		
+		static Gtk.IconFactory iconFactory = null;
+		static Hashtable stockMappings = null;
+
+		internal static void AddToIconFactory (string stockId,
+		                                       string filename,
+						       Gtk.IconSize iconSize)
+		{
+			try {
+				Gtk.IconSet iconSet = iconFactory.Lookup (stockId);
+				if (iconSet == null) {
+					iconSet = new Gtk.IconSet ();
+					iconFactory.Add (stockId, iconSet);
+				}
+
+				Gtk.IconSource source = new Gtk.IconSource ();
+				source.Filename = Path.GetFullPath (Path.Combine ("../data/resources/icons", filename));
+				source.Size = iconSize;
+				iconSet.AddSource (source);
+
+				// FIXME: temporary hack to retrieve the correct icon
+				// from the filename
+				stockMappings.Add (filename, stockId);
+			}
+			catch (GLib.GException ex) {
+				// just discard the exception, the icon simply can't be
+				// loaded
+				Console.WriteLine ("Warning: can't load " + filename +
+				                   " icon file");
+			}
+		}
+
+		internal static void AddToIconFactory (string stockId, string filename)
+		{
+			AddToIconFactory (stockId, filename, Gtk.IconSize.Invalid);
+		}
+		
+		internal static void AddDefaultStockMapping (string stockFile, string nativeStock)
+		{
+			stockMappings.Add (stockFile, nativeStock);
+		}
+
+		public static string GetStockId (string filename)
+		{
+			string s = (string) stockMappings [filename];
+			
+			if (s != null)
+				return s;
+			
+			Console.WriteLine ("WARNING Could not find stock {0}", filename);
+			
+			return filename;
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/ServiceManager.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/ServiceManager.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/ServiceManager.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,128 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Threading;
+using System.Resources;
+using System.Diagnostics;
+using System.Reflection;
+using System.Xml;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// This class does basic service handling for you.
+	/// </summary>
+	public class ServiceManager
+	{
+		ArrayList serviceList       = new ArrayList();
+		Hashtable servicesHashtable = new Hashtable();
+		
+		static ServiceManager defaultServiceManager = new ServiceManager();
+		
+		/// <summary>
+		/// Gets the default ServiceManager
+		/// </summary>
+		public static ServiceManager Services {
+			get {
+				return defaultServiceManager;
+			}
+		}		
+		
+		/// <summary>
+		/// Don't create ServiceManager objects, only have ONE per application.
+		/// </summary>
+		private ServiceManager()
+		{
+			// add 'core' services
+			AddService(new PropertyService());
+			AddService(new StringParserService());
+			AddService(new FileUtilityService());
+		}
+		
+		/// <remarks>
+		/// This method initializes the service system to a path inside the add-in tree.
+		/// This method must be called ONCE.
+		/// </remarks>
+		public void InitializeServicesSubsystem(string servicesPath)
+		{
+			// add add-in tree services
+			//AddServices((IService[])AddInTreeSingleton.AddInTree.GetTreeNode(servicesPath).BuildChildItems(this).ToArray(typeof(IService)));
+			
+			// initialize all services
+			foreach (IService service in serviceList) {
+				DateTime now = DateTime.Now;
+				service.InitializeService();
+			}
+		}
+		
+		/// <remarks>
+		/// Calls UnloadService on all services. This method must be called ONCE.
+		/// </remarks>
+		public void UnloadAllServices()
+		{
+			foreach (IService service in serviceList) {
+				service.UnloadService();
+			}
+		}
+		
+		public void AddService(IService service)
+		{
+			serviceList.Add(service);
+		}
+		
+		public void AddServices(IService[] services)
+		{
+			foreach (IService service in services) {
+				AddService(service);
+			}
+		}
+		
+		// HACK: MONO BUGFIX
+		// this doesn't work on mono:serviceType.IsInstanceOfType(service)
+		bool IsInstanceOfType(Type type, IService service)
+		{
+			Type serviceType = service.GetType();
+
+			foreach (Type iface in serviceType.GetInterfaces()) {
+				if (iface == type) {
+					return true;
+				}
+			}
+			
+			while (serviceType != typeof(System.Object)) {
+				if (type == serviceType) {
+					return true;
+				}
+				serviceType = serviceType.BaseType;
+			}
+			return false;
+		}
+		
+		/// <remarks>
+		/// Requestes a specific service, may return null if this service is not found.
+		/// </remarks>
+		public IService GetService(Type serviceType)
+		{
+			IService s = (IService)servicesHashtable[serviceType];
+			if (s != null) {
+				return s;
+			}
+			
+			foreach (IService service in serviceList) {
+				if (IsInstanceOfType(serviceType, service)) {
+					servicesHashtable[serviceType] = service;
+					return service;
+				}
+			}
+			
+			return null;
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/ServicesPlugin.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/ServicesPlugin.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/ServicesPlugin.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,63 @@
+//
+// ServicesPlugin.cs: Registers the Services class with the plugin loader.
+//
+// Author:
+//   Jeroen Zwartepoorte <jeroen at xs4all.nl>
+//
+// (C) Copyright Jeroen Zwartepoorte 2004
+//
+
+using System;
+using Gtk;
+using log4net;
+
+namespace MonoDevelop.Services {
+	class ServicesPlugin : BasePlugin {
+		private static readonly ILog log = LogManager.GetLogger (typeof (ServicesPlugin));
+	
+		public override string Author {
+			get {
+				return "Jeroen Zwartepoorte";
+			}
+		}
+		
+		public override string Copyright {
+			get {
+				return "GPL";
+			}
+		}
+		
+		public override string Description {
+			get {
+				return "Core services used in MonoDevelop";
+			}
+		}
+		
+		public override string Name {
+			get {
+				return "Services";
+			}
+		}
+		
+		public override string Url {
+			get {
+				return "http://www.xs4all.nl/~jeroen/";
+			}
+		}
+		
+		public override string Version {
+			get {
+				return "1.0";
+			}
+		}
+	
+		public override bool InitializePlugin (byte major, byte minor)
+		{
+			return true;
+		}
+		
+		public override void FinalizePlugin ()
+		{
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/StringParserService.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/StringParserService.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/StringParserService.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,213 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Text;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// this class parses internal ${xyz} tags of sd.
+	/// All environment variables are avaible under the name env.[NAME]
+	/// where [NAME] represents the string under which it is avaiable in
+	/// the environment.
+	/// </summary>
+	public class StringParserService : AbstractService
+	{
+		PropertyDictionary properties         = new PropertyDictionary();
+		Hashtable          stringTagProviders = new Hashtable();
+		
+		public PropertyDictionary Properties {
+			get {
+				return properties;
+			}
+		}
+		
+		public StringParserService()
+		{
+			IDictionary variables = Environment.GetEnvironmentVariables();
+			foreach (string name in variables.Keys) {
+				properties.Add("env:" + name, (string)variables[name]);
+			}
+		}
+		
+		public string Parse(string input)
+		{
+			return Parse(input, null);
+		}
+		
+		/// <summary>
+		/// Parses an array and replaces the elements
+		/// </summary>
+		public void Parse(ref string[] inputs)
+		{
+			for (int i = inputs.GetLowerBound(0); i <= inputs.GetUpperBound(0); ++i) {
+				inputs[i] = Parse(inputs[i], null);
+			}
+		}
+		
+		public void RegisterStringTagProvider(IStringTagProvider tagProvider)
+		{
+			foreach (string str in tagProvider.Tags) {
+				stringTagProviders[str.ToUpper()] = tagProvider;
+			}
+		}
+		
+		string Replace (string[,] customTags, string propertyName)
+		{
+			string propertyValue = null;
+			switch (propertyName.ToUpper()) {
+				case "DATE": // current date
+					propertyValue = DateTime.Today.ToShortDateString();
+					break;
+				case "TIME": // current time
+					propertyValue = DateTime.Now.ToShortTimeString();
+					break;
+				default:
+					propertyValue = null;
+					if (customTags != null) {
+						for (int j = 0; j < customTags.GetLength(0); ++j) {
+							if (propertyName.ToUpper() == customTags[j, 0].ToUpper()) {
+								propertyValue = customTags[j, 1];
+								break;
+							}
+						}
+					}
+					
+					if (propertyValue == null) {
+						propertyValue = properties[propertyName.ToUpper()];
+					}
+					
+					if (propertyValue == null) {
+						IStringTagProvider stringTagProvider = stringTagProviders[propertyName.ToUpper()] as IStringTagProvider;
+						if (stringTagProvider != null) {
+							propertyValue = stringTagProvider.Convert(propertyName.ToUpper());
+						}
+					}
+					
+					if (propertyValue == null) {
+						int k = propertyName.IndexOf(':');
+						if (k > 0) {
+							switch (propertyName.Substring(0, k).ToUpper()) {
+								case "RES":
+									IResourceService resourceService = (IResourceService)ServiceManager.Services.GetService(typeof(IResourceService));
+									if (resourceService != null) {
+											propertyValue = Parse(resourceService.GetString(propertyName.Substring(k + 1)), customTags);
+									}
+									break;
+								case "PROPERTY":
+									PropertyService propertyService = (PropertyService)ServiceManager.Services.GetService(typeof(PropertyService));
+									propertyValue = propertyService.GetProperty(propertyName.Substring(k + 1)).ToString();
+									break;
+							}
+						}
+					}
+					break;
+			}
+			
+			return propertyValue;
+		}
+			
+		/// <summary>
+		/// Expands ${xyz} style property values.
+		/// </summary>
+		public string Parse(string input, string [,] customTags)
+		{
+			StringBuilder sb = new StringBuilder (input.Length);
+			for (int i = 0; i < input.Length; i++) {
+				if (input [i] != '$') {
+					sb.Append (input [i]);
+					continue;
+				}
+				
+				int start = i;
+				
+				if (++i >= input.Length)
+					break;
+				
+				if (input [i] != '{') {
+					sb.Append (input [i]);
+					continue;
+				}
+				
+				int end;
+				for (end = ++i; end < input.Length; end++) {
+					if (input [end] == '}')
+						break;
+				}
+				
+				string replacement;
+				if (end == input.Length || (replacement = Replace (customTags, input.Substring (i, end - i))) == null) {
+					sb.Append (input.Substring (start, end - start));
+					break;
+				}
+				
+				sb.Append (replacement);
+				i = end;
+			}
+			
+			sb.Replace (@"\&", "||!|");
+			sb.Replace ("&", "_");
+			sb.Replace ("||!|", "&");
+			
+			return sb.ToString ();
+		}
+	}
+	
+	public class PropertyDictionary : DictionaryBase
+	{
+		/// <summary>
+		/// Maintains a list of the property names that are readonly.
+		/// </summary>
+		StringCollection readOnlyProperties = new StringCollection();
+		
+		/// <summary>
+		/// Adds a property that cannot be changed.
+		/// </summary>
+		/// <remarks>
+		/// Properties added with this method can never be changed.  Note that
+		/// they are removed if the <c>Clear</c> method is called.
+		/// </remarks>
+		/// <param name="name">Name of property</param>
+		/// <param name="value">Value of property</param>
+		public void AddReadOnly(string name, string value) 
+		{
+			if (!readOnlyProperties.Contains(name)) {
+				readOnlyProperties.Add(name);
+				Dictionary.Add(name, value);
+			}
+		}
+		
+		/// <summary>
+		/// Adds a property to the collection.
+		/// </summary>
+		/// <param name="name">Name of property</param>
+		/// <param name="value">Value of property</param>
+		public void Add(string name, string value) 
+		{
+			if (!readOnlyProperties.Contains(name)) {
+				Dictionary.Add(name, value);
+			}
+		}
+		
+		public string this[string name] {
+			get { 
+				return (string)Dictionary[(object)name.ToUpper()];
+			}
+			set {
+				Dictionary[name.ToUpper()] = value;
+			}
+		}
+		
+		protected override void OnClear() 
+		{
+			readOnlyProperties.Clear();
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/UnknownPropertyNodeException.cs
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/UnknownPropertyNodeException.cs	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/UnknownPropertyNodeException.cs	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,21 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Mike Krüger" email="mike at icsharpcode.net"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	/// <summary>
+	/// Is thrown when an unknown XmlNode in a property file is encountered.
+	/// </summary>
+	public class UnknownPropertyNodeException : Exception
+	{
+		public UnknownPropertyNodeException(string nodeName) : base("unknown XmlNode : " + nodeName)
+		{
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Plugins/Services/services.plugin.in
===================================================================
--- branches/MonoDevelop-playground/src/Plugins/Services/services.plugin.in	2004-02-28 23:00:02 UTC (rev 1059)
+++ branches/MonoDevelop-playground/src/Plugins/Services/services.plugin.in	2004-02-29 09:47:46 UTC (rev 1060)
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin version="1.0">
+	<assembly>@assembly@</assembly>
+	<class name="MonoDevelop.Services.ServicesPlugin"/>
+</plugin>




More information about the Monodevelop-patches-list mailing list