diff --git a/SparkleShare/Windows/SparkleEventLogWindow.xaml b/SparkleShare/Windows/SparkleEventLogWindow.xaml
new file mode 100644
index 00000000..57ba9c7e
--- /dev/null
+++ b/SparkleShare/Windows/SparkleEventLogWindow.xaml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SparkleShare/Windows/SparkleEventLogWindow.xaml.cs b/SparkleShare/Windows/SparkleEventLogWindow.xaml.cs
new file mode 100644
index 00000000..f690aedc
--- /dev/null
+++ b/SparkleShare/Windows/SparkleEventLogWindow.xaml.cs
@@ -0,0 +1,248 @@
+using System.Windows;
+
+namespace SparkleShare
+{
+ using System;
+ using System.ComponentModel;
+ using System.IO;
+ using System.Runtime.InteropServices;
+ using System.Windows.Controls;
+ using System.Windows.Media;
+ using System.Windows.Media.Imaging;
+
+ using Microsoft.Win32;
+
+ ///
+ /// Logics for the recent-changes-window.
+ ///
+ public partial class SparkleEventLogWindow : Window
+ {
+ public SparkleEventLogController Controller = new SparkleEventLogController ();
+
+ [DllImport("urlmon.dll")]
+ [PreserveSig]
+ [return: MarshalAs(UnmanagedType.Error)]
+ static extern int CoInternetSetFeatureEnabled(int feature, [MarshalAs(UnmanagedType.U4)] int flags, bool enable);
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SparkleEventLogWindow ()
+ {
+ this.InitializeComponent ();
+
+ // Hide the minimize and maximize buttons.
+ this.SourceInitialized += (sender, args) => this.HideMinimizeAndMaximizeButtons();
+ // Set some window-properties from code.
+ this.Background = new SolidColorBrush (Color.FromRgb(240, 240, 240));
+ this.AllowsTransparency = false;
+ this.Icon = SparkleUIHelpers.GetImageSource ("sparkleshare-app", "ico");
+ this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
+
+ // Write images to temp-folder.
+ this.WriteOutImages ();
+
+ // Set values from controller to ui.
+ this.label_Size.Content = "Size: " + Controller.Size;
+ this.label_History.Content = "History: " + Controller.HistorySize;
+
+ this.webbrowser.ObjectForScripting = new SparkleScriptingObject ();
+ // Disable annoying IE clicking sound
+ CoInternetSetFeatureEnabled (21, 0x00000002, true);
+
+ // Tell controller on closing event.
+ this.Closing += this.OnClosing;
+
+ // Show the window on controllers request.
+ this.Controller.ShowWindowEvent += () => this.Dispatcher.BeginInvoke (
+ (Action)(() => {
+ this.Show ();
+ this.Activate ();
+ this.BringIntoView ();
+ }));
+
+ // Hide the window on controllers request.
+ // Also hide the webbrowser-element and show the spinner.
+ this.Controller.HideWindowEvent += () => this.Dispatcher.BeginInvoke (
+ (Action)(() => {
+ this.Hide ();
+ this.spinner.Visibility = Visibility.Visible;
+ this.webbrowser.Visibility = Visibility.Collapsed;
+ }));
+
+ // Update labels on controllers request.
+ this.Controller.UpdateSizeInfoEvent += (size, history_size) => this.Dispatcher.BeginInvoke (
+ (Action)(() => {
+ this.label_Size.Content = "Size: " + size;
+ this.label_History.Content = "History: " + history_size;
+ }));
+
+ // Update the combobox-elements.
+ this.Controller.UpdateChooserEvent += folders => this.Dispatcher.BeginInvoke (
+ (Action)(() => this.UpdateChooser (folders)));
+
+ // Update the enabled-state of the combobox.
+ this.Controller.UpdateChooserEnablementEvent += enabled => this.Dispatcher.BeginInvoke (
+ (Action)(() => this.combobox.IsEnabled = enabled));
+
+ // Update the content of the webbrowser.
+ this.Controller.UpdateContentEvent += html => this.Dispatcher.BeginInvoke ((Action)(() => {
+ this.UpdateContent (html);
+
+ this.spinner.Visibility = Visibility.Collapsed;
+ this.webbrowser.Visibility = Visibility.Visible;
+ }));
+
+ // Show the spinner if the content is loading.
+ this.Controller.ContentLoadingEvent += () => this.Dispatcher.BeginInvoke (
+ (Action)(() => {
+ this.spinner.Visibility = Visibility.Visible;
+ this.spinner.Start ();
+ this.webbrowser.Visibility = Visibility.Collapsed;
+ }));
+
+ // Show the save-file-dialog on controllers request.
+ this.Controller.ShowSaveDialogEvent +=
+ (file_name, target_folder_path) => this.Dispatcher.BeginInvoke (
+ (Action)(() => {
+ SaveFileDialog dialog = new SaveFileDialog ()
+ {
+ FileName = file_name,
+ InitialDirectory = target_folder_path,
+ Title = "Restore from History",
+ DefaultExt = "." + Path.GetExtension (file_name),
+ Filter = "All Files|*.*"
+ };
+
+ bool? result = dialog.ShowDialog (this);
+
+ if (result == true) this.Controller.SaveDialogCompleted (dialog.FileName);
+ else this.Controller.SaveDialogCancelled ();
+ }));
+ }
+
+ ///
+ /// Called when [closing].
+ /// Suppress the closing and asks controller to hide this window.
+ ///
+ /// The sender.
+ /// The instance containing the event data.
+ private void OnClosing (object sender, CancelEventArgs cancel_event_args)
+ {
+ this.Controller.WindowClosed ();
+ cancel_event_args.Cancel = true;
+ }
+
+ ///
+ /// Updates the content of the webbrowser.
+ ///
+ /// The HTML.
+ private void UpdateContent (string html)
+ {
+ string pixmaps_path = Path.Combine (SparkleLib.SparkleConfig.DefaultConfig.TmpPath, "Pixmaps");
+ pixmaps_path = pixmaps_path.Replace ("\\", "/");
+
+ html = html.Replace("", "'Segoe UI', sans-serif");
+ html = html.Replace("", "13px");
+ html = html.Replace("", "12px");
+ html = html.Replace("", "#bbb");
+ html = html.Replace("", "#ddd");
+ html = html.Replace("", "90%");
+ html = html.Replace("", "#f5f5f5");
+ html = html.Replace("", "#0085cf");
+ html = html.Replace("", "#009ff8");
+ html = html.Replace("", pixmaps_path);
+ html = html.Replace("", pixmaps_path + "/document-added-12.png");
+ html = html.Replace("", pixmaps_path + "/document-edited-12.png");
+ html = html.Replace("", pixmaps_path + "/document-deleted-12.png");
+ html = html.Replace("", pixmaps_path + "/document-moved-12.png");
+
+ this.spinner.Stop();
+
+ this.webbrowser.ObjectForScripting = new SparkleScriptingObject ();
+ this.webbrowser.NavigateToString (html);
+ }
+
+ ///
+ /// Updates the combobox-items.
+ ///
+ /// The folders.
+ public void UpdateChooser (string [] folders)
+ {
+ if (folders == null) {
+ folders = Controller.Folders;
+ }
+
+ this.combobox.Items.Clear ();
+ this.combobox.Items.Add (new ComboBoxItem () { Content = "Summary" });
+ this.combobox.Items.Add(new Separator());
+ this.combobox.SelectedItem = combobox.Items[0];
+
+ int row = 2;
+ foreach (string folder in folders)
+ {
+ this.combobox.Items.Add(new ComboBoxItem() { Content = folder } );
+
+ if (folder.Equals (Controller.SelectedFolder)) {
+ this.combobox.SelectedItem = this.combobox.Items [row];
+ }
+
+ row++;
+ }
+
+ this.combobox.SelectionChanged += delegate {
+ Dispatcher.BeginInvoke((Action)delegate {
+ int index = this.combobox.SelectedIndex;
+
+ if (index == 0) {
+ Controller.SelectedFolder = null;
+ } else {
+ Controller.SelectedFolder = (string)((ComboBoxItem)this.combobox.Items[index]).Content;
+ }
+ });
+ };
+ }
+
+ ///
+ /// Writes the images from the pixel-map to the temp-folder.
+ ///
+ private void WriteOutImages ()
+ {
+ string tmp_path = SparkleLib.SparkleConfig.DefaultConfig.TmpPath;
+ string pixmaps_path = Path.Combine(tmp_path, "Pixmaps");
+
+ if (!Directory.Exists(pixmaps_path))
+ {
+ Directory.CreateDirectory(pixmaps_path);
+
+ File.SetAttributes(tmp_path, File.GetAttributes(tmp_path) | FileAttributes.Hidden);
+ }
+
+ BitmapSource image = SparkleUIHelpers.GetImageSource("user-icon-default");
+ string file_path = Path.Combine(pixmaps_path, "user-icon-default.png");
+
+ using (FileStream stream = new FileStream(file_path, FileMode.Create))
+ {
+ BitmapEncoder encoder = new PngBitmapEncoder();
+ encoder.Frames.Add(BitmapFrame.Create(image));
+ encoder.Save(stream);
+ }
+
+ string[] actions = new string[] { "added", "deleted", "edited", "moved" };
+
+ foreach (string action in actions)
+ {
+ image = SparkleUIHelpers.GetImageSource("document-" + action + "-12");
+ file_path = Path.Combine(pixmaps_path, "document-" + action + "-12.png");
+
+ using (FileStream stream = new FileStream(file_path, FileMode.Create))
+ {
+ BitmapEncoder encoder = new PngBitmapEncoder();
+ encoder.Frames.Add(BitmapFrame.Create(image));
+ encoder.Save(stream);
+ }
+ }
+ }
+ }
+}
diff --git a/SparkleShare/Windows/SparkleScriptingObject.cs b/SparkleShare/Windows/SparkleScriptingObject.cs
new file mode 100644
index 00000000..171ee087
--- /dev/null
+++ b/SparkleShare/Windows/SparkleScriptingObject.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using System.Runtime.InteropServices;
+using System.Security.Permissions;
+
+namespace SparkleShare
+{
+ [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
+ [ComVisible(true)]
+ public class SparkleScriptingObject
+ {
+ public void LinkClicked(string url)
+ {
+ Program.UI.EventLog.Controller.LinkClicked(url);
+ }
+ }
+}
diff --git a/SparkleShare/Windows/SparkleShare.csproj b/SparkleShare/Windows/SparkleShare.csproj
index 15b97abf..5b437b41 100644
--- a/SparkleShare/Windows/SparkleShare.csproj
+++ b/SparkleShare/Windows/SparkleShare.csproj
@@ -76,6 +76,10 @@
SparkleStatusIconController.cs
+
+ SparkleEventLogWindow.xaml
+
+
@@ -83,7 +87,6 @@
-
@@ -99,6 +102,7 @@
+
@@ -152,6 +156,7 @@
HTML\event-log.html
+ Designer
HTML\jquery.js
@@ -259,4 +264,10 @@
-
+
+
+ Designer
+ MSBuild:Compile
+
+
+
\ No newline at end of file
diff --git a/SparkleShare/Windows/SparkleSpinner.cs b/SparkleShare/Windows/SparkleSpinner.cs
index 450af909..e8a38856 100644
--- a/SparkleShare/Windows/SparkleSpinner.cs
+++ b/SparkleShare/Windows/SparkleSpinner.cs
@@ -20,16 +20,22 @@ using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
+using System.ComponentModel;
namespace SparkleShare {
-
public class SparkleSpinner : Image {
private Timer timer;
+ public SparkleSpinner ()
+ : this (22) {
+ }
- public SparkleSpinner (int size) : base ()
- {
+ public SparkleSpinner (int size) : base () {
+ if (DesignerProperties.GetIsInDesignMode(this)) {
+ return;
+ }
+
Width = size;
Height = size;
diff --git a/SparkleShare/Windows/SparkleUI.cs b/SparkleShare/Windows/SparkleUI.cs
index 1255a483..be3a5d74 100644
--- a/SparkleShare/Windows/SparkleUI.cs
+++ b/SparkleShare/Windows/SparkleUI.cs
@@ -23,7 +23,7 @@ namespace SparkleShare {
public class SparkleUI {
public SparkleSetup Setup;
- public SparkleEventLog EventLog;
+ public SparkleEventLogWindow EventLog;
public SparkleBubbles Bubbles;
public SparkleStatusIcon StatusIcon;
public SparkleAbout About;
@@ -35,7 +35,7 @@ namespace SparkleShare {
// don't have the smooth ease in animation, but appear abruptly.
// The ease out animation always seems to work
Setup = new SparkleSetup ();
- EventLog = new SparkleEventLog ();
+ EventLog = new SparkleEventLogWindow();
About = new SparkleAbout ();
Bubbles = new SparkleBubbles ();
StatusIcon = new SparkleStatusIcon ();
diff --git a/SparkleShare/Windows/WPFChromeExtensions.cs b/SparkleShare/Windows/WPFChromeExtensions.cs
new file mode 100644
index 00000000..175e7a7c
--- /dev/null
+++ b/SparkleShare/Windows/WPFChromeExtensions.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using System.Runtime.InteropServices;
+using System.Windows;
+
+namespace SparkleShare
+{
+ ///
+ /// Thanks to Matt Hamilton for this code!
+ /// See http://stackoverflow.com/questions/339620/how-do-i-remove-minimize-and-maximize-from-a-resizable-window-in-wpf
+ ///
+ internal static class WindowExtensions {
+ // from winuser.h
+ private const int GWL_STYLE = -16,
+ WS_MAXIMIZEBOX = 0x10000,
+ WS_MINIMIZEBOX = 0x20000;
+
+ [DllImport("user32.dll")]
+ extern private static int GetWindowLong (IntPtr hwnd, int index);
+
+ [DllImport("user32.dll")]
+ extern private static int SetWindowLong (IntPtr hwnd, int index, int value);
+
+ internal static void HideMinimizeAndMaximizeButtons (this Window window)
+ {
+ IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
+ var currentStyle = GetWindowLong (hwnd, GWL_STYLE);
+
+ SetWindowLong (hwnd, GWL_STYLE, (currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX));
+ }
+ }
+}