3
// Mikael Hallendal <micke@imendio.com>
13
using System.Collections;
14
using System.Globalization;
17
using System.Threading;
20
namespace Imendio.Blam {
22
public class OpmlDialog {
23
[Widget] Gtk.Dialog opmlDialog;
24
[Widget] Gtk.Image dialogImage;
25
[Widget] Gtk.Entry urlEntry;
26
[Widget] Gtk.Button importButton;
28
private Gtk.FileSelection fileDialog;
30
private OpmlStatusDialog opmlStatusDialog;
32
public event ChannelEventHandler ChannelAdded;
33
public event ActionFinishedHandler ImportFinished;
35
Gtk.Window mParentWindow;
42
urlEntry.Text = value;
46
public OpmlDialog (Gtk.Window parentWindow)
48
Glade.XML gladeXML = Glade.XML.FromAssembly("blam.glade",
51
gladeXML.Autoconnect(this);
53
mParentWindow = parentWindow;
54
opmlDialog.TransientFor = mParentWindow;
55
opmlDialog.Icon = Gdk.Pixbuf.LoadFromResource("blam.png");
58
Gdk.Pixbuf.LoadFromResource ("blam-add-news.png");
60
Gtk.Drag.DestSet(opmlDialog, DestDefaults.All,
61
Application.DragEntries,
62
DragAction.Copy | DragAction.Move);
64
opmlDialog.DragDataReceived += DragDataReceivedCb;
66
opmlStatusDialog = new OpmlStatusDialog (parentWindow);
72
opmlDialog.ShowAll ();
75
private void DragDataReceivedCb(object o, DragDataReceivedArgs args)
77
SelectionData d = args.SelectionData;
79
if (d.Length < 0 && d.Format != 8){
80
Gtk.Drag.Finish(args.Context, false, false, args.Time);
84
UTF8Encoding encoding = new UTF8Encoding( );
85
string text = encoding.GetString(d.Data);
89
Gtk.Drag.Finish(args.Context, true, true, args.Time);
92
private void FileButtonClicked(object obj, EventArgs args)
94
if (fileDialog == null) {
95
fileDialog = new Gtk.FileSelection (Catalog.GetString ("Select OPML file"));
96
fileDialog.Modal = true;
97
fileDialog.ShowFileops = false;
100
fileDialog.TransientFor = this.opmlDialog;
101
int result = fileDialog.Run();
104
case (int)ResponseType.Ok:
105
urlEntry.Text = fileDialog.Filename;
112
private int nrChannels;
114
private void ChannelReadCb (Channel channel)
118
string status = String.Format (Catalog.GetString ("Imported {0} channels"), nrChannels);
120
if (ChannelAdded != null) {
121
ChannelAdded (channel);
125
private void ImportFinishedCb ()
127
// FIXME: Signal this to application
128
opmlStatusDialog.Hide ();
130
if (ImportFinished != null) {
131
ImportFinished (String.Format (Catalog.GetString ("Imported {0} channels from OPML file"), nrChannels));
135
private void ImportErrorCb (string errorMsg)
137
opmlStatusDialog.Hide ();
139
ShowErrorDialog (Url, errorMsg);
142
public void ShowErrorDialog (string url, string errorMsg)
144
string str = String.Format (Catalog.GetString ("Failed to import {0}"), url);
146
Gtk.Dialog dialog = new HigDialog (mParentWindow,
147
DialogFlags.Modal | DialogFlags.DestroyWithParent,
156
public static string GetXmlExceptionString ()
158
return Catalog.GetString ("Not a valid OPML file");
161
public static string GetFileNotFoundExceptionString ()
163
return Catalog.GetString ("File not found");
166
public static string GetUriFormatExceptionString ()
168
return Catalog.GetString ("Invalid file name");
171
public static string GetWebExceptionString ()
173
return Catalog.GetString ("Could not find OPML file");
176
public static string GetUnknownExceptionString ()
178
return Catalog.GetString ("Unknown error");
181
private void ImportButtonClicked (object obj, EventArgs args)
184
string errorMsg = "";
187
Uri uri = new Uri (Url);
188
OpmlReader reader = new OpmlReader (uri);
189
reader.ChannelRead += ChannelReadCb;
190
reader.ImportFinished += ImportFinishedCb;
191
reader.ErrorEvent += ImportErrorCb;
196
opmlStatusDialog.Show (Catalog.GetString ("Opening OPML file"));
197
reader.ReadChannelsAsync ();
200
reader.ReadChannels ();
203
catch (XmlException) {
204
errorMsg = GetXmlExceptionString ();
206
catch (FileNotFoundException) {
207
errorMsg = GetFileNotFoundExceptionString ();
209
catch (UriFormatException) {
210
errorMsg = GetUriFormatExceptionString ();
213
errorMsg = GetUnknownExceptionString ();
217
ShowErrorDialog (Url, errorMsg);
220
private void CancelButtonClicked (object obj, EventArgs args)
225
private void UrlEntryChanged (object obj, EventArgs args)
227
if (urlEntry.Text == "") {
228
importButton.Sensitive = false;
230
importButton.Sensitive = true;
234
private void UrlEntryActivated (object obj, EventArgs args)
236
if (urlEntry.Text == "") {
240
importButton.Click ();
243
public class OpmlStatusDialog {
244
[Widget] Gtk.Dialog opmlStatusDialog;
245
[Widget] Gtk.ProgressBar progressBar;
247
private uint timeoutId;
249
public OpmlStatusDialog (Gtk.Window parentWindow)
251
Glade.XML gladeXML = Glade.XML.FromAssembly("blam.glade",
254
gladeXML.Autoconnect(this);
255
opmlStatusDialog.TransientFor = parentWindow;
256
opmlStatusDialog.Icon = Gdk.Pixbuf.LoadFromResource("blam.png");
259
public void Show (string initialStatus)
261
timeoutId = GLib.Timeout.Add (100, new GLib.TimeoutHandler (UpdateProgress));
262
opmlStatusDialog.ShowAll ();
267
opmlStatusDialog.Hide ();
269
GLib.Source.Remove (timeoutId);
274
private void CancelButtonClicked (object obj, EventArgs args)
276
System.Console.WriteLine ("Cancel");
277
opmlStatusDialog.Hide ();
280
private bool UpdateProgress ()
282
progressBar.Pulse ();
289
public class OpmlReader {
291
public delegate void ImportFinishedHandler ();
292
public delegate void ErrorHandler (string errorMsg);
294
public event ChannelEventHandler ChannelRead;
295
public event ImportFinishedHandler ImportFinished;
296
public event ErrorHandler ErrorEvent;
300
private string mErrorMsg;
302
private IList mChannels;
303
protected IList ReadList {
309
public OpmlReader (Uri uri)
312
mChannels = ArrayList.Synchronized (new ArrayList ());
315
public void ReadChannels ()
320
public void ReadChannelsAsync ()
322
Thread thread = new Thread (new ThreadStart (ReadThread));
326
private void DoRead ()
328
XmlTextReader reader = new XmlTextReader (mUri.ToString ());
330
while (reader.Read ()) {
331
string nodeName = reader.Name;
335
// Ignore all other nodes
336
if (nodeName == "outline") {
337
name = reader.GetAttribute ("text");
338
url = reader.GetAttribute ("xmlUrl");
340
if (name == null || url == null) {
344
Channel channel = new Channel (name, url);
345
new MainloopEmitter (this.ChannelRead, channel).Emit ();
348
GLib.Idle.Add (new GLib.IdleHandler (EmitImportFinished));
351
private void ReadThread ()
354
XmlTextReader reader = new XmlTextReader (mUri.ToString ());
356
while (reader.Read ()) {
357
string nodeName = reader.Name;
361
// Ignore all other nodes
362
if (nodeName == "outline") {
363
name = reader.GetAttribute ("text");
364
url = reader.GetAttribute ("xmlUrl");
366
if (name == null || url == null) {
370
Channel channel = new Channel (name, url);
371
new MainloopEmitter (this.ChannelRead, channel).Emit ();
374
GLib.Idle.Add (new GLib.IdleHandler (EmitImportFinished));
377
catch (XmlException) {
378
mErrorMsg = OpmlDialog.GetXmlExceptionString ();
380
catch (FileNotFoundException) {
381
mErrorMsg = OpmlDialog.GetFileNotFoundExceptionString ();
383
catch (UriFormatException) {
384
mErrorMsg = OpmlDialog.GetUriFormatExceptionString ();
386
catch (System.Net.WebException) {
387
mErrorMsg = OpmlDialog.GetWebExceptionString ();
390
mErrorMsg = OpmlDialog.GetUnknownExceptionString ();
393
GLib.Idle.Add (new GLib.IdleHandler (EmitErrorEvent));
396
private bool EmitImportFinished ()
398
if (ImportFinished != null) {
405
private bool EmitErrorEvent ()
407
if (ErrorEvent != null) {
408
ErrorEvent (mErrorMsg);
415
public class OpmlWriter {
416
public static void Write (ChannelCollection collection, string fileName)
418
XmlTextWriter xtw = new XmlTextWriter (fileName, null);
420
xtw.Formatting = Formatting.Indented;
423
xtw.WriteStartDocument ();
424
xtw.WriteStartElement ("opml");
425
xtw.WriteAttributeString ("version", "1.0");
429
WriteBody (xtw, collection);
431
xtw.WriteEndElement ();
437
private static void WriteHeader (XmlTextWriter xtw)
439
xtw.WriteStartElement ("head");
441
xtw.WriteElementString ("dateCreated", DateTime.Now.ToString ("r"));
443
xtw.WriteEndElement ();
446
private static void WriteBody (XmlTextWriter xtw, ChannelCollection collection)
448
xtw.WriteStartElement ("body");
450
foreach (Channel channel in collection.Channels) {
451
xtw.WriteStartElement ("outline");
452
xtw.WriteAttributeString ("text", channel.Name);
453
xtw.WriteAttributeString ("xmlUrl", channel.Url);
454
xtw.WriteEndElement ();
457
xtw.WriteEndElement ();