This commit is contained in:
Hylke Bons 2014-05-08 21:25:51 -07:00
commit 7dbd7c9a86
7 changed files with 365 additions and 7 deletions

View file

@ -0,0 +1,38 @@
<Window x:Class="SparkleShare.SparkleEventLogWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:sparkleShare="clr-namespace:SparkleShare"
mc:Ignorable="d"
Height="640" SizeToContent="WidthAndHeight" Title="Recent Changes" MinHeight="640" MinWidth="490">
<Grid x:Name="grid_Base" Background="White">
<Border VerticalAlignment="Top" Height="35" Background="#FFF0F0F0" BorderBrush="#FFDFDFDF" BorderThickness="0,0,0,1">
<Grid>
<Label Content="Size: ?" Height="28" Name="label_Size" HorizontalAlignment="Left" Margin="20,0,0,0" FontWeight="Bold" />
<Label Content="History: ?" Height="28" Name="label_History" HorizontalAlignment="Left" Margin="100,0,0,0" FontWeight="Bold" />
<ComboBox HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,6,0" MinWidth="120" x:Name="combobox" />
</Grid>
</Border>
<Grid Margin="0, 35, 0, 0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<sparkleShare:SparkleSpinner x:Name="spinner" />
<WebBrowser x:Name="webbrowser" Height="{Binding ElementName=sizingControlHeight, Path=ActualHeight}" Width="{Binding ElementName=sizingControlWidth, Path=ActualWidth}" />
<!-- Unfortunatly WPF allways resizes from child to parent. Unfortunatley the webbrowser takes all space it gets -> stupid!
To correct this "feature" we use a dummy control in a different column to bind the height to.
Compare: http://stackoverflow.com/questions/7300975/prevent-parent-from-being-resized-by-child -->
<Rectangle Name="sizingControlHeight" Grid.Column="1" Visibility="Hidden" />
<Rectangle Name="sizingControlWidth" Grid.Column="0" Grid.Row="1" Visibility="Hidden" />
</Grid>
</Grid>
</Window>

View file

@ -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;
/// <summary>
/// Logics for the recent-changes-window.
/// </summary>
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);
/// <summary>
/// Initializes a new instance of the <see cref="SparkleEventLogWindow"/> class.
/// </summary>
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 ();
}));
}
/// <summary>
/// Called when [closing].
/// Suppress the closing and asks controller to hide this window.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="cancel_event_args">The <see cref="CancelEventArgs"/> instance containing the event data.</param>
private void OnClosing (object sender, CancelEventArgs cancel_event_args)
{
this.Controller.WindowClosed ();
cancel_event_args.Cancel = true;
}
/// <summary>
/// Updates the content of the webbrowser.
/// </summary>
/// <param name="html">The HTML.</param>
private void UpdateContent (string html)
{
string pixmaps_path = Path.Combine (SparkleLib.SparkleConfig.DefaultConfig.TmpPath, "Pixmaps");
pixmaps_path = pixmaps_path.Replace ("\\", "/");
html = html.Replace("<a href=", "<a class='windows' href=");
html = html.Replace("<!-- $body-font-family -->", "'Segoe UI', sans-serif");
html = html.Replace("<!-- $day-entry-header-font-size -->", "13px");
html = html.Replace("<!-- $body-font-size -->", "12px");
html = html.Replace("<!-- $secondary-font-color -->", "#bbb");
html = html.Replace("<!-- $small-color -->", "#ddd");
html = html.Replace("<!-- $small-font-size -->", "90%");
html = html.Replace("<!-- $day-entry-header-background-color -->", "#f5f5f5");
html = html.Replace("<!-- $a-color -->", "#0085cf");
html = html.Replace("<!-- $a-hover-color -->", "#009ff8");
html = html.Replace("<!-- $pixmaps-path -->", pixmaps_path);
html = html.Replace("<!-- $document-added-background-image -->", pixmaps_path + "/document-added-12.png");
html = html.Replace("<!-- $document-edited-background-image -->", pixmaps_path + "/document-edited-12.png");
html = html.Replace("<!-- $document-deleted-background-image -->", pixmaps_path + "/document-deleted-12.png");
html = html.Replace("<!-- $document-moved-background-image -->", pixmaps_path + "/document-moved-12.png");
this.spinner.Stop();
this.webbrowser.ObjectForScripting = new SparkleScriptingObject ();
this.webbrowser.NavigateToString (html);
}
/// <summary>
/// Updates the combobox-items.
/// </summary>
/// <param name="folders">The folders.</param>
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;
}
});
};
}
/// <summary>
/// Writes the images from the pixel-map to the temp-folder.
/// </summary>
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);
}
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -76,6 +76,10 @@
<Link>SparkleStatusIconController.cs</Link>
</Compile>
<Compile Include="..\SparkleSetupController.cs" />
<Compile Include="SparkleEventLogWindow.xaml.cs">
<DependentUpon>SparkleEventLogWindow.xaml</DependentUpon>
</Compile>
<Compile Include="SparkleScriptingObject.cs" />
<Compile Include="SparkleShortcut.cs" />
<Compile Include="SparkleUI.cs" />
<Compile Include="..\SparkleAboutController.cs" />
@ -83,7 +87,6 @@
<Compile Include="SparkleBubbles.cs" />
<Compile Include="SparkleAbout.cs" />
<Compile Include="SparkleController.cs" />
<Compile Include="SparkleEventLog.cs" />
<Compile Include="SparkleSetup.cs" />
<Compile Include="SparkleStatusIcon.cs" />
<Compile Include="SparkleUIHelpers.cs" />
@ -99,6 +102,7 @@
</Compile>
<Compile Include="SparkleNotifyIcon.cs" />
<Compile Include="SparkleSpinner.cs" />
<Compile Include="WPFChromeExtensions.cs" />
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>
@ -152,6 +156,7 @@
</EmbeddedResource>
<EmbeddedResource Include="..\Common\HTML\event-log.html">
<Link>HTML\event-log.html</Link>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="..\Common\HTML\jquery.js">
<Link>HTML\jquery.js</Link>
@ -259,4 +264,10 @@
<ItemGroup>
<Content Include="Pixmaps\sparkleshare-folder.ico" />
</ItemGroup>
</Project>
<ItemGroup>
<Page Include="SparkleEventLogWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
</Project>

View file

@ -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;

View file

@ -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 ();

View file

@ -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
{
/// <summary>
/// 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
/// </summary>
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));
}
}
}