// // Utility functions. // // Miguel de Icaza (miguel@ximian.com). // // (C) 2002 Ximian, Inc. // // using System.Runtime.InteropServices; using System.Threading; using System.Collections; using System.IO; using System.Text; using System; class Semaphore { int count = 0; public Semaphore () { } public void Down () { lock (this){ while (count <= 0){ Monitor.Wait (this, Timeout.Infinite); } count--; } } public void Up () { lock (this){ count++; Monitor.Pulse (this); } } } class Timer : IDisposable { System.DateTime start; string label; public Timer (string label) { this.label = label; start = System.DateTime.Now; } public System.TimeSpan ElapsedTime { get { return System.DateTime.Now - start; } } public void WriteElapsed (string message) { System.Console.WriteLine ("{0} {1} {2}", label, message, ElapsedTime); } public void Dispose () { WriteElapsed ("timer stopped:"); } } public class UriList : ArrayList { public UriList (Photo [] photos) { foreach (Photo p in photos) { Uri uri; try { uri = p.DefaultVersionUri; } catch { continue; } Add (uri); } } public UriList () : base () { } private void LoadFromString (string data) { //string [] items = System.Text.RegularExpressions.Regex.Split ("\n", data); string [] items = data.Split ('\n'); foreach (String i in items) { if (!i.StartsWith ("#")) { Uri uri; String s = i; if (i.EndsWith ("\r")) { s = i.Substring (0, i.Length - 1); Console.WriteLine ("uri = {0}", s); } try { uri = new Uri (s); } catch { #if true //Workaround to bgo 362016 in gnome-screenshot. Remove this hack when gnome 2.6.18 is widely distributed. if (System.Text.RegularExpressions.Regex.IsMatch (s, "^file:/[^/]")) { try { s = "file:///" + s.Substring(6); uri = new Uri (s); Console.WriteLine ("Converted uri from file:/ to >>{0}<<", s); } catch { continue; } } else continue; #else continue; #endif } Add (uri); } } } // NOTE: this was copied from mono's System.Uri where it is protected. public static string EscapeString (string str, bool escapeReserved, bool escapeHex, bool escapeBrackets) { if (str == null) return String.Empty; byte [] data = Encoding.UTF8.GetBytes (str); StringBuilder s = new StringBuilder (); int len = data.Length; for (int i = 0; i < len; i++) { char c = (char) data [i]; // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" // control = // space = // delims = "<" | ">" | "#" | "%" | <"> // unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`" // check for escape code already placed in str, // i.e. for encoding that follows the pattern // "%hexhex" in a string, where "hex" is a digit from 0-9 // or a letter from A-F (case-insensitive). if('%' == c && Uri.IsHexEncoding(str,i)) { // if ,yes , copy it as is s.Append(c); s.Append(str[++i]); s.Append(str[++i]); continue; } if ((c <= 0x20) || (c >= 0x7f) || ("<>%\"{}|\\^`".IndexOf (c) != -1) || (escapeHex && (c == '#')) || (escapeBrackets && (c == '[' || c == ']')) || (escapeReserved && (";/?:@&=+$,".IndexOf (c) != -1))) { s.Append (Uri.HexEscape (c)); continue; } s.Append (c); } return s.ToString (); } static char[] CharsToQuote = { ';', '?', ':', '@', '&', '=', '$', ',', '#' }; public static string UriToStringEscaped (Uri uri) { return EscapeString (uri.ToString (), false, true, false); } public static string PathToFileUriEscaped (string path) { return UriToStringEscaped (PathToFileUri (path)); } public static Uri PathToFileUri (string path) { path = Path.GetFullPath (path); StringBuilder builder = new StringBuilder (); builder.Append (Uri.UriSchemeFile); builder.Append (Uri.SchemeDelimiter); int i; while ((i = path.IndexOfAny (CharsToQuote)) != -1) { if (i > 0) builder.Append (path.Substring (0, i)); builder.Append (Uri.HexEscape (path [i])); path = path.Substring (i+1); } builder.Append (path); return new Uri (builder.ToString (), true); } public UriList (string [] uris) { // FIXME this is so lame do real chacking at some point foreach (string str in uris) { AddUnknown (str); } } public void AddUnknown (string unknown) { Uri uri; if (File.Exists (unknown) || Directory.Exists (unknown)) uri = PathToFileUri (unknown); else uri = new Uri (unknown); Add (uri); } public UriList (string data) { LoadFromString (data); } public UriList (Gtk.SelectionData selection) { // FIXME this should check the atom etc. LoadFromString (System.Text.Encoding.UTF8.GetString (selection.Data)); } public new Uri [] ToArray () { return ToArray (typeof (Uri)) as Uri []; } public void Add (string path) { AddUnknown (path); } public void Add (Uri uri) { Add ((object)uri); } public void Add (FSpot.IBrowsableItem item) { Add (item.DefaultVersionUri); } public override string ToString () { StringBuilder list = new StringBuilder (); foreach (Uri uri in this) { if (uri == null) break; list.Append (uri.ToString () + Environment.NewLine); } return list.ToString (); } public string [] ToLocalPaths () { int count = 0; foreach (Uri uri in this) { if (uri.IsFile) count++; } String [] paths = new String [count]; count = 0; foreach (Uri uri in this) { if (uri.IsFile) paths[count++] = uri.LocalPath; } return paths; } } class GtkUtil { public static Gtk.MenuItem MakeMenuItem (Gtk.Menu menu, string l, EventHandler e) { return MakeMenuItem (menu, l, e, true); } public static Gtk.MenuItem MakeMenuItem (Gtk.Menu menu, string l, EventHandler e, bool enabled) { Gtk.MenuItem i; Gtk.StockItem item = Gtk.StockItem.Zero; if (Gtk.StockManager.Lookup (l, ref item)) { i = new Gtk.ImageMenuItem (l, new Gtk.AccelGroup ()); } else { i = new Gtk.MenuItem (l); } if (e != null) i.Activated += e; i.Sensitive = enabled; menu.Append (i); i.Show (); return i; } public static Gtk.MenuItem MakeMenuItem (Gtk.Menu menu, string label, string image_name, EventHandler e, bool enabled) { Gtk.ImageMenuItem i = new Gtk.ImageMenuItem (label); i.Activated += e; i.Sensitive = enabled; i.Image = Gtk.Image.NewFromIconName (image_name, Gtk.IconSize.Menu); menu.Append (i); i.Show (); return i; } public static Gtk.MenuItem MakeCheckMenuItem (Gtk.Menu menu, string label, EventHandler e, bool enabled, bool active, bool as_radio) { Gtk.CheckMenuItem i = new Gtk.CheckMenuItem (label); i.Activated += e; i.Sensitive = enabled; i.DrawAsRadio = as_radio; i.Active = active; menu.Append(i); i.Show (); return i; } public static void MakeMenuSeparator (Gtk.Menu menu) { Gtk.SeparatorMenuItem i = new Gtk.SeparatorMenuItem (); menu.Append (i); i.Show (); } private class SignalFuncHelper { public SignalFuncHelper (System.EventHandler e) { this.e = e; } public void Func () { this.e (Sender, System.EventArgs.Empty); } System.EventHandler e; public object Sender; } public static Gtk.ToolButton ToolButtonFromTheme (string theme_id, string label, bool important) { Gtk.ToolButton button = new Gtk.ToolButton (null, null); button.Label = label; button.IconName = theme_id; button.IsImportant = important; button.UseUnderline = true; return button; } public static Gdk.Pixbuf TryLoadIcon (Gtk.IconTheme theme, string icon_name, int size, Gtk.IconLookupFlags flags) { try { return theme.LoadIcon (icon_name, size, flags); } catch { try { return theme.LoadIcon ("gtk-missing-image", size, flags); } catch { return null; } } } } public class SizeUtil { public static string ToHumanReadable (long size) { string tmp_str = String.Empty; float tmp_size = size; int k = 0; string[] size_abr = {"bytes", "kB", "MB", "GB", "TB" }; while (tmp_size > 700) { //it's easier to read 0.9MB than 932kB tmp_size = tmp_size / 1024; k++; } if (tmp_size < 7) tmp_str = tmp_size.ToString ("0.##"); else if (tmp_size < 70) tmp_str = tmp_size.ToString ("##.#"); else tmp_str = tmp_size.ToString ("#,###"); if (k < size_abr.Length) return tmp_str + " " + size_abr[k]; else return size.ToString(); } } public class GnomeUtil { Gtk.Window window; string url; private GnomeUtil (Gtk.Window window, string url) { this.window = window; this.url = url; } public void Show () { try { Gnome.Url.Show (url); } catch (Exception ge) { System.Console.WriteLine (ge.ToString ()); HigMessageDialog md = new HigMessageDialog (window, Gtk.DialogFlags.DestroyWithParent, Gtk.MessageType.Error, Gtk.ButtonsType.Ok, Mono.Unix.Catalog.GetString ("There was an error invoking the external handler"), String.Format (Mono.Unix.Catalog.GetString ("Received error:{1}\"{0}\"{1}"), ge.Message, Environment.NewLine)); md.Run (); md.Destroy (); } } public static void UrlShow (Gtk.Window owner_window, string url) { GnomeUtil disp = new GnomeUtil (owner_window, url); Gtk.Application.Invoke (disp, null, delegate (object sender, EventArgs args) { ((GnomeUtil) disp).Show (); }); } public static void ShowHelp (string filename, string link_id, Gdk.Screen screen, Gtk.Window parent) { try { Gnome.Help.DisplayDesktopOnScreen ( Gnome.Program.Get (), FSpot.Global.HelpDirectory, filename, link_id, screen); } catch { string message = Mono.Unix.Catalog.GetString ("The \"F-Spot Manual\" could " + "not be found. Please verify " + "that your installation has been " + "completed successfully."); HigMessageDialog dialog = new HigMessageDialog (parent, Gtk.DialogFlags.DestroyWithParent, Gtk.MessageType.Error, Gtk.ButtonsType.Ok, Mono.Unix.Catalog.GetString ("Help not found"), message); dialog.Run (); dialog.Destroy (); } } }