Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into pr/n28_wolfbyte

Refactored documentparser to be static for better memory usage.
  • Loading branch information...
commit a087d1d53fe697ceaae4a6ebd62a504bc8deefc0 2 parents 2835525 + 88e0b38
@distantcam distantcam authored
Showing with 676 additions and 115 deletions.
  1. +0 −1  MarkPad.sln
  2. +6 −0 Test.markdown
  3. +59 −0 src/MarkPad.Services/Implementation/SettingsService.cs
  4. +11 −0 src/MarkPad.Services/Interfaces/ISettingsService.cs
  5. +7 −0 src/MarkPad.Services/MarkPad.Services.csproj
  6. +1 −0  src/MarkPad.Services/ServicesModule.cs
  7. +1 −0  src/MarkPad.Services/packages.config
  8. +7 −4 src/MarkPad/App.xaml
  9. +21 −1 src/MarkPad/App.xaml.cs
  10. +40 −28 src/MarkPad/AppBootstrapper.cs
  11. +19 −0 src/MarkPad/Constants.cs
  12. +13 −13 src/MarkPad/Document/DocumentView.xaml
  13. +3 −6 src/MarkPad/Document/DocumentViewModel.cs
  14. +27 −38 src/MarkPad/Document/ParsedDocument.cs
  15. +10 −0 src/MarkPad/Framework/Events/AppReadyEvent.cs
  16. +12 −0 src/MarkPad/Framework/Events/FileOpenEvent.cs
  17. +1 −2  src/MarkPad/Loader.cs
  18. +19 −1 src/MarkPad/MarkPad.csproj
  19. +89 −0 src/MarkPad/Settings/SettingsView.xaml
  20. +22 −0 src/MarkPad/Settings/SettingsView.xaml.cs
  21. +84 −0 src/MarkPad/Settings/SettingsViewModel.cs
  22. +128 −0 src/MarkPad/Shell/JumpListIntegration.cs
  23. +9 −8 src/MarkPad/Shell/ShellView.xaml
  24. +14 −0 src/MarkPad/Shell/ShellView.xaml.cs
  25. +38 −13 src/MarkPad/Shell/ShellViewModel.cs
  26. +35 −0 src/MarkPad/SingleInstanceManager.cs
  27. BIN  src/MarkPad/markpaddoc.ico
