diff --git a/SparkleShare/SparkleRepo.cs b/SparkleShare/SparkleRepo.cs index c82d6c58..9f09d37c 100644 --- a/SparkleShare/SparkleRepo.cs +++ b/SparkleShare/SparkleRepo.cs @@ -411,7 +411,7 @@ namespace SparkleShare { if (FilesAdded > 1) return "added ‘" + Line.Replace ("#\tnew file:", "").Trim () + - "’ and " + (FilesAdded - 1) + " more."; + "’\nand " + (FilesAdded - 1) + " more."; else return "added ‘" + Line.Replace ("#\tnew file:", "").Trim () + "’."; @@ -424,7 +424,7 @@ namespace SparkleShare { if (FilesEdited > 1) return "edited ‘" + Line.Replace ("#\tmodified:", "").Trim () + - "’ and " + (FilesEdited - 1) + " more."; + "’\nand " + (FilesEdited - 1) + " more."; else return "edited ‘" + Line.Replace ("#\tmodified:", "").Trim () + "’."; @@ -437,7 +437,7 @@ namespace SparkleShare { if (FilesDeleted > 1) return "deleted ‘" + Line.Replace ("#\tdeleted:", "").Trim () + - "’ and " + (FilesDeleted - 1) + " more."; + "’\nand " + (FilesDeleted - 1) + " more."; else return "deleted ‘" + Line.Replace ("#\tdeleted:", "").Trim () + "’."; diff --git a/SparkleShare/SparkleWindow.cs b/SparkleShare/SparkleWindow.cs new file mode 100644 index 00000000..52b634c3 --- /dev/null +++ b/SparkleShare/SparkleWindow.cs @@ -0,0 +1,226 @@ +// SparkleShare, an instant update workflow to Git. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Gtk; +using Mono.Unix; +using SparkleShare; +using System; +using System.Diagnostics; +using System.IO; +using System.Text.RegularExpressions; +using System.Timers; + +namespace SparkleShare { + + public class SparkleWindow : Window + { + + // Short alias for the translations + public static string _ (string s) + { + return Catalog.GetString (s); + } + + private SparkleRepo SparkleRepo; + private VBox LayoutVertical; + private ScrolledWindow LogScrolledWindow; + private string SelectedEmail; + + public SparkleWindow (SparkleRepo Repo) : base ("") + { + + SparkleRepo = Repo; + SelectedEmail = ""; + SetSizeRequest (640, 480); + SetPosition (WindowPosition.Center); + BorderWidth = 12; + Title = String.Format(_("‘{0}’ on {1}"), SparkleRepo.Name, + SparkleRepo.RemoteOriginUrl.TrimEnd (("/" + SparkleRepo.Name + ".git").ToCharArray ())); + IconName = "folder"; + + LayoutVertical = new VBox (false, 12); + + LayoutVertical.PackStart (CreateEventLog (), true, true, 0); + + HButtonBox DialogButtons = new HButtonBox (); + DialogButtons.Layout = ButtonBoxStyle.Edge; + DialogButtons.BorderWidth = 0; + + Button OpenFolderButton = new Button (_("Open Folder")); + OpenFolderButton.Clicked += delegate (object o, EventArgs args) { + Process Process = new Process (); + Process.StartInfo.FileName = "xdg-open"; + Process.StartInfo.Arguments = + SparkleHelpers.CombineMore (SparklePaths.SparklePath, SparkleRepo.Name); + Process.Start (); + Destroy (); + }; + + Button CloseButton = new Button (Stock.Close); + CloseButton.Clicked += delegate (object o, EventArgs args) { + Destroy (); + }; + + DialogButtons.Add (OpenFolderButton); + DialogButtons.Add (CloseButton); + + LayoutVertical.PackStart (DialogButtons, false, false, 0); + + Add (LayoutVertical); + + } + + + public void UpdateEventLog () + { + + LayoutVertical.Remove (LogScrolledWindow); + LogScrolledWindow = CreateEventLog (); + LayoutVertical.PackStart (LogScrolledWindow, true, true, 0); + ShowAll (); + + } + + + public ScrolledWindow CreateEventLog () + { + + ListStore LogStore = new ListStore (typeof (Gdk.Pixbuf), + typeof (string), + typeof (string), + typeof (string)); + + Process Process = new Process (); + Process.EnableRaisingEvents = true; + Process.StartInfo.RedirectStandardOutput = true; + Process.StartInfo.UseShellExecute = false; + Process.StartInfo.FileName = "git"; + + string Output = ""; + + Process.StartInfo.WorkingDirectory = SparkleRepo.LocalPath; + // We're using the snowman here to separate messages :) + Process.StartInfo.Arguments = "log --format=\"%at☃%s☃%an☃%cr☃%ae\" -25"; + Process.Start (); + + Output += "\n" + Process.StandardOutput.ReadToEnd ().Trim (); + + Output = Output.TrimStart ("\n".ToCharArray ()); + string [] Lines = Regex.Split (Output, "\n"); + + // Sort by time and get the last 25 + Array.Sort (Lines); + Array.Reverse (Lines); + + TreeIter Iter; + for (int i = 0; i < 25 && i < Lines.Length; i++) { + + string Line = Lines [i]; + if (Line.Contains (SelectedEmail)) { + + // Look for the snowman! + string [] Parts = Regex.Split (Line, "☃"); + string Message = Parts [1].Replace ("\n", " ");; + string UserName = Parts [2]; + string TimeAgo = Parts [3]; + string UserEmail = Parts [4]; + + Iter = LogStore.Append (); + + LogStore.SetValue (Iter, 0, SparkleHelpers.GetAvatar (UserEmail, 24)); + + if (SparkleRepo.UserEmail.Equals (UserEmail)) + LogStore.SetValue (Iter, 1, "You\n" + Message.Replace ("/", " → ")); + else + LogStore.SetValue (Iter, 1, "" + UserName + "\n" + Message.Replace ("/", " → ")); + + LogStore.SetValue (Iter, 2, TimeAgo + " "); + + // We're not showing email, it's only + // there for lookup purposes + LogStore.SetValue (Iter, 3, UserEmail); + + } + + } + + TreeView LogView = new TreeView (LogStore); + LogView.HeadersVisible = false; + + CellRendererText TextCellRight = new Gtk.CellRendererText (); + TextCellRight.Xalign = 1; + + LogView.AppendColumn ("", new Gtk.CellRendererPixbuf (), "pixbuf", 0); + + CellRendererText CellRendererMarkup = new CellRendererText (); + TreeViewColumn ColumnMarkup = new TreeViewColumn (); + ColumnMarkup.PackStart (CellRendererMarkup, true); + LogView.AppendColumn (ColumnMarkup); + + ColumnMarkup.SetCellDataFunc (CellRendererMarkup, new Gtk.TreeCellDataFunc (RenderRow)); + + LogView.AppendColumn (ColumnMarkup); + LogView.AppendColumn ("", TextCellRight, "text", 2); + + TreeViewColumn [] Columns = LogView.Columns; + Columns [0].MinWidth = 42; + Columns [1].Expand = true; + Columns [2].Expand = true; + Columns [1].MinWidth = 350; + Columns [2].MinWidth = 50; + + Columns [2].Spacing = 200; + LogView.CursorChanged += delegate (object o, EventArgs args) { + TreeModel Model; + if (LogView.Selection.GetSelected (out Model, out Iter)) { + SelectedEmail = (string) Model.GetValue (Iter, 3); + } + }; + + // Compose an e-mail when a row is activated + LogView.RowActivated += + delegate (object o, RowActivatedArgs Args) { + switch (SparklePlatform.Name) { + case "GNOME": + Process.StartInfo.FileName = "xdg-open"; + break; + case "OSX": + Process.StartInfo.FileName = "open"; + break; + } + Process.StartInfo.Arguments = "mailto:" + SelectedEmail; + Process.Start (); + }; + + LogScrolledWindow = new ScrolledWindow (); + LogScrolledWindow.AddWithViewport (LogView); + + return LogScrolledWindow; + + } + + // Renders a row with custom markup + private void RenderRow (TreeViewColumn Column, CellRenderer Cell, TreeModel Model, TreeIter Iter) + { + + string Item = (string) Model.GetValue (Iter, 1); + (Cell as CellRendererText).Markup = Item; + + } + + } + +}