Work on project panel, trees, added settings

This commit is contained in:
Tiberiu Chibici 2014-07-28 20:18:18 +03:00
parent 5e526fa48c
commit 1c4c7ccfb0
23 changed files with 932 additions and 133 deletions

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Xml.Serialization; using System.Xml.Serialization;
using RainmeterStudio.Storage;
namespace RainmeterStudio.Model namespace RainmeterStudio.Model
{ {
@ -170,9 +171,26 @@ namespace RainmeterStudio.Model
/// <summary> /// <summary>
/// Gets or sets the root node /// Gets or sets the root node
/// </summary> /// </summary>
[XmlElement("root")] [XmlIgnore]
public Tree<Reference> Root { get; set; } public Tree<Reference> Root { get; set; }
/// <summary>
/// Gets or sets the serializable root node
/// </summary>
/// <remarks>Warning: not efficient</remarks>
[XmlElement("root")]
public SerializableTree<Reference> SerializableRoot
{
get
{
return Root.AsSerializableTree();
}
set
{
Root = value.AsTree();
}
}
#endregion #endregion
#region Constructor #region Constructor

View File

@ -7,13 +7,11 @@ using System.Xml.Serialization;
namespace RainmeterStudio.Model namespace RainmeterStudio.Model
{ {
public class Tree<T> public class Tree<T> : IList<Tree<T>>
{ {
[XmlElement("data")]
public T Data { get; set; } public T Data { get; set; }
[XmlArray("children"), XmlArrayItem("child")] public ObservableCollection<Tree<T>> Children { get; private set; }
public ObservableCollection<Tree<T>> Children { get; set; }
public Tree() public Tree()
{ {
@ -150,5 +148,10 @@ namespace RainmeterStudio.Model
return hash; return hash;
} }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return Children.GetEnumerator();
}
} }
} }

View File

@ -25,12 +25,66 @@ namespace RainmeterStudio.Properties {
[global::System.Configuration.UserScopedSettingAttribute()] [global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Windows.Input.KeyGestureConverter asdf { [global::System.Configuration.DefaultSettingValueAttribute("Ctrl+Shift+N")]
[global::System.Configuration.SettingsManageabilityAttribute(global::System.Configuration.SettingsManageability.Roaming)]
public string ProjectCreateCommand_Shortcut {
get { get {
return ((global::System.Windows.Input.KeyGestureConverter)(this["asdf"])); return ((string)(this["ProjectCreateCommand_Shortcut"]));
} }
set { set {
this["asdf"] = value; this["ProjectCreateCommand_Shortcut"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("F5")]
[global::System.Configuration.SettingsManageabilityAttribute(global::System.Configuration.SettingsManageability.Roaming)]
public string ProjectPanel_RefreshCommand_Shortcut {
get {
return ((string)(this["ProjectPanel_RefreshCommand_Shortcut"]));
}
set {
this["ProjectPanel_RefreshCommand_Shortcut"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Ctrl+N")]
[global::System.Configuration.SettingsManageabilityAttribute(global::System.Configuration.SettingsManageability.Roaming)]
public string DocumentCreateCommand_Shortcut {
get {
return ((string)(this["DocumentCreateCommand_Shortcut"]));
}
set {
this["DocumentCreateCommand_Shortcut"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Ctrl+Shift+O")]
[global::System.Configuration.SettingsManageabilityAttribute(global::System.Configuration.SettingsManageability.Roaming)]
public string ProjectOpenCommand_Shortcut {
get {
return ((string)(this["ProjectOpenCommand_Shortcut"]));
}
set {
this["ProjectOpenCommand_Shortcut"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Ctrl+W")]
[global::System.Configuration.SettingsManageabilityAttribute(global::System.Configuration.SettingsManageability.Roaming)]
public string DocumentCloseCommand_Shortcut {
get {
return ((string)(this["DocumentCloseCommand_Shortcut"]));
}
set {
this["DocumentCloseCommand_Shortcut"] = value;
} }
} }
} }

View File

@ -1,7 +1,21 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="RainmeterStudio.Properties" GeneratedClassName="Settings">
<Profiles> <Profiles />
<Profile Name="(Default)" /> <Settings>
</Profiles> <Setting Name="ProjectCreateCommand_Shortcut" Roaming="true" Type="System.String" Scope="User">
<Settings /> <Value Profile="(Default)">Ctrl+Shift+N</Value>
</Setting>
<Setting Name="ProjectPanel_RefreshCommand_Shortcut" Roaming="true" Type="System.String" Scope="User">
<Value Profile="(Default)">F5</Value>
</Setting>
<Setting Name="DocumentCreateCommand_Shortcut" Roaming="true" Type="System.String" Scope="User">
<Value Profile="(Default)">Ctrl+N</Value>
</Setting>
<Setting Name="ProjectOpenCommand_Shortcut" Roaming="true" Type="System.String" Scope="User">
<Value Profile="(Default)">Ctrl+Shift+O</Value>
</Setting>
<Setting Name="DocumentCloseCommand_Shortcut" Roaming="true" Type="System.String" Scope="User">
<Value Profile="(Default)">Ctrl+W</Value>
</Setting>
</Settings>
</SettingsFile> </SettingsFile>

View File

@ -109,9 +109,11 @@
<Compile Include="Model\IDocumentStorage.cs" /> <Compile Include="Model\IDocumentStorage.cs" />
<Compile Include="Storage\ProjectStorage.cs" /> <Compile Include="Storage\ProjectStorage.cs" />
<Compile Include="Storage\SkinDirectory.cs" /> <Compile Include="Storage\SkinDirectory.cs" />
<Compile Include="Storage\SerializableTree.cs" />
<Compile Include="UI\Command.cs" /> <Compile Include="UI\Command.cs" />
<Compile Include="UI\Controller\IconProvider.cs" /> <Compile Include="UI\Controller\IconProvider.cs" />
<Compile Include="UI\Controller\ProjectController.cs" /> <Compile Include="UI\Controller\ProjectController.cs" />
<Compile Include="UI\Controller\SettingsProvider.cs" />
<Compile Include="UI\Dialogs\CreateDocumentDialog.xaml.cs"> <Compile Include="UI\Dialogs\CreateDocumentDialog.xaml.cs">
<DependentUpon>CreateDocumentDialog.xaml</DependentUpon> <DependentUpon>CreateDocumentDialog.xaml</DependentUpon>
</Compile> </Compile>
@ -123,7 +125,9 @@
<Compile Include="UI\ProjectPanel.xaml.cs"> <Compile Include="UI\ProjectPanel.xaml.cs">
<DependentUpon>ProjectPanel.xaml</DependentUpon> <DependentUpon>ProjectPanel.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="UI\ViewModel\ReferenceViewModel.cs" />
<Compile Include="Utils\DirectoryHelper.cs" /> <Compile Include="Utils\DirectoryHelper.cs" />
<Compile Include="Utils\TreeExtensions.cs" />
<Page Include="Documents\Ini\IniSkinDesignerControl.xaml"> <Page Include="Documents\Ini\IniSkinDesignerControl.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -248,6 +252,9 @@
<ItemGroup> <ItemGroup>
<Resource Include="Resources\Icons\16\view-refresh.png" /> <Resource Include="Resources\Icons\16\view-refresh.png" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Resource Include="Resources\Icons\16\folder_project.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -108,9 +108,9 @@ namespace RainmeterStudio.Resources {
/// <summary> /// <summary>
/// Looks up a localized string similar to /Resources/Icons/16/folder.png. /// Looks up a localized string similar to /Resources/Icons/16/folder.png.
/// </summary> /// </summary>
internal static string ProjectItemFolder { internal static string ProjectItemDirectory {
get { get {
return ResourceManager.GetString("ProjectItemFolder", resourceCulture); return ResourceManager.GetString("ProjectItemDirectory", resourceCulture);
} }
} }
@ -132,6 +132,15 @@ namespace RainmeterStudio.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to /Resources/Icons/16/folder_project.png.
/// </summary>
internal static string ProjectOpenCommand {
get {
return ResourceManager.GetString("ProjectOpenCommand", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to /Resources/Icons/16/minus.png. /// Looks up a localized string similar to /Resources/Icons/16/minus.png.
/// </summary> /// </summary>

View File

@ -126,7 +126,7 @@
<data name="ProjectCreateCommand" xml:space="preserve"> <data name="ProjectCreateCommand" xml:space="preserve">
<value>/Resources/Icons/16/project_star.png</value> <value>/Resources/Icons/16/project_star.png</value>
</data> </data>
<data name="ProjectItemFolder" xml:space="preserve"> <data name="ProjectItemDirectory" xml:space="preserve">
<value>/Resources/Icons/16/folder.png</value> <value>/Resources/Icons/16/folder.png</value>
</data> </data>
<data name="ProjectItemNone" xml:space="preserve"> <data name="ProjectItemNone" xml:space="preserve">
@ -141,6 +141,9 @@
<data name="ProjectItem_txt" xml:space="preserve"> <data name="ProjectItem_txt" xml:space="preserve">
<value>/Resources/Icons/16/text_generic.png</value> <value>/Resources/Icons/16/text_generic.png</value>
</data> </data>
<data name="ProjectOpenCommand" xml:space="preserve">
<value>/Resources/Icons/16/folder_project.png</value>
</data>
<data name="ProjectPanel_CollapseAllCommand" xml:space="preserve"> <data name="ProjectPanel_CollapseAllCommand" xml:space="preserve">
<value>/Resources/Icons/16/minus.png</value> <value>/Resources/Icons/16/minus.png</value>
</data> </data>

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

View File

@ -96,6 +96,24 @@ namespace RainmeterStudio.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to All files.
/// </summary>
public static string Dialog_FileType_AllFiles {
get {
return ResourceManager.GetString("Dialog_FileType_AllFiles", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to RainmeterStudio project.
/// </summary>
public static string Dialog_FileType_Project {
get {
return ResourceManager.GetString("Dialog_FileType_Project", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to OK. /// Looks up a localized string similar to OK.
/// </summary> /// </summary>
@ -105,6 +123,33 @@ namespace RainmeterStudio.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Open project....
/// </summary>
public static string Dialog_OpenProject_Title {
get {
return ResourceManager.GetString("Dialog_OpenProject_Title", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Close.
/// </summary>
public static string DocumentCloseCommand_DisplayText {
get {
return ResourceManager.GetString("DocumentCloseCommand_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Close active document.
/// </summary>
public static string DocumentCloseCommand_ToolTip {
get {
return ResourceManager.GetString("DocumentCloseCommand_ToolTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to _File.... /// Looks up a localized string similar to _File....
/// </summary> /// </summary>
@ -115,7 +160,7 @@ namespace RainmeterStudio.Resources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Creates a new file. /// Looks up a localized string similar to Create a new file.
/// </summary> /// </summary>
public static string DocumentCreateCommand_ToolTip { public static string DocumentCreateCommand_ToolTip {
get { get {
@ -150,6 +195,33 @@ namespace RainmeterStudio.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to _File.
/// </summary>
public static string MainWindow_File {
get {
return ResourceManager.GetString("MainWindow_File", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _New.
/// </summary>
public static string MainWindow_File_New {
get {
return ResourceManager.GetString("MainWindow_File_New", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Open.
/// </summary>
public static string MainWindow_File_Open {
get {
return ResourceManager.GetString("MainWindow_File_Open", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to _Project.... /// Looks up a localized string similar to _Project....
/// </summary> /// </summary>
@ -160,7 +232,7 @@ namespace RainmeterStudio.Resources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Creates a new project. /// Looks up a localized string similar to Create a new project.
/// </summary> /// </summary>
public static string ProjectCreateCommand_ToolTip { public static string ProjectCreateCommand_ToolTip {
get { get {
@ -222,6 +294,24 @@ namespace RainmeterStudio.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to _Project....
/// </summary>
public static string ProjectOpenCommand_DisplayText {
get {
return ResourceManager.GetString("ProjectOpenCommand_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open existing project.
/// </summary>
public static string ProjectOpenCommand_ToolTip {
get {
return ResourceManager.GetString("ProjectOpenCommand_ToolTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Collapse all. /// Looks up a localized string similar to Collapse all.
/// </summary> /// </summary>

View File

@ -129,14 +129,29 @@
<data name="Dialog_Create" xml:space="preserve"> <data name="Dialog_Create" xml:space="preserve">
<value>Create</value> <value>Create</value>
</data> </data>
<data name="Dialog_FileType_AllFiles" xml:space="preserve">
<value>All files</value>
</data>
<data name="Dialog_FileType_Project" xml:space="preserve">
<value>RainmeterStudio project</value>
</data>
<data name="Dialog_OK" xml:space="preserve"> <data name="Dialog_OK" xml:space="preserve">
<value>OK</value> <value>OK</value>
</data> </data>
<data name="Dialog_OpenProject_Title" xml:space="preserve">
<value>Open project...</value>
</data>
<data name="DocumentCloseCommand_DisplayText" xml:space="preserve">
<value>_Close</value>
</data>
<data name="DocumentCloseCommand_ToolTip" xml:space="preserve">
<value>Close active document</value>
</data>
<data name="DocumentCreateCommand_DisplayText" xml:space="preserve"> <data name="DocumentCreateCommand_DisplayText" xml:space="preserve">
<value>_File...</value> <value>_File...</value>
</data> </data>
<data name="DocumentCreateCommand_ToolTip" xml:space="preserve"> <data name="DocumentCreateCommand_ToolTip" xml:space="preserve">
<value>Creates a new file</value> <value>Create a new file</value>
</data> </data>
<data name="DocumentEditor_Text_Name" xml:space="preserve"> <data name="DocumentEditor_Text_Name" xml:space="preserve">
<value>Text Editor</value> <value>Text Editor</value>
@ -147,11 +162,20 @@
<data name="DocumentFormat_TextFile_Name" xml:space="preserve"> <data name="DocumentFormat_TextFile_Name" xml:space="preserve">
<value>Text file</value> <value>Text file</value>
</data> </data>
<data name="MainWindow_File" xml:space="preserve">
<value>_File</value>
</data>
<data name="MainWindow_File_New" xml:space="preserve">
<value>_New</value>
</data>
<data name="MainWindow_File_Open" xml:space="preserve">
<value>_Open</value>
</data>
<data name="ProjectCreateCommand_DisplayText" xml:space="preserve"> <data name="ProjectCreateCommand_DisplayText" xml:space="preserve">
<value>_Project...</value> <value>_Project...</value>
</data> </data>
<data name="ProjectCreateCommand_ToolTip" xml:space="preserve"> <data name="ProjectCreateCommand_ToolTip" xml:space="preserve">
<value>Creates a new project</value> <value>Create a new project</value>
</data> </data>
<data name="ProjectCreateDialog_Location" xml:space="preserve"> <data name="ProjectCreateDialog_Location" xml:space="preserve">
<value>Location:</value> <value>Location:</value>
@ -171,6 +195,12 @@
<data name="ProjectCreateDialog_Title" xml:space="preserve"> <data name="ProjectCreateDialog_Title" xml:space="preserve">
<value>Create project</value> <value>Create project</value>
</data> </data>
<data name="ProjectOpenCommand_DisplayText" xml:space="preserve">
<value>_Project...</value>
</data>
<data name="ProjectOpenCommand_ToolTip" xml:space="preserve">
<value>Open existing project</value>
</data>
<data name="ProjectPanel_CollapseAllCommand_DisplayText" xml:space="preserve"> <data name="ProjectPanel_CollapseAllCommand_DisplayText" xml:space="preserve">
<value>Collapse all</value> <value>Collapse all</value>
</data> </data>

View File

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using RainmeterStudio.Model;
namespace RainmeterStudio.Storage
{
/// <summary>
/// A special type of tree that implements a very small subset of tree operations, and can be serialized
/// </summary>
/// <typeparam name="T"></typeparam>
public class SerializableTree<T>
{
/// <summary>
/// Gets or sets the attached data
/// </summary>
[XmlElement("data")]
public T Data { get; set; }
/// <summary>
/// Gets or sets the list of children
/// </summary>
[XmlArray("children"), XmlArrayItem("child")]
public List<SerializableTree<T>> Children { get; set; }
/// <summary>
/// Initializes the serializable tree
/// </summary>
public SerializableTree()
{
Children = new List<SerializableTree<T>>();
Data = default(T);
}
/// <summary>
/// Initializes the serializable tree with specified data
/// </summary>
/// <param name="data">Data</param>
public SerializableTree(T data)
{
Children = new List<SerializableTree<T>>();
Data = data;
}
}
/// <summary>
/// Extension methods for converting to and from serializable trees
/// </summary>
public static class SerializableTreeExtensions
{
/// <summary>
/// Converts tree into a serializable tree
/// </summary>
/// <typeparam name="T">Data type of tree</typeparam>
/// <param name="root">Root node</param>
/// <returns>Serializable tree</returns>
public static SerializableTree<T> AsSerializableTree<T>(this Tree<T> root)
{
// Convert current node
SerializableTree<T> sRoot = new SerializableTree<T>(root.Data);
// Add children
foreach (var child in root.Children)
sRoot.Children.Add(AsSerializableTree(child));
// Return root
return sRoot;
}
/// <summary>
/// Converts serializable tree into a tree
/// </summary>
/// <typeparam name="T">Data type of tree</typeparam>
/// <param name="root">Root node</param>
/// <returns>Tree</returns>
public static Tree<T> AsTree<T>(this SerializableTree<T> root)
{
// Convert current node
Tree<T> sRoot = new Tree<T>(root.Data);
// Add children
foreach (var child in root.Children)
sRoot.Add(AsTree(child));
// Return root
return sRoot;
}
}
}

View File

@ -95,10 +95,28 @@ namespace RainmeterStudio.UI
#region Keyboard shortcut property #region Keyboard shortcut property
private KeyGesture _shortcut;
/// <summary> /// <summary>
/// Gets or sets the keyboard shortcut of this command /// Gets or sets the keyboard shortcut of this command
/// </summary> /// </summary>
public KeyGesture Shortcut { get; set; } public KeyGesture Shortcut
{
get
{
if (_shortcut == null)
{
string str = SettingsProvider.GetSetting<string>(Name + "_Shortcut");
return GetKeyGestureFromString(str);
}
return _shortcut;
}
set
{
_shortcut = value;
}
}
/// <summary> /// <summary>
/// Gets the text representation of the keyboard shortcut /// Gets the text representation of the keyboard shortcut
@ -107,10 +125,12 @@ namespace RainmeterStudio.UI
{ {
get get
{ {
string text = String.Empty; // Safety check
if (Shortcut == null) if (Shortcut == null)
return text; return null;
// Build string
string text = String.Empty;
if ((Shortcut.Modifiers & ModifierKeys.Windows) != 0) if ((Shortcut.Modifiers & ModifierKeys.Windows) != 0)
text += "Win+"; text += "Win+";
@ -127,17 +147,56 @@ namespace RainmeterStudio.UI
text += Enum.GetName(typeof(Key), Shortcut.Key); text += Enum.GetName(typeof(Key), Shortcut.Key);
return text; return text;
} }
set
{
Shortcut = GetKeyGestureFromString(value);
}
}
private KeyGesture GetKeyGestureFromString(string k)
{
// Safety check
if (k == null)
return null;
// Variables
ModifierKeys mods = ModifierKeys.None;
Key key = Key.None;
// Parse each field
foreach (var field in k.Split('+'))
{
// Trim surrounding white space
string trimmed = field.Trim();
// Parse
if (trimmed.Equals("Win", StringComparison.InvariantCultureIgnoreCase))
mods |= ModifierKeys.Windows;
if (trimmed.Equals("Ctrl", StringComparison.InvariantCultureIgnoreCase))
mods |= ModifierKeys.Control;
if (trimmed.Equals("Alt", StringComparison.InvariantCultureIgnoreCase))
mods |= ModifierKeys.Alt;
if (trimmed.Equals("Shift", StringComparison.InvariantCultureIgnoreCase))
mods |= ModifierKeys.Shift;
else Enum.TryParse<Key>(field, out key);
}
return new KeyGesture(key, mods);
} }
#endregion #endregion
#endregion #endregion
#pragma warning disable 67
public event EventHandler CanExecuteChanged; public event EventHandler CanExecuteChanged;
#pragma warning restore 67 public void NotifyCanExecuteChanged()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, new EventArgs());
}
/// <summary> /// <summary>
/// Initializes this command /// Initializes this command

View File

@ -23,10 +23,7 @@ namespace RainmeterStudio.UI.Controller
{ {
if (_documentCreateCommand == null) if (_documentCreateCommand == null)
{ {
_documentCreateCommand = new Command("DocumentCreateCommand", () => CreateWindow()) _documentCreateCommand = new Command("DocumentCreateCommand", () => CreateWindow());
{
Shortcut = new KeyGesture(Key.N, ModifierKeys.Control)
};
} }
return _documentCreateCommand; return _documentCreateCommand;

View File

@ -55,10 +55,10 @@ namespace RainmeterStudio.UI.Controller
{ {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{ {
var tree = value as Tree<Reference>; var reference = value as Reference;
if (tree != null) if (reference != null)
{ {
return IconProvider.GetProjectItemIcon(tree.Data); return IconProvider.GetProjectItemIcon(reference);
} }
return null; return null;

View File

@ -6,6 +6,7 @@ using System.Text;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Microsoft.Win32;
using RainmeterStudio.Business; using RainmeterStudio.Business;
using RainmeterStudio.Model; using RainmeterStudio.Model;
using RainmeterStudio.UI.Dialogs; using RainmeterStudio.UI.Dialogs;
@ -71,22 +72,9 @@ namespace RainmeterStudio.UI.Controller
#region Commands #region Commands
private Command _projectCreateCommand; public Command ProjectCreateCommand { get; private set; }
public Command ProjectCreateCommand
{
get
{
if (_projectCreateCommand == null)
{
_projectCreateCommand = new Command("ProjectCreateCommand", () => CreateProject())
{
Shortcut = new KeyGesture(Key.N, ModifierKeys.Control | ModifierKeys.Shift)
};
}
return _projectCreateCommand; public Command ProjectOpenCommand { get; private set; }
}
}
#endregion #endregion
@ -97,6 +85,9 @@ namespace RainmeterStudio.UI.Controller
public ProjectController(ProjectManager manager) public ProjectController(ProjectManager manager)
{ {
Manager = manager; Manager = manager;
ProjectCreateCommand = new Command("ProjectCreateCommand", () => CreateProject());
ProjectOpenCommand = new Command("ProjectOpenCommand", () => OpenProject());
} }
/// <summary> /// <summary>
@ -133,7 +124,21 @@ namespace RainmeterStudio.UI.Controller
/// <param name="path"></param> /// <param name="path"></param>
public void OpenProject(string path = null) public void OpenProject(string path = null)
{ {
// Open dialog
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = Resources.Strings.Dialog_FileType_Project + "|*.rsproj|"
+ Resources.Strings.Dialog_FileType_AllFiles + "|*.*";
dialog.Title = Resources.Strings.Dialog_OpenProject_Title;
dialog.Multiselect = false;
// Show dialog
bool? res = dialog.ShowDialog(OwnerWindow);
if (!res.HasValue || !res.Value)
return;
// Call manager
string filename = dialog.FileName;
Manager.OpenProject(filename);
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
namespace RainmeterStudio.UI.Controller
{
public static class SettingsProvider
{
/// <summary>
/// Attempts to retrieve the setting of type T, where T is class
/// </summary>
/// <typeparam name="T">Any class type</typeparam>
/// <param name="name">Name of setting</param>
/// <returns>Retrieved setting, or null if not found</returns>
public static T GetSetting<T> (string name) where T : class
{
var property = Properties.Settings.Default.Properties
.OfType<SettingsProperty>()
.FirstOrDefault(x => String.Equals(x.Name, name));
return (property == null) ? null : (property.DefaultValue as T);
}
/// <summary>
/// Attempts to retrieve the setting of type T
/// </summary>
/// <typeparam name="T">Any type</typeparam>
/// <param name="name">Name of setting</param>
/// <param name="value">Output value</param>
/// <returns>True if attempt was successful</returns>
public static bool TryGetSetting<T>(string name, out T value)
{
var property = Properties.Settings.Default.Properties.OfType<SettingsProperty>().FirstOrDefault(x => x.Name.Equals(name));
if (property != null)
{
value = (T)property.DefaultValue;
return true;
}
else
{
value = default(T);
return false;
}
}
}
}

View File

@ -4,6 +4,7 @@
xmlns:ui="clr-namespace:RainmeterStudio.UI" xmlns:ui="clr-namespace:RainmeterStudio.UI"
xmlns:ad="clr-namespace:Xceed.Wpf.AvalonDock;assembly=Xceed.Wpf.AvalonDock" xmlns:ad="clr-namespace:Xceed.Wpf.AvalonDock;assembly=Xceed.Wpf.AvalonDock"
xmlns:adlayout="clr-namespace:Xceed.Wpf.AvalonDock.Layout;assembly=Xceed.Wpf.AvalonDock" xmlns:adlayout="clr-namespace:Xceed.Wpf.AvalonDock.Layout;assembly=Xceed.Wpf.AvalonDock"
xmlns:r="clr-namespace:RainmeterStudio.Resources"
Title="Rainmeter Studio" Height="600" Width="800" Title="Rainmeter Studio" Height="600" Width="800"
ResizeMode="CanResizeWithGrip" > ResizeMode="CanResizeWithGrip" >
@ -21,8 +22,8 @@
<!-- Menu bar --> <!-- Menu bar -->
<Menu Grid.Row="0" Grid.ColumnSpan="10"> <Menu Grid.Row="0" Grid.ColumnSpan="10">
<MenuItem Header="_File"> <MenuItem Header="{x:Static r:Strings.MainWindow_File}">
<MenuItem Header="_New"> <MenuItem Header="{x:Static r:Strings.MainWindow_File_New}">
<MenuItem DataContext="{Binding DocumentController.DocumentCreateCommand}" <MenuItem DataContext="{Binding DocumentController.DocumentCreateCommand}"
Style="{StaticResource CommandMenuItemStyle}" > Style="{StaticResource CommandMenuItemStyle}" >
<MenuItem.Icon> <MenuItem.Icon>
@ -37,7 +38,15 @@
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
<Separator /> <Separator />
<MenuItem Header="_Open..." /> <MenuItem Header="{x:Static r:Strings.MainWindow_File_Open}">
<MenuItem DataContext="{Binding ProjectController.ProjectOpenCommand}"
Style="{StaticResource CommandMenuItemStyle}">
<MenuItem.Icon>
<Image Source="{Binding Icon}" />
</MenuItem.Icon>
</MenuItem>
<Separator />
</MenuItem>
<Separator /> <Separator />
<MenuItem Header="_Close" /> <MenuItem Header="_Close" />
<MenuItem Header="E_xit" /> <MenuItem Header="E_xit" />

View File

@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ctrl="clr-namespace:RainmeterStudio.UI.Controller" xmlns:ctrl="clr-namespace:RainmeterStudio.UI.Controller"
xmlns:ui="clr-namespace:RainmeterStudio.UI"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"> d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources> <UserControl.Resources>
@ -45,13 +46,16 @@
<TreeView Grid.Row="2" Name="treeProjectItems"> <TreeView Grid.Row="2" Name="treeProjectItems">
<TreeView.ItemContainerStyle> <TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}"> <Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" /> <Setter Property="IsExpanded" Value="{Binding Data.IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding Data.IsSelected, Mode=TwoWay}" />
<EventSetter Event="Expanded" Handler="TreeViewItem_ExpandedOrCollapsed" />
<EventSetter Event="Collapsed" Handler="TreeViewItem_ExpandedOrCollapsed" />
</Style> </Style>
</TreeView.ItemContainerStyle> </TreeView.ItemContainerStyle>
<TreeView.ItemTemplate> <TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}"> <HierarchicalDataTemplate ItemsSource="{Binding Children}">
<DockPanel LastChildFill="True"> <DockPanel LastChildFill="True">
<Image DockPanel.Dock="Left" Width="16" Height="16" Source="{Binding Converter={StaticResource IconConverter}}" /> <Image DockPanel.Dock="Left" Width="16" Height="16" Source="{Binding Data.Reference, Converter={StaticResource IconConverter}}" />
<TextBlock Text="{Binding Data.Name}" /> <TextBlock Text="{Binding Data.Name}" />
</DockPanel> </DockPanel>
</HierarchicalDataTemplate> </HierarchicalDataTemplate>

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Text; using System.Text;
@ -17,6 +18,7 @@ using RainmeterStudio.Interop;
using RainmeterStudio.Model; using RainmeterStudio.Model;
using RainmeterStudio.Storage; using RainmeterStudio.Storage;
using RainmeterStudio.UI.Controller; using RainmeterStudio.UI.Controller;
using RainmeterStudio.UI.ViewModel;
using RainmeterStudio.Utils; using RainmeterStudio.Utils;
namespace RainmeterStudio.UI namespace RainmeterStudio.UI
@ -48,78 +50,50 @@ namespace RainmeterStudio.UI
} }
} }
private Command _syncWithActiveViewCommand; #region Commands
public Command SyncWithActiveViewCommand
public Command SyncWithActiveViewCommand { get; private set; }
public Command RefreshCommand { get; private set; }
public Command ExpandAllCommand { get; private set; }
public Command CollapseAllCommand { get; private set; }
public Command ShowAllFilesCommand { get; private set; }
#endregion
private bool _canExpand = false;
private bool CanExpand
{ {
get get
{ {
if (_syncWithActiveViewCommand == null) return _canExpand;
{
_syncWithActiveViewCommand = new Command("ProjectPanel_SyncWithActiveViewCommand", SyncWithActiveView);
} }
return _syncWithActiveViewCommand; set
{
_canExpand = value;
if (ExpandAllCommand != null)
ExpandAllCommand.NotifyCanExecuteChanged();
if (CollapseAllCommand != null)
CollapseAllCommand.NotifyCanExecuteChanged();
} }
} }
private Command _refreshCommand;
public Command RefreshCommand
{
get
{
if (_refreshCommand == null)
{
_refreshCommand = new Command("ProjectPanel_RefreshCommand", SyncWithActiveView)
{
Shortcut = new KeyGesture(Key.F5)
};
}
return _refreshCommand;
}
}
private Command _expandAllCommand;
public Command ExpandAllCommand
{
get
{
if (_expandAllCommand == null)
{
_expandAllCommand = new Command("ProjectPanel_ExpandAllCommand", SyncWithActiveView);
}
return _expandAllCommand;
}
}
private Command _collapseAllCommand;
public Command CollapseAllCommand
{
get
{
if (_collapseAllCommand == null)
{
_collapseAllCommand = new Command("ProjectPanel_CollapseAllCommand", SyncWithActiveView);
}
return _collapseAllCommand;
}
}
private Command _showAllFilesCommand;
public Command ShowAllFilesCommand
{
get
{
if (_showAllFilesCommand == null)
{
_showAllFilesCommand = new Command("ProjectPanel_ShowAllFilesCommand", SyncWithActiveView);
}
return _showAllFilesCommand;
}
}
public ProjectPanel() public ProjectPanel()
{ {
InitializeComponent(); InitializeComponent();
SyncWithActiveViewCommand = new Command("ProjectPanel_SyncWithActiveViewCommand", SyncWithActiveView);
RefreshCommand = new Command("ProjectPanel_RefreshCommand", Refresh);
ExpandAllCommand = new Command("ProjectPanel_ExpandAllCommand", ExpandAll, () => _canExpand);
CollapseAllCommand = new Command("ProjectPanel_CollapseAllCommand", CollapseAll, () => !_canExpand);
ShowAllFilesCommand = new Command("ProjectPanel_ShowAllFilesCommand", Refresh);
this.DataContext = this; this.DataContext = this;
Refresh(); Refresh();
} }
@ -144,34 +118,86 @@ namespace RainmeterStudio.UI
{ {
this.IsEnabled = true; this.IsEnabled = true;
// Display all files in the project directory // Get tree
Tree<ReferenceViewModel> tree;
if (toggleShowAllFiles.IsChecked.HasValue && toggleShowAllFiles.IsChecked.Value) if (toggleShowAllFiles.IsChecked.HasValue && toggleShowAllFiles.IsChecked.Value)
{ {
string projectFolder = System.IO.Path.GetDirectoryName(Controller.ActiveProjectPath); tree = GetAllFiles();
var tree = DirectoryHelper.GetFolderTree(projectFolder); }
tree.Data = Controller.ActiveProject.Root.Data; else
{
tree = GetProjectItems();
}
// Add tree to tree view
treeProjectItems.Items.Clear(); treeProjectItems.Items.Clear();
treeProjectItems.Items.Add(tree); treeProjectItems.Items.Add(tree);
} }
// Display only the project items
else
{
treeProjectItems.Items.Clear();
treeProjectItems.Items.Add(Controller.ActiveProject.Root);
}
}
} }
private void toggleShowAllFiles_Checked(object sender, RoutedEventArgs e) private Tree<ReferenceViewModel> GetAllFiles()
{ {
Refresh(); // Get directory name
string projectFolder = System.IO.Path.GetDirectoryName(Controller.ActiveProjectPath);
// Get folder tree
Tree<Reference> refTree = DirectoryHelper.GetFolderTree(projectFolder);
refTree.Data = Controller.ActiveProject.Root.Data;
// Remove the project file from the list
Tree<Reference> project = refTree.First(x => DirectoryHelper.PathsEqual(x.Data.Path, Controller.ActiveProjectPath));
refTree.Remove(project);
// Transform to reference view model and return
return refTree.TransformData<Reference, ReferenceViewModel>((data) => new ReferenceViewModel(data));
} }
private void toggleShowAllFiles_Unchecked(object sender, RoutedEventArgs e) private Tree<ReferenceViewModel> GetProjectItems()
{ {
Refresh(); // Get project items
Tree<Reference> refTree = Controller.ActiveProject.Root;
// Transform to reference view model and return
return refTree.TransformData<Reference, ReferenceViewModel>((data) => new ReferenceViewModel(data));
}
private void ExpandAll()
{
// Get tree
var tree = treeProjectItems.Items[0] as Tree<ReferenceViewModel>;
if (tree == null)
return;
// Expand all
tree.Apply((node) => node.Data.IsExpanded = true);
// Set can expand property
CanExpand = false;
}
private void CollapseAll()
{
// Get tree
var tree = treeProjectItems.Items[0] as Tree<ReferenceViewModel>;
if (tree == null)
return;
// Expand all
tree.Apply((node) => node.Data.IsExpanded = false);
// Set can expand property
CanExpand = true;
}
void TreeViewItem_ExpandedOrCollapsed(object sender, RoutedEventArgs e)
{
// Get tree
var tree = treeProjectItems.Items[0] as Tree<ReferenceViewModel>;
if (tree == null)
return;
// We can expand if the root is not expanded
CanExpand = (!tree.Data.IsExpanded);
} }
} }
} }

View File

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using RainmeterStudio.Model;
namespace RainmeterStudio.UI.ViewModel
{
/// <summary>
/// Contains the view model of a reference
/// </summary>
public class ReferenceViewModel : INotifyPropertyChanged
{
#region Properties
/// <summary>
/// Gets the linked reference
/// </summary>
public Reference Reference { get; private set; }
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name
{
get
{
return Reference.Name;
}
set
{
Reference.Name = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
/// <summary>
/// Gets or sets the path
/// </summary>
public string Path
{
get
{
return Reference.Path;
}
set
{
Reference.Path = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Path"));
}
}
private bool _isExpanded = true;
/// <summary>
/// Gets or sets a property indicating if the tree view item is expanded
/// </summary>
public bool IsExpanded
{
get
{
return _isExpanded;
}
set
{
_isExpanded = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("IsExpanded"));
}
}
private bool _isSelected;
/// <summary>
/// Gets or sets a property indicating if the tree view item is selected
/// </summary>
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
}
}
#endregion
#region Events
/// <summary>
/// Event triggered when a property is changed
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Constructor
/// <summary>
/// Creates a new instance of reference view model
/// </summary>
/// <param name="reference">Reference</param>
public ReferenceViewModel(Reference reference)
{
Reference = reference;
}
#endregion
}
}

View File

@ -9,6 +9,11 @@ namespace RainmeterStudio.Utils
{ {
public static class DirectoryHelper public static class DirectoryHelper
{ {
/// <summary>
/// Gets a tree of the folder structure
/// </summary>
/// <param name="folder">Folder</param>
/// <returns>A tree</returns>
public static Tree<Reference> GetFolderTree(string folder) public static Tree<Reference> GetFolderTree(string folder)
{ {
// Build tree object // Build tree object
@ -28,5 +33,19 @@ namespace RainmeterStudio.Utils
// Return tree // Return tree
return tree; return tree;
} }
/// <summary>
/// Returns true if two paths are equal
/// </summary>
/// <param name="path1">First path</param>
/// <param name="path2">Second path</param>
/// <returns>True if the paths are equal</returns>
public static bool PathsEqual(string path1, string path2)
{
path1 = System.IO.Path.GetFullPath(path1);
path2 = System.IO.Path.GetFullPath(path2);
return String.Equals(path1, path2, StringComparison.InvariantCultureIgnoreCase);
}
} }
} }

View File

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RainmeterStudio.Model;
namespace RainmeterStudio.Utils
{
/// <summary>
/// Extension methods for trees
/// </summary>
public static class TreeExtensions
{
/// <summary>
/// Tree traversal orders
/// </summary>
public enum TreeTraversalOrder
{
BreadthFirst,
DepthFirst,
DepthFirstPreOrder = DepthFirst,
DepthFirstPostOrder
}
/// <summary>
/// Traverses a tree
/// </summary>
/// <typeparam name="T">Tree data type</typeparam>
/// <param name="root">Root node of tree</param>
/// <param name="order">Traversal order</param>
/// <returns>An enumeration of the nodes in the specified traverse order</returns>
public static IEnumerable<Tree<T>> Traverse<T>(this Tree<T> root, TreeTraversalOrder order = TreeTraversalOrder.BreadthFirst)
{
if (order == TreeTraversalOrder.BreadthFirst)
return TraverseBF(root);
else return TraverseDF(root, order);
}
private static IEnumerable<Tree<T>> TraverseDF<T>(this Tree<T> root, TreeTraversalOrder order)
{
// Preorder - return root first
if (order == TreeTraversalOrder.DepthFirstPreOrder)
yield return root;
// Return children
foreach (var child in root.Children)
foreach (var node in TraverseDF(child, order))
yield return node;
// Postorder - return root last
if (order == TreeTraversalOrder.DepthFirstPostOrder)
yield return root;
}
private static IEnumerable<Tree<T>> TraverseBF<T>(this Tree<T> root)
{
// Create a queue containing the root
Queue<Tree<T>> queue = new Queue<Tree<T>>();
queue.Enqueue(root);
// While there are elements in the queue
while (queue.Count > 0)
{
// Return next node in tree
var node = queue.Dequeue();
yield return node;
// Enqueue node's children
foreach (var child in node.Children)
queue.Enqueue(child);
}
}
/// <summary>
/// Applies an action to every node of the tree
/// </summary>
/// <typeparam name="T">Tree data type</typeparam>
/// <param name="root">Root node of tree</param>
/// <param name="action">Action to apply</param>
/// <param name="order">Traversal order</param>
public static void Apply<T>(this Tree<T> root, Action<Tree<T>> action, TreeTraversalOrder order = TreeTraversalOrder.BreadthFirst)
{
// Safety check
if (action == null)
return;
// Apply action
foreach (var node in Traverse(root, order))
action(node);
}
/// <summary>
/// Applies an action to every node of the tree
/// </summary>
/// <typeparam name="T">Tree data type</typeparam>
/// <param name="root">Root node of tree</param>
/// <param name="action">Action to apply</param>
/// <param name="order">Traversal order</param>
public static void ApplyToData<T>(this Tree<T> root, Action<T> action, TreeTraversalOrder order = TreeTraversalOrder.BreadthFirst)
where T : class
{
// Safety check
if (action == null)
return;
// Apply action
foreach (var node in Traverse(root, order))
action(node.Data);
}
/// <summary>
/// Rebuilds the tree by applying the specified transform function
/// </summary>
/// <typeparam name="T">Data type of tree</typeparam>
/// <typeparam name="TResult">Data type of rebuilt tree</typeparam>
/// <param name="root">The root node</param>
/// <param name="transformFunction">The transform function</param>
/// <returns>The transformed tree</returns>
public static Tree<TResult> Transform<T,TResult>(this Tree<T> root, Func<Tree<T>, Tree<TResult>> transformFunction)
{
// Safety check
if (transformFunction == null)
throw new ArgumentNullException("Transform function cannot be null.");
// Build root
Tree<TResult> resRoot = transformFunction(root);
// Add children
foreach (var node in root.Children)
resRoot.Children.Add(Transform(node, transformFunction));
// Return
return resRoot;
}
/// <summary>
/// Rebuilds the tree by applying the specified transform function
/// </summary>
/// <typeparam name="T">Data type of tree</typeparam>
/// <typeparam name="TResult">Data type of rebuilt tree</typeparam>
/// <param name="root">The root node</param>
/// <param name="transformFunction">The transform function</param>
/// <returns>The transformed tree</returns>
public static Tree<TResult> TransformData<T, TResult>(this Tree<T> root, Func<T, TResult> transformFunction)
{
// Safety check
if (transformFunction == null)
throw new ArgumentNullException("Transform function cannot be null.");
// Build root
Tree<TResult> resRoot = new Tree<TResult>(transformFunction(root.Data));
// Add children
foreach (var node in root.Children)
resRoot.Children.Add(TransformData(node, transformFunction));
// Return
return resRoot;
}
}
}

View File

@ -1,3 +1,27 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration> <configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="RainmeterStudio.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup><userSettings>
<RainmeterStudio.Properties.Settings>
<setting name="ProjectCreateCommand_Shortcut" serializeAs="String">
<value>Ctrl+Shift+N</value>
</setting>
<setting name="ProjectPanel_RefreshCommand_Shortcut" serializeAs="String">
<value>F5</value>
</setting>
<setting name="DocumentCreateCommand_Shortcut" serializeAs="String">
<value>Ctrl+N</value>
</setting>
<setting name="ProjectOpenCommand_Shortcut" serializeAs="String">
<value>Ctrl+Shift+O</value>
</setting>
<setting name="DocumentCloseCommand_Shortcut" serializeAs="String">
<value>Ctrl+W</value>
</setting>
</RainmeterStudio.Properties.Settings>
</userSettings>
</configuration>