Thumbnail file hits. Based on a patch from D Bera
[beagle.git] / ImLogViewer / ImLogWindow.cs
blobb0ef4db0752d879d87f25b4b77a48cac3835a58b
1 //
2 // ImLogWindow.cs
3 //
4 // Lukas Lipka <lukas@pmad.net>
5 // Raphael Slinckx <rslinckx@gmail.com>
6 //
7 // Copyright (C) 2005 Novell, Inc.
8 //
10 using System;
11 using System.Collections;
12 using System.IO;
13 using Gtk;
14 using Glade;
15 using System.Threading;
16 using Beagle.Util;
17 using Mono.Posix;
19 namespace ImLogViewer {
21 public class ImLogWindow {
22 [Widget] Window imviewer;
23 [Widget] TreeView timelinetree;
24 [Widget] Label time_title;
25 [Widget] Entry search_entry;
26 [Widget] Button search_button;
27 [Widget] Button clear_button;
28 [Widget] TextView conversation;
30 private string selected_log;
32 private string speaking_to;
33 private string log_path;
34 private string highlight_text;
35 private string search_text;
37 private TreeStore tree_store;
38 private ThreadNotify index_thread_notify;
39 private Timeline timeline = new Timeline ();
41 private string client;
43 public ImLogWindow (string path, string search, string highlight)
45 // FIXME: This is a bunch of crap, ImLog should be more dynamic.
46 if (path.IndexOf (".gaim/logs") != -1)
47 client = "gaim";
48 else if (path.IndexOf ("apps/kopete/logs") != -1)
49 client = "kopete";
51 if (Directory.Exists (path)) {
52 log_path = path;
53 } else if (File.Exists (path)) {
54 log_path = Path.GetDirectoryName (path);
55 selected_log = path;
56 } else {
57 Console.WriteLine ("ERROR: Log path doesn't exist - {0}", path);
58 return;
61 highlight_text = highlight;
62 search_text = search;
64 ShowWindow ();
68 private void SetStatusTitle (DateTime dt)
70 time_title.Markup = String.Format ("<b>{0}</b>", StringFu.DateTimeToPrettyString (dt));
73 private void SetWindowTitle (string speaker)
75 if (speaker == null || speaker == "")
76 return;
78 // Find the buddy
79 ImBuddy buddy = null;
81 if (client == "gaim")
82 buddy = new GaimBuddyListReader ().Search (speaker);
83 else if (client == "kopete")
84 buddy = new KopeteBuddyListReader ().Search (speaker);
86 if (speaker.EndsWith (".chat")) {
87 imviewer.Title = String.Format (Catalog.GetString ("Conversations in {0}"), speaker.Replace (".chat", ""));
88 } else {
89 string nick = speaker;
91 if (buddy != null && buddy.Alias != "")
92 nick = buddy.Alias;
94 imviewer.Title = String.Format (Catalog.GetString ("Conversations with {0}"), nick);
97 speaking_to = speaker;
100 private void ShowWindow ()
102 Application.Init();
104 Glade.XML gxml = new Glade.XML (null, "ImLogViewer.glade", "imviewer", null);
105 gxml.Autoconnect (this);
107 conversation.PixelsAboveLines = 3;
108 conversation.LeftMargin = 4;
109 conversation.RightMargin = 4;
111 TextTag boldtag = new TextTag ("bold");
112 boldtag.Weight = Pango.Weight.Bold;
113 conversation.Buffer.TagTable.Add (boldtag);
115 TextTag highlight = new TextTag ("highlight");
116 highlight.Background = "yellow";
117 conversation.Buffer.TagTable.Add (highlight);
119 tree_store = new TreeStore (new Type[] {typeof (string), typeof (string), typeof (object)});
121 timelinetree.Model = tree_store;
122 timelinetree.AppendColumn ("Date", new CellRendererText(), "markup", 0);
123 timelinetree.AppendColumn ("Snippet", new CellRendererText(), "text", 1);
124 timelinetree.Selection.Changed += OnConversationSelected;
126 if (highlight_text != null)
127 search_entry.Text = highlight_text;
129 if (search_text != null)
130 Search (search_text);
132 search_entry.Activated += OnSearchClicked;
133 search_button.Clicked += OnSearchClicked;
134 clear_button.Clicked += OnClearClicked;
135 imviewer.DeleteEvent += new DeleteEventHandler (OnWindowDelete);
137 AccelGroup accel_group = new AccelGroup ();
138 GlobalKeybinder global_keys = new GlobalKeybinder (accel_group);
139 global_keys.AddAccelerator (OnWindowClose, (uint) Gdk.Key.Escape, 0, Gtk.AccelFlags.Visible);
140 imviewer.AddAccelGroup (accel_group);
142 // Index the logs
143 index_thread_notify = new ThreadNotify (new ReadyEvent (RepopulateTimeline));
144 Thread t = new Thread (new ThreadStart (IndexLogs));
145 t.Start ();
147 Application.Run();
150 private void IndexLogs ()
152 foreach (string file in Directory.GetFiles (log_path)) {
153 ICollection logs = null;
155 if (client == "gaim")
156 logs = GaimLog.ScanLog (new FileInfo (file));
157 else if (client == "kopete")
158 logs = KopeteLog.ScanLog (new FileInfo (file));
160 if (logs == null)
161 continue;
163 foreach (ImLog log in logs) {
164 if (speaking_to == null)
165 SetWindowTitle (log.SpeakingTo);
167 timeline.Add (log, log.StartTime);
171 index_thread_notify.WakeupMain ();
174 private bool LogContainsString (ImLog log, string text)
176 string [] words = text.Split (null);
178 //FIXME: This is very crude and EXPENSIVE!
179 foreach (string word in words) {
180 bool match = false;
182 foreach (ImLog.Utterance utt in log.Utterances) {
183 if (utt.Text.ToLower ().IndexOf (word.ToLower ()) != -1) {
184 match = true;
185 break;
189 if (!match) return false;
192 return true;
195 private class ImLogPreview
197 public string Snippet;
198 public ImLog Log;
200 public ImLogPreview (ImLog log)
202 Snippet = log.EllipsizedSnippet;
203 Log = log;
207 private void AddCategory (ArrayList list, string name, string date_format)
209 if (list.Count > 0) {
210 ArrayList previews = GetPreviews (list);
211 if (previews.Count > 0) {
212 TreeIter parent = tree_store.AppendValues (String.Format ("<b>{0}</b>", Catalog.GetString (name)), "", null);
213 AddPreviews (parent, previews, Catalog.GetString (date_format));
218 private void RepopulateTimeline ()
220 tree_store.Clear ();
222 AddCategory (timeline.Today, "Today", "HH:mm");
223 AddCategory (timeline.Yesterday, "Yesterday", "HH:mm");
224 AddCategory (timeline.ThisWeek, "This Week", "dddd");
225 AddCategory (timeline.LastWeek, "Last Week", "dddd");
226 AddCategory (timeline.ThisMonth, "This Month", "MMM d");
227 AddCategory (timeline.ThisYear, "This Year", "MMM d");
228 AddCategory (timeline.Older, "Older", "yyy MMM d");
230 timelinetree.ExpandAll();
233 private void AddPreviews (TreeIter parent, ArrayList previews, string date_format)
235 foreach (ImLogPreview preview in previews) {
236 string date = preview.Log.StartTime.ToString (date_format);
237 tree_store.AppendValues (parent, date, preview.Snippet, preview.Log);
239 if (selected_log == null || selected_log == preview.Log.LogFile) {
240 selected_log = preview.Log.LogFile;
241 RenderConversation (preview.Log);
242 ScrollToLog (preview.Log.LogFile);
247 private ArrayList GetPreviews (ArrayList list)
249 ArrayList logs = new ArrayList ();
251 foreach (ImLog log in list) {
252 if (search_text != null && search_text != "")
253 if (! LogContainsString (log, search_text))
254 continue;
256 ImLogPreview preview = new ImLogPreview (log);
257 logs.Add (preview);
260 return logs;
263 private void RenderConversation (ImLog im_log)
265 TextBuffer buffer = conversation.Buffer;
266 buffer.Delete (buffer.StartIter, buffer.EndIter);
268 if (im_log == null) {
269 //SetStatusTitle (new DateTime ());
270 return;
273 SetStatusTitle (im_log.StartTime);
275 TextTag bold = buffer.TagTable.Lookup ("bold");
277 foreach (ImLog.Utterance utt in im_log.Utterances) {
278 buffer.InsertWithTags (buffer.EndIter, utt.Who + ":", new TextTag[] {bold});
279 buffer.Insert (buffer.EndIter, String.Format(" {0}\n", utt.Text));
282 if (highlight_text != null)
283 HighlightSearchTerms (highlight_text);
285 if (search_text != null && search_text != "")
286 HighlightSearchTerms (search_text);
289 private void HighlightSearchTerms (string highlight)
291 TextBuffer buffer = conversation.Buffer;
292 string text = buffer.GetText (buffer.StartIter, buffer.EndIter, false).ToLower ();
293 string [] words = highlight.Split (' ');
295 foreach (string word in words) {
296 int idx = 0;
298 if (word == String.Empty)
299 continue;
301 while ((idx = text.IndexOf (word.ToLower (), idx)) != -1) {
302 Gtk.TextIter start = buffer.GetIterAtOffset (idx);
303 Gtk.TextIter end = start;
304 end.ForwardChars (word.Length);
306 buffer.ApplyTag ("highlight", start, end);
308 idx += word.Length;
313 private void Search (string text)
315 search_entry.Text = text;
316 search_button.Visible = false;
317 clear_button.Visible = true;
318 search_entry.Sensitive = false;
320 search_text = text;
321 highlight_text = null;
322 selected_log = null;
325 private void OnConversationSelected (object o, EventArgs args)
327 TreeIter iter;
328 TreeModel model;
330 if (((TreeSelection)o).GetSelected (out model, out iter)) {
331 ImLog log = model.GetValue (iter, 2) as ImLog;
333 if (log == null)
334 return;
336 selected_log = log.LogFile;
337 RenderConversation (log);
341 private void OnWindowClose (object o, EventArgs args)
343 Application.Quit ();
346 private void OnWindowDelete (object o, DeleteEventArgs args)
348 Application.Quit ();
351 private void OnSearchClicked (object o, EventArgs args)
353 if (search_entry.Text == null || search_entry.Text == "")
354 return;
356 Search (search_entry.Text);
357 RepopulateTimeline ();
360 private void ScrollToLog (string scroll_log)
362 TreeIter root_iter;
363 tree_store.GetIterFirst (out root_iter);
365 do {
366 if (tree_store.IterHasChild (root_iter)) {
367 TreeIter child;
368 tree_store.IterNthChild (out child, root_iter, 0);
370 do {
371 ImLog log = tree_store.GetValue (child, 2) as ImLog;
373 if (log.LogFile == scroll_log) {
374 TreePath path = tree_store.GetPath (child);
375 timelinetree.ExpandToPath (path);
376 timelinetree.Selection.SelectPath (path);
377 timelinetree.ScrollToCell (path, null, true, 0.5f, 0.0f);
378 return;
380 } while (tree_store.IterNext (ref child));
382 } while (tree_store.IterNext (ref root_iter));
385 private void OnClearClicked (object o, EventArgs args)
387 highlight_text = search_text = null;
388 search_button.Visible = true;
389 clear_button.Visible = false;
390 search_entry.Sensitive = true;
392 RepopulateTimeline ();
394 ScrollToLog (selected_log);