using System;
using SemWeb;
using System.IO;
using Mono.Unix;
namespace FSpot {
public class InfoDialog : Gtk.Dialog {
InfoDisplay info_display;
public InfoDisplay InfoDisplay {
get { return info_display; }
}
public InfoDialog (Gtk.Window parent) : base (Catalog.GetString ("Metadata Browser"),
parent,
Gtk.DialogFlags.NoSeparator | Gtk.DialogFlags.DestroyWithParent)
{
info_display = new InfoDisplay ();
SetDefaultSize (400, 400);
Gtk.ScrolledWindow scrolled = new Gtk.ScrolledWindow ();
VBox.PackStart (scrolled);
scrolled.Add (info_display);
}
}
public class InfoDisplay : Gtk.HTML {
public InfoDisplay ()
{
}
private Exif.ExifData exif_info;
private IBrowsableItem photo;
public IBrowsableItem Photo {
get {
return photo;
}
set {
photo = value;
if (exif_info != null)
exif_info.Dispose ();
if (photo != null) {
if (File.Exists (photo.DefaultVersionUri.LocalPath))
exif_info = new Exif.ExifData (photo.DefaultVersionUri.LocalPath);
} else {
exif_info = null;
}
this.Update ();
}
}
protected override void OnLinkClicked (string url)
{
if (url.StartsWith ("/")) {
// do a lame job of creating a URI out of local paths
url = "file://" + url;
}
GnomeUtil.UrlShow (null, url);
}
protected override void OnStyleSet (Gtk.Style previous)
{
this.Update ();
}
private static string Color (Gdk.Color color)
{
Byte r = (byte)(color.Red / 256);
Byte b = (byte)(color.Blue / 256);
Byte g = (byte)(color.Green / 256);
string value = r.ToString ("x2") + g.ToString ("x2") + b.ToString ("x2");
return value;
}
protected override void OnUrlRequested (string url, Gtk.HTMLStream stream)
{
if (url == "exif:thumbnail") {
byte [] data = exif_info.Data;
if (data.Length > 0) {
stream.Write (data, data.Length);
stream.Close (Gtk.HTMLStreamStatus.Ok);
} else
stream.Close (Gtk.HTMLStreamStatus.Error);
}
}
private static string Escape (string value)
{
if (value == null)
return "(null)";
value = value.Replace ("&", "&");
value = value.Replace (">", ">");
value = value.Replace ("<", "<");
value = value.Replace ("\r\n", "
");
value = value.Replace ("\n", "
");
return value;
}
private static string GetExportUrl (ExportItem export)
{
switch (export.ExportType) {
case ExportStore.FlickrExportType:
string[] split_token = export.ExportToken.Split (':');
return String.Format ("http://www.{0}/photos/{1}/{2}/", split_token[2],
split_token[0], split_token[3]);
case ExportStore.FolderExportType:
Gnome.Vfs.Uri uri = new Gnome.Vfs.Uri (export.ExportToken);
return (uri.HasParent) ? uri.Parent.ToString () : export.ExportToken;
case ExportStore.Gallery2ExportType:
string[] split_item = export.ExportToken.Split (':');
return String.Format ("{0}:{1}?g2_itemId={2}",split_item[0], split_item[1], split_item[2]);
case ExportStore.OldFolderExportType: //This is obsolete and meant to be removed once db reach rev4
case ExportStore.PicasaExportType:
case ExportStore.SmugMugExportType:
return export.ExportToken;
default:
return null;
}
}
private static string GetExportLabel (ExportItem export)
{
switch (export.ExportType) {
case ExportStore.FlickrExportType:
string[] split_token = export.ExportToken.Split (':');
return String.Format ("Flickr ({0})", split_token[1]);
case ExportStore.OldFolderExportType: //Obsolete, remove after db rev4
return Catalog.GetString ("Folder");
case ExportStore.FolderExportType:
return Catalog.GetString ("Folder");
case ExportStore.PicasaExportType:
return Catalog.GetString ("Picasaweb");
case ExportStore.SmugMugExportType:
return Catalog.GetString ("SmugMug");
case ExportStore.Gallery2ExportType:
return Catalog.GetString ("Gallery2");
default:
return null;
}
}
private void Update ()
{
Gtk.HTMLStream stream = this.Begin (null, "text/html; charset=utf-8", Gtk.HTMLBeginFlags.Scroll);
string bg = Color (this.Style.Background (Gtk.StateType.Active));
string fg = Color (this.Style.Foreground (Gtk.StateType.Active));
string ig = Color (this.Style.Base (Gtk.StateType.Active));
stream.Write ("
");
bool empty = true;
bool missing = false;
System.Exception error = null;
if (exif_info != null) {
foreach (Exif.ExifContent content in exif_info.GetContents ()) {
Exif.ExifEntry [] entries = content.GetEntries ();
if (entries.Length > 0) {
empty = false;
break;
}
}
if (exif_info.Data.Length > 0)
stream.Write (String.Format ("" +
" |
", ig));
int i = 0;
foreach (Exif.ExifContent content in exif_info.GetContents ()) {
Exif.ExifEntry [] entries = content.GetEntries ();
i++;
if (entries.Length < 1)
continue;
stream.Write ("| "
+ Exif.ExifUtil.GetIfdNameExtended ((Exif.Ifd)i - 1) + " |
|---|
");
foreach (Exif.ExifEntry entry in entries) {
stream.Write ("
| ");
if (entry.Title != null)
stream.Write (entry.Title);
else
stream.Write ("<Unknown Tag ID=" + entry.Tag.ToString () + ">");
stream.Write (" | ");
string s = entry.Value;
if (s != null && s != String.Empty)
stream.Write (s);
stream.Write (" |
");
}
}
}
if (photo != null) {
MetadataStore store = new MetadataStore ();
try {
using (ImageFile img = ImageFile.Create (photo.DefaultVersionUri)) {
if (img is SemWeb.StatementSource) {
StatementSource source = (StatementSource)img;
source.Select (store);
}
}
} catch (System.IO.FileNotFoundException) {
missing = true;
} catch (System.Exception e){
// Sometimes we don't get the right exception, check for the file
if (!System.IO.File.Exists (photo.DefaultVersionUri.LocalPath)) {
missing = true;
} else {
// if the file is there but we still got an exception display it.
error = e;
}
}
if (store.StatementCount > 0) {
#if false
using (System.IO.Stream xmpstream = System.IO.File.OpenWrite ("tmp.xmp")) {
xmpstream.Length = 0;
FSpot.Xmp.XmpFile file;
file = new FSpot.Xmp.XmpFile ();
store.Select (file);
file.Save (xmpstream);
}
#endif
empty = false;
stream.Write ("
| "
+ Catalog.GetString ("Extended Metadata") + " |
");
foreach (Statement stmt in store) {
// Skip anonymous subjects because they are
// probably part of a collection
if (stmt.Subject.Uri == null && store.SelectSubjects (null, stmt.Subject).Length > 0)
continue;
string title;
string value;
Description.GetDescription (store, stmt, out title, out value);
stream.Write ("| ");
stream.Write (title);
stream.Write (" | ");
if (value != null)
value = Escape (value);
else {
MemoryStore substore = store.Select (new Statement ((Entity)stmt.Object, null, null, null)).Load();
WriteCollection (substore, stream);
}
if (value != null && value != String.Empty)
stream.Write (value);
stream.Write (" |
");
}
}
if (Core.Database != null && photo is Photo) {
stream.Write ("| " + Catalog.GetString ("Exported Locations") + " |
");
Photo p = photo as Photo;
foreach (ExportItem export in Core.Database.Exports.GetByImageId (p.Id, p.DefaultVersionId)) {
string url = GetExportUrl (export);
string label = GetExportLabel (export);
if (url == null || label == null)
continue;
stream.Write ("| ");
stream.Write (String.Format ("{1}", url, label));
stream.Write (" |
");
}
}
}
if (empty) {
string msg;
if (photo == null) {
// FIXME we should pass the full selection to the info display and let it
// handle multiple items however it wants.
msg = String.Format ("| "
+ "{1} |
", ig,
Catalog.GetString ("No active photo"));
} else if (missing) {
string text = String.Format (Catalog.GetString ("The photo \"{0}\" does not exist"), photo.DefaultVersionUri);
msg = String.Format ("| "
+ "{1} |
", ig, text);
} else {
msg = String.Format ("| "
+ "{1} |
", ig,
Catalog.GetString ("No metadata available"));
if (error != null) {
String.Format ("{0}", error);
}
}
stream.Write (msg);
}
stream.Write ("
");
End (stream, Gtk.HTMLStreamStatus.Ok);
}
private void WriteCollection (MemoryStore substore, Gtk.HTMLStream stream)
{
string type = null;
foreach (Statement stmt in substore) {
if (stmt.Predicate.Uri == MetadataStore.Namespaces.Resolve ("rdf:type")) {
string prefix;
MetadataStore.Namespaces.Normalize (stmt.Object.Uri, out prefix, out type);
}
}
stream.Write ("");
foreach (Statement sub in substore) {
if (sub.Object is Literal) {
string title;
string value = ((Literal)(sub.Object)).Value;
string vc = String.Empty;
Description.GetDescription (substore, sub, out title, out value);
if (type != "Alt")
vc = " bgcolor=" + Color (Style.Backgrounds [(int)Gtk.StateType.Normal]);
if (type == null)
stream.Write (String.Format ("| {0} | {1} |
",
Escape (title),
Escape (value),
Color (Style.MidColors [(int)Gtk.StateType.Normal]),
Color (Style.Backgrounds [(int)Gtk.StateType.Normal])));
else
stream.Write (String.Format ("| {0} |
",
Escape (value),
vc));
} else {
if (type == null) {
stream.Write ("| ");
MemoryStore substore2 = substore.Select (new Statement ((Entity)sub.Object, null, null, null)).Load();
if (substore.StatementCount > 0)
WriteCollection (substore2, stream);
stream.Write (" |
");
}
}
}
stream.Write (" |
");
}
private class StreamSink : SemWeb.StatementSink
{
Gtk.HTMLStream stream;
SemWeb.StatementSource source;
InfoDisplay info;
public StreamSink (SemWeb.StatementSource source, Gtk.HTMLStream stream, InfoDisplay info)
{
this.stream = stream;
this.info = info;
this.source = source;
}
public bool Add (SemWeb.Statement stmt)
{
string predicate = stmt.Predicate.Uri;
string title = System.IO.Path.GetFileName (predicate);
string bg = InfoDisplay.Color (info.Style.Background (Gtk.StateType.Active));
string fg = InfoDisplay.Color (info.Style.Foreground (Gtk.StateType.Active));
//if (MetadataStore.Namespaces.GetPrefix (path) != null) {
if (stmt.Object is Literal) {
stream.Write ("| ");
stream.Write (title);
stream.Write (" | ");
string s = ((SemWeb.Literal)(stmt.Object)).Value;
/*
else {
MemoryStore store = source.Select (stmt.Invert (), new SelectPartialFilter (true, false, false, false));
s = "";
foreach (Statement sub in store) {
s += sub.Object.ToString () + "/n";
}
}
*/
if (s != null && s != String.Empty)
stream.Write (s);
stream.Write (" |
");
}
return true;
}
}
}
}