View
1  MarkPad.sln
@@ -14,7 +14,6 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "misc", "misc", "{F95A6BBE-B8AE-4CCA-A0ED-949C14833B85}"
ProjectSection(SolutionItems) = preProject
tools\EmbedAssemblies.targets = tools\EmbedAssemblies.targets
- src\GlobalAssemblyInfo.cs = src\GlobalAssemblyInfo.cs
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MarkPad.Services", "src\MarkPad.Services\MarkPad.Services.csproj", "{8088D80C-14AF-4618-B12A-F47C2771EBDD}"
View
6 Test.markdown
@@ -0,0 +1,6 @@
+---
+theme: ChaosSquirrel
+---
+#Test
+##La dee da
+###Foo
View
59 src/MarkPad.Services/Implementation/SettingsService.cs
@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+using System.IO;
+using MarkPad.Services.Interfaces;
+using Newtonsoft.Json;
+
+namespace MarkPad.Services.Implementation
+{
+ public class SettingsService : ISettingsService
+ {
+ private readonly string filePath;
+ private readonly Settings settings;
+
+ public SettingsService()
+ {
+ filePath = Path.Combine(Path.GetTempPath(), "settings.json");
+
+ if (File.Exists(filePath))
+ {
+ var contents = File.ReadAllText(filePath);
+ settings = JsonConvert.DeserializeObject<Settings>(contents);
+ }
+ else
+ {
+ settings = new Settings();
+ }
+ }
+
+ public IList<string> GetRecentFiles()
+ {
+ return settings.RecentFiles;
+ }
+
+ public void UpdateRecentFiles(IList<string> files)
+ {
+ settings.RecentFiles = files;
+ }
+
+ public void AddRecentFile(string path)
+ {
+ settings.RecentFiles.Insert(0, path);
+ }
+
+ public void Save()
+ {
+ var contents = JsonConvert.SerializeObject(settings);
+ File.WriteAllText(filePath, contents);
+ }
+ }
+
+ internal class Settings
+ {
+ public Settings()
+ {
+ RecentFiles = new List<string>();
+ }
+
+ public IList<string> RecentFiles { get; set; }
+ }
+}
View
11 src/MarkPad.Services/Interfaces/ISettingsService.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace MarkPad.Services.Interfaces
+{
+ public interface ISettingsService
+ {
+ IList<string> GetRecentFiles();
+ void UpdateRecentFiles(IList<string> files);
+ void Save();
+ }
+}
View
7 src/MarkPad.Services/MarkPad.Services.csproj
@@ -41,6 +41,9 @@
<Reference Include="Autofac.Configuration">
<HintPath>..\..\packages\Autofac.2.5.2.830\lib\NET40\Autofac.Configuration.dll</HintPath>
</Reference>
+ <Reference Include="Newtonsoft.Json">
+ <HintPath>..\..\packages\Newtonsoft.Json.4.0.5\lib\net40\Newtonsoft.Json.dll</HintPath>
+ </Reference>
<Reference Include="Ookii.Dialogs.Wpf">
<HintPath>..\..\packages\Ookii.Dialogs.1.0\lib\net35\Ookii.Dialogs.Wpf.dll</HintPath>
</Reference>
@@ -48,6 +51,8 @@
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
+ <Reference Include="System.ServiceModel" />
+ <Reference Include="System.ServiceModel.Activation" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@@ -63,6 +68,8 @@
<Compile Include="Implementation\DialogMessageService.cs" />
<Compile Include="Implementation\DialogService.cs" />
<Compile Include="Interfaces\IDialogService.cs" />
+ <Compile Include="Interfaces\ISettingsService.cs" />
+ <Compile Include="Implementation\SettingsService.cs" />
<Compile Include="ServicesModule.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
View
1  src/MarkPad.Services/ServicesModule.cs
@@ -9,6 +9,7 @@ public class ServicesModule : Module
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DialogService>().As<IDialogService>();
+ builder.RegisterType<SettingsService>().As<ISettingsService>();
}
}
}
View
1  src/MarkPad.Services/packages.config
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Autofac" version="2.5.2.830" />
+ <package id="Newtonsoft.Json" version="4.0.5" />
<package id="Ookii.Dialogs" version="1.0" />
</packages>
View
11 src/MarkPad/App.xaml
@@ -5,13 +5,16 @@
xmlns:local="clr-namespace:MarkPad"
>
<Application.Resources>
- <ResourceDictionary>
- <ResourceDictionary.MergedDictionaries>
-
+ <!--<ResourceDictionary>
+ <ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:AppBootstrapper x:Key="bootstrapper" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
- </ResourceDictionary>
+ </ResourceDictionary>-->
</Application.Resources>
+
+ <JumpList.JumpList>
+ <JumpList ShowRecentCategory="True" />
+ </JumpList.JumpList>
</Application>
View
22 src/MarkPad/App.xaml.cs
@@ -1,10 +1,30 @@
-namespace MarkPad
+using System.IO;
+using System.Linq;
+using Autofac;
+using Caliburn.Micro;
+using MarkPad.Framework.Events;
+
+namespace MarkPad
{
public partial class App
{
+ private readonly AppBootstrapper bootstrapper;
+
public App()
{
InitializeComponent();
+
+ bootstrapper = new AppBootstrapper();
+ }
+
+ public void HandleArguments(string[] args)
+ {
+ if (args.Length == 1)
+ {
+ var filePath = args[0];
+ if (File.Exists(filePath) && Constants.DefaultExtensions.Contains(Path.GetExtension(filePath).ToLower()))
+ bootstrapper.Container.Resolve<IEventAggregator>().Publish(new FileOpenEvent(filePath));
+ }
}
}
}
View
68 src/MarkPad/AppBootstrapper.cs
@@ -1,23 +1,31 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
using System.Linq;
+using System.Reflection;
using Autofac;
using Caliburn.Micro;
using MarkPad.Framework;
+using MarkPad.Framework.Events;
+using MarkPad.Services;
using MarkPad.Shell;
using NLog;
using NLog.Config;
using NLog.Targets;
-using System.IO;
-using System.Reflection;
+using LogManager = NLog.LogManager;
namespace MarkPad
{
class AppBootstrapper : Bootstrapper<ShellViewModel>
{
+ private string initialFile;
private IContainer container;
+ private JumpListIntegration jumpList;
- private void SetupLogging()
+ public IContainer Container { get { return container; } }
+
+ private static void SetupLogging()
{
var debuggerTarget = new DebuggerTarget { Layout = "[${level:uppercase=true}] (${logger}) ${message}" };
@@ -25,7 +33,7 @@ private void SetupLogging()
config.AddTarget("debugger", debuggerTarget);
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, debuggerTarget));
- NLog.LogManager.Configuration = config;
+ LogManager.Configuration = config;
}
protected override void Configure()
@@ -39,23 +47,43 @@ protected override void Configure()
SetupCaliburnMicroDefaults(builder);
builder.RegisterModule<EventAggregationAutoSubscriptionModule>();
+ builder.RegisterModule<ServicesModule>();
- builder.RegisterModule<Services.ServicesModule>();
+ builder.RegisterType<JumpListIntegration>().SingleInstance();
container = builder.Build();
- //SetAwesomiumDefaults();
+ jumpList = container.Resolve<JumpListIntegration>();
}
protected override void PrepareApplication()
{
Application.Startup += OnStartup;
-#if (!DEBUG)
- Application.DispatcherUnhandledException += OnUnhandledException;
-#endif
+
+ if (!Debugger.IsAttached)
+ Application.DispatcherUnhandledException += OnUnhandledException;
+
Application.Exit += OnExit;
}
+ protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
+ {
+ base.OnStartup(sender, e);
+
+ SetAwesomiumDefaults();
+
+ container.Resolve<IEventAggregator>().Publish(new AppReadyEvent());
+
+ ((App)Application).HandleArguments(Environment.GetCommandLineArgs().Skip(1).ToArray());
+ }
+
+ protected override void OnExit(object sender, EventArgs e)
+ {
+ jumpList.Dispose();
+
+ base.OnExit(sender, e);
+ }
+
private void SetAwesomiumDefaults()
{
var c = new Awesomium.Core.WebCoreConfig
@@ -69,47 +97,31 @@ private void SetAwesomiumDefaults()
Awesomium.Core.WebCore.Initialize(c, true);
Awesomium.Core.WebCore.BaseDirectory = Path.Combine(
- Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
+ Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
"Themes"
);
}
- protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
- {
- base.OnStartup(sender, e);
- SetAwesomiumDefaults();
- }
-
private static void SetupCaliburnMicroDefaults(ContainerBuilder builder)
{
- // register view models
builder.RegisterAssemblyTypes(AssemblySource.Instance.ToArray())
- // must be a type with a name that ends with ViewModel
.Where(type => type.Name.EndsWith("ViewModel"))
- // registered as self
.AsSelf()
- // always create a new one
.InstancePerDependency();
- // register views
builder.RegisterAssemblyTypes(AssemblySource.Instance.ToArray())
- // must be a type with a name that ends with View
.Where(type => type.Name.EndsWith("View"))
- // registered as self
.AsSelf()
- // always create a new one
.InstancePerDependency();
- // register the single window manager for this container
builder.Register<IWindowManager>(c => new WindowManager()).InstancePerLifetimeScope();
- // register the single event aggregator for this container
builder.Register<IEventAggregator>(c => new EventAggregator()).InstancePerLifetimeScope();
}
protected override object GetInstance(Type service, string key)
{
object instance;
- if (string.IsNullOrWhiteSpace(key))
+ if (String.IsNullOrWhiteSpace(key))
{
if (container.TryResolve(service, out instance))
return instance;
@@ -119,7 +131,7 @@ protected override object GetInstance(Type service, string key)
if (container.TryResolveNamed(key, service, out instance))
return instance;
}
- throw new Exception(string.Format("Could not locate any instances of contract {0}.", key ?? service.Name));
+ throw new Exception(String.Format("Could not locate any instances of contract {0}.", key ?? service.Name));
}
protected override IEnumerable<object> GetAllInstances(Type service)
View
19 src/MarkPad/Constants.cs
@@ -0,0 +1,19 @@
+using System.Linq;
+
+namespace MarkPad
+{
+ public static class Constants
+ {
+ public static readonly string[] DefaultExtensions = new[] { ".md", ".markdown", ".mdown" };
+
+ public static string ExtensionFilter
+ {
+ get
+ {
+ var extWildcards = DefaultExtensions.Select(ext => "*" + ext).ToArray();
+
+ return "Markdown Files (" + string.Join(", ", extWildcards) + ")|" + string.Join(";", extWildcards);
+ }
+ }
+ }
+}
View
26 src/MarkPad/Document/DocumentView.xaml
@@ -479,13 +479,13 @@
<ControlTemplate TargetType="{x:Type avalonedit:TextArea}">
<DockPanel Focusable="False">
<ItemsControl DockPanel.Dock="Left"
- Focusable="False"
+ Focusable="False"
Margin="0,0,5,0"
FontSize="10"
FontFamily="Segoe UI"
Padding="10,0,0,0"
Background="#adDEDEDE"
- ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=LeftMargins}">
+ ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=LeftMargins}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
@@ -493,9 +493,9 @@
</ItemsControl.ItemsPanel>
</ItemsControl>
<ContentPresenter
- Panel.ZIndex="-1"
- Focusable="False"
- Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TextView}"/>
+ Panel.ZIndex="-1"
+ Focusable="False"
+ Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TextView}"/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
@@ -509,15 +509,15 @@
</Grid.ColumnDefinitions>
<avalonedit:TextEditor
- x:Name="Document"
- WordWrap="True"
+ x:Name="Document"
+ WordWrap="True"
ShowLineNumbers="True"
- Document="{Binding Document}"
- cal:Message.Attach="[Event TextChanged]=[Action Update]"
- Grid.Column="0"
- Margin="10,10,10,-5"
- VerticalAlignment="Stretch"
- HorizontalAlignment="Stretch" Padding="0,0,10,0">
+ Document="{Binding Document}"
+ cal:Message.Attach="[Event TextChanged]=[Action Update]"
+ Grid.Column="0"
+ Margin="10,10,10,-5"
+ VerticalAlignment="Stretch"
+ HorizontalAlignment="Stretch" Padding="0,0,10,0">
<avalonedit:TextEditor.Effect>
<DropShadowEffect BlurRadius="10" Color="Black" Opacity="0.25" Direction="270" />
</avalonedit:TextEditor.Effect>
View
9 src/MarkPad/Document/DocumentViewModel.cs
@@ -56,7 +56,7 @@ public bool Save()
if (string.IsNullOrEmpty(filename))
{
- var path = dialogService.GetFileSavePath("Choose a location to save the document.", "*.md", "Markdown Files (*.md)|*.md|All Files (*.*)|*.*");
+ var path = dialogService.GetFileSavePath("Choose a location to save the document.", "*.md", Constants.ExtensionFilter + "|All Files (*.*)|*.*");
if (string.IsNullOrEmpty(path))
return false;
@@ -77,10 +77,7 @@ public bool Save()
public string Render
{
- get
- {
- return new ParsedDocument(Document.Text).ToHtml();
- }
+ get { return DocumentParser.Parse(Document.Text); }
}
public bool HasChanges
@@ -131,7 +128,7 @@ public override void CanClose(System.Action<bool> callback)
public void Print()
{
var view = this.GetView() as DocumentView;
- if(view != null)
+ if (view != null)
{
view.wb.Print();
}
View
65 src/MarkPad/Document/ParsedDocument.cs
@@ -1,75 +1,64 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.Text.RegularExpressions;
using MarkdownSharp;
namespace MarkPad.Document
{
- class DocumentHeader
+ static class DocumentParser
{
- private readonly string _text;
+ private static Markdown MarkdownParser = new Markdown();
- public DocumentHeader(string text)
- {
- _text = text;
- }
-
- public bool TryGetValue(string key, out string value)
- {
- // TODO: Cache these?
- var match = Regex.Match(_text, "^" + key + ": (.*)$", RegexOptions.Multiline | RegexOptions.IgnoreCase);
-
- value = match.Success ? match.Result("$1").Trim() : String.Empty;
-
- return match.Success;
- }
- }
-
- class ParsedDocument
- {
- public DocumentHeader Header { get; private set; }
- public string Contents { get; private set; }
-
- public ParsedDocument(string source)
+ public static string Parse(string source)
{
const string delimiter = "---";
var components = source.Split(new[] { delimiter }, 2, StringSplitOptions.RemoveEmptyEntries);
+ string header;
+ string contents;
+
if (components.Length == 0)
{
- Header = new DocumentHeader("");
- Contents = "";
+ header = "";
+ contents = "";
}
else if (components.Length == 2)
{
- Header = new DocumentHeader(components[0]);
- Contents = components[1];
+ header = components[0];
+ contents = components[1];
}
else
{
- Header = new DocumentHeader("");
- Contents = components[0];
+ header = "";
+ contents = components[0];
}
+
+ return ToHtml(header, contents);
}
- public string ToHtml()
+ private static string ToHtml(string header, string contents)
{
- var markdown = new Markdown();
-
- var body = markdown.Transform(Contents);
+ var body = MarkdownParser.Transform(contents);
string themeName;
string head = "";
- if (Header.TryGetValue("theme", out themeName))
+ if (TryGetHeaderValue(header, "theme", out themeName))
head = String.Format(@"<link rel=""stylesheet"" type=""text/css"" href=""{0}/style.css"" />", themeName);
var document = String.Format("<html>\r\n<head>\r\n{0}\r\n</head>\r\n<body>\r\n{1}\r\n</body>\r\n</html>", head, body);
return document;
}
+
+ private static bool TryGetHeaderValue(string header, string key, out string value)
+ {
+ // TODO: Cache these?
+ var match = Regex.Match(header, "^" + key + "\\s*:\\s*(.*)$", RegexOptions.Multiline | RegexOptions.IgnoreCase);
+
+ value = match.Success ? match.Result("$1").Trim() : String.Empty;
+
+ return match.Success;
+ }
}
}
View
10 src/MarkPad/Framework/Events/AppReadyEvent.cs
@@ -0,0 +1,10 @@
+namespace MarkPad.Framework.Events
+{
+ /// <summary>
+ /// Event for components to subscribe to to execute code after the shell is visible
+ /// </summary>
+ public class AppReadyEvent
+ {
+
+ }
+}
View
12 src/MarkPad/Framework/Events/FileOpenEvent.cs
@@ -0,0 +1,12 @@
+namespace MarkPad.Framework.Events
+{
+ public class FileOpenEvent
+ {
+ public FileOpenEvent(string path)
+ {
+ Path = path;
+ }
+
+ public string Path { get; private set; }
+ }
+}
View
3  src/MarkPad/Loader.cs
@@ -14,8 +14,7 @@ internal class Loader
static readonly Dictionary<string, Assembly> Libraries = new Dictionary<string, Assembly>();
static readonly Dictionary<string, Assembly> ReflectionOnlyLibraries = new Dictionary<string, Assembly>();
- [STAThreadAttribute]
- public static void Main(string[] args)
+ public static void Start()
{
AppDomain.CurrentDomain.AssemblyResolve += FindAssembly;
View
20 src/MarkPad/MarkPad.csproj
@@ -70,6 +70,7 @@
<Reference Include="MarkdownSharp">
<HintPath>..\..\packages\MarkdownSharp.1.13.0.0\lib\35\MarkdownSharp.dll</HintPath>
</Reference>
+ <Reference Include="Microsoft.VisualBasic" />
<Reference Include="NLog">
<HintPath>..\..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll</HintPath>
</Reference>
@@ -79,6 +80,8 @@
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Data" />
+ <Reference Include="System.ServiceModel" />
+ <Reference Include="System.ServiceModel.Activation" />
<Reference Include="System.Windows.Interactivity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\MahApps.Metro.0.4.0.17\lib\net40\System.Windows.Interactivity.dll</HintPath>
</Reference>
@@ -95,6 +98,7 @@
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="SingleInstanceManager.cs" />
<Page Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -107,15 +111,23 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="AppBootstrapper.cs" />
+ <Compile Include="Framework\Events\AppReadyEvent.cs" />
+ <Compile Include="Constants.cs" />
+ <Compile Include="Settings\SettingsView.xaml.cs">
+ <DependentUpon>SettingsView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Settings\SettingsViewModel.cs" />
<Compile Include="Document\DocumentView.xaml.cs">
<DependentUpon>DocumentView.xaml</DependentUpon>
</Compile>
<Compile Include="Document\DocumentViewModel.cs" />
<Compile Include="Document\ParsedDocument.cs" />
+ <Compile Include="Framework\Events\FileOpenEvent.cs" />
<Compile Include="MDI\MDIView.xaml.cs">
<DependentUpon>MDIView.xaml</DependentUpon>
</Compile>
<Compile Include="MDI\MDIViewModel.cs" />
+ <Compile Include="Shell\JumpListIntegration.cs" />
<Compile Include="Shell\ShellViewModel.cs" />
</ItemGroup>
<ItemGroup>
@@ -159,6 +171,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
+ <Page Include="Settings\SettingsView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="Shell\ShellView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -201,7 +217,9 @@
<ItemGroup>
<Resource Include="markpad.ico" />
</ItemGroup>
- <ItemGroup />
+ <ItemGroup>
+ <Resource Include="markpaddoc.ico" />
+ </ItemGroup>
<ItemGroup>
<Content Include="Themes\ChaosSquirrel\style.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
View
89 src/MarkPad/Settings/SettingsView.xaml
@@ -0,0 +1,89 @@
+<Window
+ x:Class="MarkPad.Settings.SettingsView"
+ 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:i="http://schemas.microsoft.com/expression/2010/interactivity"
+ xmlns:Behaviours="clr-namespace:MahApps.Metro.Behaviours;assembly=MahApps.Metro"
+ MouseLeftButtonDown="DragMoveWindow"
+ WindowStartupLocation="CenterOwner"
+ mc:Ignorable="d"
+ Height="300"
+ Width="300"
+ ResizeMode="NoResize"
+>
+ <i:Interaction.Behaviors>
+ <Behaviours:BorderlessWindowBehavior/>
+ </i:Interaction.Behaviors>
+
+ <Window.Resources>
+ <ResourceDictionary>
+ <ResourceDictionary.MergedDictionaries>
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml" />
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.AnimatedSingleRowTabControl.xaml" />
+ </ResourceDictionary.MergedDictionaries>
+
+ <!--ACCENT COLORS-->
+ <Color x:Key="HighlightDarkColor">#FFbe0606</Color>
+ <Color x:Key="HighlightLightColor">#FFbe0606</Color>
+
+ <Color x:Key="AccentDarkColor">#FFbe0606</Color>
+
+ <!--80%-->
+ <Color x:Key="AccentColor">#CCbe0606</Color>
+ <!--60%-->
+ <Color x:Key="AccentColor2">#99ff3333</Color>
+ <!--40%-->
+ <Color x:Key="AccentColor3">#66ff3333</Color>
+ <!--20%-->
+ <Color x:Key="AccentColor4">#33ff3333</Color>
+
+ <LinearGradientBrush x:Key="BrandingBrush"
+ EndPoint="0,0.5"
+ StartPoint="1,0.5">
+ <GradientStop Color="{DynamicResource HighlightDarkColor}"
+ Offset="0" />
+ <GradientStop Color="Blue"
+ Offset="1" />
+ </LinearGradientBrush>
+
+ <SolidColorBrush x:Key="AccentColorBrush"
+ Color="{DynamicResource AccentColor}" />
+ </ResourceDictionary>
+ </Window.Resources>
+
+ <Window.Background>
+ <LinearGradientBrush MappingMode="Absolute" StartPoint="0,0" EndPoint="0,150">
+ <GradientStop Color="#FFDEDEDE"/>
+ <GradientStop Color="White" Offset="1"/>
+ </LinearGradientBrush>
+ </Window.Background>
+
+ <DockPanel>
+ <TextBlock TextWrapping="Wrap" VerticalAlignment="Top" d:LayoutOverrides="Width" FontWeight="Bold" FontSize="10.667" Margin="10,10,0,0"><Run Language="en-au" Text="SETTINGS"/></TextBlock>
+ <Grid DockPanel.Dock="Top">
+ <StackPanel HorizontalAlignment="Right" VerticalAlignment="Top" Margin="10" Orientation="Horizontal">
+ <Button x:Name="TryClose" Style="{DynamicResource ChromelessButtonStyle}" Content="r" FontFamily="Marlett" />
+ </StackPanel>
+ </Grid>
+
+ <Grid DockPanel.Dock="Bottom">
+ <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="10" Orientation="Horizontal">
+ <Button x:Name="Accept" Content="OK" />
+ <Button x:Name="Cancel" Content="Cancel" />
+ </StackPanel>
+ </Grid>
+
+ <StackPanel>
+ <TextBlock Text="Set Markpad as default for file extensions:" />
+ <CheckBox x:Name="FileMDBinding" Content=".md" />
+ <CheckBox x:Name="FileMDownBinding" Content=".mdown" />
+ <CheckBox x:Name="FileMarkdownBinding" Content=".markdown" />
+ </StackPanel>
+
+ </DockPanel>
+</Window>
View
22 src/MarkPad/Settings/SettingsView.xaml.cs
@@ -0,0 +1,22 @@
+using System.Windows;
+using System.Windows.Input;
+
+namespace MarkPad.Settings
+{
+ /// <summary>
+ /// Interaction logic for SettingsView.xaml
+ /// </summary>
+ public partial class SettingsView : Window
+ {
+ public SettingsView()
+ {
+ InitializeComponent();
+ }
+
+ private void DragMoveWindow(object sender, MouseButtonEventArgs e)
+ {
+ if (e.RightButton != MouseButtonState.Pressed && e.MiddleButton != MouseButtonState.Pressed)
+ DragMove();
+ }
+ }
+}
View
84 src/MarkPad/Settings/SettingsViewModel.cs
@@ -0,0 +1,84 @@
+using System.Linq;
+using System.Reflection;
+using Caliburn.Micro;
+using Microsoft.Win32;
+
+namespace MarkPad.Settings
+{
+ public class SettingsViewModel : Screen
+ {
+ private const string markpadKeyName = "markpad.md";
+
+ public SettingsViewModel()
+ {
+ using (RegistryKey key = Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Classes"))
+ {
+ FileMDBinding = key.GetSubKeyNames().Contains(Constants.DefaultExtensions[0]) &&
+ !string.IsNullOrEmpty(key.OpenSubKey(Constants.DefaultExtensions[0]).GetValue("").ToString());
+
+ FileMarkdownBinding = key.GetSubKeyNames().Contains(Constants.DefaultExtensions[1]) &&
+ !string.IsNullOrEmpty(key.OpenSubKey(Constants.DefaultExtensions[1]).GetValue("").ToString());
+
+ FileMDownBinding = key.GetSubKeyNames().Contains(Constants.DefaultExtensions[2]) &&
+ !string.IsNullOrEmpty(key.OpenSubKey(Constants.DefaultExtensions[2]).GetValue("").ToString());
+ }
+ }
+
+ public bool FileMDBinding { get; set; }
+ public bool FileMarkdownBinding { get; set; }
+ public bool FileMDownBinding { get; set; }
+
+ public void Accept()
+ {
+ UpdateExtensionRegistryKeys();
+
+ TryClose();
+ }
+
+ public void Cancel()
+ {
+ TryClose();
+ }
+
+ private void UpdateExtensionRegistryKeys()
+ {
+ string exePath = Assembly.GetEntryAssembly().Location;
+
+ using (RegistryKey key = Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Classes", true))
+ {
+ for (int i = 0; i < Constants.DefaultExtensions.Length; i++)
+ {
+ using (RegistryKey extensionKey = key.CreateSubKey(Constants.DefaultExtensions[i]))
+ {
+ if ((i == 0 && FileMDBinding) ||
+ (i == 1 && FileMarkdownBinding) ||
+ (i == 2 && FileMDownBinding))
+ extensionKey.SetValue("", markpadKeyName);
+ else
+ extensionKey.SetValue("", "");
+ }
+ }
+
+ using (RegistryKey markpadKey = key.CreateSubKey(markpadKeyName))
+ {
+ // Can't get this to work right now.
+ //using (RegistryKey defaultIconKey = markpadKey.CreateSubKey("DefaultIcon"))
+ //{
+ // defaultIconKey.SetValue("", exePath + ",1");
+ //}
+
+ using (RegistryKey shellKey = markpadKey.CreateSubKey("shell"))
+ {
+ using (RegistryKey openKey = shellKey.CreateSubKey("open"))
+ {
+ using (RegistryKey commandKey = openKey.CreateSubKey("command"))
+ {
+ commandKey.SetValue("", "\"" + exePath + "\" \"%1\"");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
View
128 src/MarkPad/Shell/JumpListIntegration.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using System.Windows;
+using System.Windows.Shell;
+using Caliburn.Micro;
+using MarkPad.Framework.Events;
+using MarkPad.Services.Interfaces;
+
+namespace MarkPad.Shell
+{
+ /// <summary>
+ /// Class for interacting with the Windows7 JumpList
+ /// </summary>
+ public class JumpListIntegration : IHandle<FileOpenEvent>, IHandle<AppReadyEvent>, IDisposable
+ {
+ private readonly ISettingsService settingsService;
+ private JumpList jumpList;
+
+ public JumpListIntegration(ISettingsService settingsService)
+ {
+ this.settingsService = settingsService;
+ }
+
+ public void Handle(FileOpenEvent message)
+ {
+ var x = new Thread(new ParameterizedThreadStart(delegate { OpenFileAsync(message.Path); }));
+ x.SetApartmentState(ApartmentState.STA);
+ x.Start();
+ }
+
+ public void OpenFileAsync(string openedFile)
+ {
+ var currentFiles = jumpList.JumpItems.OfType<JumpTask>().Select(t => t.Arguments);
+
+ if (currentFiles.Contains(openedFile))
+ {
+ // find file in list
+ var files = settingsService.GetRecentFiles();
+ var index = files.IndexOf(openedFile);
+ files.RemoveAt(index);
+ files.Insert(0, openedFile);
+ settingsService.UpdateRecentFiles(files);
+
+ jumpList.JumpItems.RemoveAt(index);
+ InsertFileFirst(openedFile);
+ }
+ else
+ {
+ // update settings
+ var files = settingsService.GetRecentFiles();
+ files.Insert(0, openedFile);
+ if (files.Count > 5) files.RemoveAt(5);
+ settingsService.UpdateRecentFiles(files);
+
+ InsertFileFirst(openedFile);
+ }
+ }
+
+ private void InsertFileFirst(string openedFile)
+ {
+ if (jumpList != null)
+ {
+ var item = CreateJumpListItem(openedFile);
+ jumpList.JumpItems.Insert(0, item);
+ jumpList.Apply();
+ }
+ }
+
+ public void Handle(AppReadyEvent message)
+ {
+ jumpList = GetJumpList();
+
+ var x = new Thread(new ParameterizedThreadStart(delegate { PopulateJumpList(settingsService.GetRecentFiles()); }));
+ x.SetApartmentState(ApartmentState.STA);
+ x.Start();
+ }
+
+ public void Dispose()
+ {
+ settingsService.Save();
+ }
+
+ private void PopulateJumpList(IEnumerable<string> recentFiles)
+ {
+ foreach (var file in recentFiles.Distinct())
+ {
+ if (!File.Exists(file)) continue;
+ var item = CreateJumpListItem(file);
+ jumpList.JumpItems.Add(item);
+ }
+
+ jumpList.Apply();
+ }
+
+ private static JumpItem CreateJumpListItem(string file)
+ {
+ var path = Assembly.GetEntryAssembly().CodeBase;
+ return new JumpTask
+ {
+ Arguments = file,
+ IconResourcePath = path,
+ ApplicationPath = path,
+ Title = new FileInfo(file).Name,
+ CustomCategory = "Recent Files"
+ };
+ }
+
+ private static JumpList GetJumpList()
+ {
+ // check for Windows7
+ var os = Environment.OSVersion.Version;
+ if (os.Major < 6) return null;
+ if (os.Minor < 1) return null;
+
+ var list = JumpList.GetJumpList(Application.Current);
+ if (list != null) return list;
+
+ list = new JumpList { ShowFrequentCategory = false, ShowRecentCategory = false };
+
+ JumpList.SetJumpList(Application.Current, list);
+ return list;
+ }
+ }
+}
View
17 src/MarkPad/Shell/ShellView.xaml
@@ -39,8 +39,8 @@
<Color x:Key="AccentColor4">#33ff3333</Color>
<LinearGradientBrush x:Key="BrandingBrush"
- EndPoint="0.001,0.5"
- StartPoint="1.002,0.5">
+ EndPoint="0,0.5"
+ StartPoint="1,0.5">
<GradientStop Color="{DynamicResource HighlightDarkColor}"
Offset="0" />
<GradientStop Color="Blue"
@@ -51,12 +51,12 @@
Color="{DynamicResource AccentColor}" />
</ResourceDictionary>
</Window.Resources>
- <Window.Background>
+ <Window.Background>
<LinearGradientBrush MappingMode="Absolute" StartPoint="0,0" EndPoint="0,150">
- <GradientStop Color="#FFDEDEDE"/>
- <GradientStop Color="White" Offset="1"/>
- </LinearGradientBrush>
- </Window.Background>
+ <GradientStop Color="#FFDEDEDE"/>
+ <GradientStop Color="White" Offset="1"/>
+ </LinearGradientBrush>
+ </Window.Background>
<DockPanel Margin="0px 0px 0px 10px">
<Grid DockPanel.Dock="Top">
<TextBlock TextWrapping="Wrap" VerticalAlignment="Top" d:LayoutOverrides="Width" FontWeight="Bold" FontSize="10.667" Margin="30,10,0,0"><Run Language="en-au" Text="MARKPAD"/></TextBlock>
@@ -69,9 +69,10 @@
<Button x:Name="PrintDocument" Content="PRINT" Style="{DynamicResource ChromelessButtonStyle}" FontSize="13.333" Margin="0,0,20,0" FontWeight="Bold" />
</StackPanel>
<StackPanel HorizontalAlignment="Right" VerticalAlignment="Top" Margin="10" Orientation="Horizontal">
+ <Button x:Name="ShowSettings" Content="SETTINGS" Style="{DynamicResource ChromelessButtonStyle}" FontSize="10.667" Margin="0,0,20,0" FontWeight="Bold" />
<Button Click="ButtonMinimiseOnClick" Style="{DynamicResource ChromelessButtonStyle}" Content="0" FontFamily="Marlett" />
<Button Click="ButtonMaxRestoreOnClick" x:Name="maxRestore" Style="{DynamicResource ChromelessButtonStyle}" Content="1" FontFamily="Marlett" />
- <Button x:Name="Exit" Style="{DynamicResource ChromelessButtonStyle}" Content="r" FontFamily="Marlett" />
+ <Button x:Name="TryClose" Style="{DynamicResource ChromelessButtonStyle}" Content="r" FontFamily="Marlett" />
</StackPanel>
<Rectangle HorizontalAlignment="Left" Stroke="Black" Width="10" StrokeThickness="0" Margin="0,10">
<Rectangle.Fill>
View
14 src/MarkPad/Shell/ShellView.xaml.cs
@@ -1,10 +1,19 @@
using System.Windows;
using System.Windows.Input;
+using Caliburn.Micro;
+using MarkPad.Framework.Events;
namespace MarkPad.Shell
{
public partial class ShellView
{
+ private readonly IEventAggregator eventAggregator;
+
+ public ShellView(IEventAggregator eventAggregator)
+ {
+ this.eventAggregator = eventAggregator;
+ }
+
private void DragMoveWindow(object sender, MouseButtonEventArgs e)
{
if (e.RightButton != MouseButtonState.Pressed && e.MiddleButton != MouseButtonState.Pressed)
@@ -29,5 +38,10 @@ private void ButtonMaxRestoreOnClick(object sender, RoutedEventArgs e)
WindowState = WindowState.Maximized;
}
}
+
+ internal void OpenFile(string path)
+ {
+ eventAggregator.Publish(new FileOpenEvent(path));
+ }
}
}
View
51 src/MarkPad/Shell/ShellViewModel.cs
@@ -1,23 +1,37 @@
using System;
using Caliburn.Micro;
using MarkPad.Document;
+using MarkPad.Framework.Events;
using MarkPad.MDI;
using MarkPad.Services.Interfaces;
+using MarkPad.Settings;
namespace MarkPad.Shell
{
- internal class ShellViewModel : Conductor<IScreen>
+ internal class ShellViewModel : Conductor<IScreen>, IHandle<FileOpenEvent>
{
+ private readonly IEventAggregator eventAggregator;
private readonly IDialogService dialogService;
+ private readonly IWindowManager windowService;
private readonly Func<DocumentViewModel> documentCreator;
+ private readonly Func<SettingsViewModel> settingsCreator;
- public ShellViewModel(IDialogService dialogService, MDIViewModel mdi, Func<DocumentViewModel> documentCreator)
+ public ShellViewModel(
+ IDialogService dialogService,
+ IWindowManager windowService,
+ IEventAggregator eventAggregator,
+ MDIViewModel mdi,
+ Func<DocumentViewModel> documentCreator,
+ Func<SettingsViewModel> settingsCreator)
{
+ this.eventAggregator = eventAggregator;
this.dialogService = dialogService;
- this.MDI = mdi;
+ this.windowService = windowService;
+ MDI = mdi;
this.documentCreator = documentCreator;
+ this.settingsCreator = settingsCreator;
- this.ActivateItem(mdi);
+ ActivateItem(mdi);
}
public override string DisplayName
@@ -28,11 +42,6 @@ public override string DisplayName
public MDIViewModel MDI { get; private set; }
- public void Exit()
- {
- this.TryClose();
- }
-
public void NewDocument()
{
MDI.Open(documentCreator());
@@ -49,18 +58,24 @@ public void NewJekyllDocument()
private static string CreateJekyllHeader()
{
- var permalink = "new-page.html";
- var title = "New Post";
- var description = "Some Description";
+ const string permalink = "new-page.html";
+ const string title = "New Post";
+ const string description = "Some Description";
var date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz");
return string.Format("---\r\nlayout: post\r\ntitle: {0}\r\npermalink: {1}\r\ndescription: {2}\r\ndate: {3}\r\ntags: \"some tags here\"\r\n---\r\n\r\n", title, permalink, description, date);
}
+
public void OpenDocument()
{
- var path = dialogService.GetFileOpenPath("Open a markdown document.", "Any File (*.*)|*.*");
+ var path = dialogService.GetFileOpenPath("Open a markdown document.", Constants.ExtensionFilter + "|Any File (*.*)|*.*");
if (string.IsNullOrEmpty(path))
return;
+ eventAggregator.Publish(new FileOpenEvent(path));
+ }
+
+ public void OpenDocument(string path)
+ {
var doc = documentCreator();
doc.Open(path);
MDI.Open(doc);
@@ -83,6 +98,16 @@ public void SaveAllDocuments()
}
}
+ public void Handle(FileOpenEvent message)
+ {
+ OpenDocument(message.Path);
+ }
+
+ public void ShowSettings()
+ {
+ windowService.ShowDialog(settingsCreator());
+ }
+
public void PrintDocument()
{
var doc = MDI.ActiveItem as DocumentViewModel;
View
35 src/MarkPad/SingleInstanceManager.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Linq;
+using System.Windows;
+using Microsoft.VisualBasic.ApplicationServices;
+using StartupEventArgs = Microsoft.VisualBasic.ApplicationServices.StartupEventArgs;
+
+namespace MarkPad
+{
+ public class SingleInstanceManager : WindowsFormsApplicationBase
+ {
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ var manager = new SingleInstanceManager();
+ manager.Run(args);
+ }
+
+ public SingleInstanceManager()
+ {
+ IsSingleInstance = true;
+ }
+
+ protected override bool OnStartup(StartupEventArgs eventArgs)
+ {
+ Loader.Start();
+ return false;
+ }
+
+ protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
+ {
+ base.OnStartupNextInstance(eventArgs);
+ ((App)Application.Current).HandleArguments(eventArgs.CommandLine.ToArray());
+ }
+ }
+}
View
BIN  src/MarkPad/markpaddoc.ico
Binary file not shown
Please sign in to comment.
Something went wrong with that request. Please try again.