Added project item commands, work on project manager, implemented project manager tests

This commit is contained in:
2014-09-16 21:57:15 +03:00
parent 425d7d62f1
commit 7691a3c326
30 changed files with 2526 additions and 321 deletions

View File

@ -3,9 +3,14 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Xml.Serialization;
using RainmeterStudio.Core.Model;
using RainmeterStudio.Core.Storage;
using RainmeterStudio.Core.Utils;
using RainmeterStudio.Editor.ProjectEditor;
using RainmeterStudio.Storage;
namespace RainmeterStudio.Business
{
@ -20,11 +25,6 @@ namespace RainmeterStudio.Business
/// </summary>
public Project ActiveProject { get; protected set; }
/// <summary>
/// Gets or sets the project storage
/// </summary>
protected ProjectStorage Storage { get; set; }
#endregion
#region Events
@ -42,9 +42,8 @@ namespace RainmeterStudio.Business
/// Initializes the project manager
/// </summary>
/// <param name="storage">Project storage</param>
public ProjectManager(ProjectStorage storage)
public ProjectManager()
{
Storage = storage;
ActiveProject = null;
}
@ -69,7 +68,10 @@ namespace RainmeterStudio.Business
ActiveProject.Path = path;
// Save to file
Directory.CreateDirectory(Path.GetDirectoryName(path));
string directory = Path.GetDirectoryName(path);
if (!String.IsNullOrEmpty(directory))
Directory.CreateDirectory(Path.GetDirectoryName(path));
SaveActiveProject();
// Raise event
@ -81,14 +83,14 @@ namespace RainmeterStudio.Business
/// Opens a project from disk
/// </summary>
/// <param name="path"></param>
public void OpenProject(string path)
public void OpenProject(string path)
{
// If there is an opened project, close it
if (ActiveProject != null)
Close();
// Open using storage
ActiveProject = Storage.Read(path);
ActiveProject = ProjectStorage.Read(path);
ActiveProject.Path = path;
// Raise event
@ -106,13 +108,13 @@ namespace RainmeterStudio.Business
throw new InvalidOperationException("Cannot save a project that is not opened.");
// Save
Storage.Write(ActiveProject);
ProjectStorage.Write(ActiveProject);
}
/// <summary>
/// Closes an opened project
/// </summary>
public void Close()
public void Close()
{
ActiveProject = null;
@ -133,12 +135,245 @@ namespace RainmeterStudio.Business
{
_projectTemplates.Add(template);
}
/// <summary>
/// Gets a list of existing project templates
/// </summary>
public IEnumerable<IProjectTemplate> ProjectTemplates { get { return _projectTemplates; } }
#endregion
#region Project item operations
[Serializable]
protected struct ClipboardData
{
public bool Cut;
public string QualifiedName;
}
/// <summary>
/// Places a project item in the clipboard, and marks it for deletion
/// </summary>
/// <param name="ref">Project item to cut</param>
public void ProjectItemCutClipboard(Reference @ref)
{
var dataFormat = DataFormats.GetDataFormat(typeof(ClipboardData).FullName);
ClipboardData data = new ClipboardData();
data.Cut = true;
data.QualifiedName = @ref.QualifiedName;
Clipboard.SetData(dataFormat.Name, data);
}
/// <summary>
/// Places a project item in the clipboard
/// </summary>
/// <param name="ref">Project item to copy</param>
public void ProjectItemCopyClipboard(Reference @ref)
{
var dataFormat = DataFormats.GetDataFormat(typeof(ClipboardData).FullName);
ClipboardData data = new ClipboardData();
data.Cut = false;
data.QualifiedName = @ref.QualifiedName;
Clipboard.SetData(dataFormat.Name, data);
}
/// <summary>
/// Pastes a project item from clipboard
/// </summary>
/// <param name="dest">Destination</param>
public void ProjectItemPasteClipboard(Reference dest)
{
var dataFormat = DataFormats.GetDataFormat(typeof(ClipboardData).FullName);
if (Clipboard.ContainsData(dataFormat.Name))
{
ClipboardData data = (ClipboardData)Clipboard.GetData(dataFormat.Name);
var reference = ActiveProject.Root.GetReference(data.QualifiedName);
if (data.Cut)
{
ProjectItemMove(reference, dest);
Clipboard.Clear();
}
else
{
ProjectItemCopy(reference, dest);
}
}
}
/// <summary>
/// Moves a project item to another folder
/// </summary>
/// <param name="ref">Project item to move</param>
/// <param name="dest">Destination folder</param>
public void ProjectItemMove(Reference @ref, Reference dest)
{
// Move storage file
string refPath = Path.GetFileName(@ref.StoragePath.TrimEnd('\\'));
string destinationPath = (dest.TargetKind == ReferenceTargetKind.Directory) ? dest.StoragePath : Path.GetDirectoryName(dest.StoragePath);
string newPath = Path.Combine(destinationPath, refPath);
if (@ref.TargetKind == ReferenceTargetKind.Directory)
{
Directory.Move(@ref.StoragePath, newPath);
// Update children
UpdateRenameChildren(@ref, @ref.StoragePath, newPath);
}
else
{
File.Move(@ref.StoragePath, newPath);
}
// Set up reference object
@ref.Unparent();
@ref.StoragePath = newPath;
dest.Add(@ref);
}
private void UpdateRenameChildren(Reference root, string oldPath, string newPath)
{
foreach (var pair in root.ChildrenDictionary)
{
pair.Value.StoragePath = pair.Value.StoragePath.Replace(oldPath, newPath);
UpdateRenameChildren(pair.Value, oldPath, newPath);
}
}
/// <summary>
/// Creates a copy of a project item to another folder
/// </summary>
/// <param name="ref">Project item to copy</param>
/// <param name="dest">Destination folder</param>
/// <returns>Reference to the copy</returns>
public Reference ProjectItemCopy(Reference @ref, Reference dest)
{
// Create a clone reference
var copyRef = (Reference)@ref.Clone();
// Copy storage file
string refPath = Path.GetFileName(@ref.StoragePath.TrimEnd('\\'));
string destinationPath = (dest.TargetKind == ReferenceTargetKind.Directory) ? dest.StoragePath : Path.GetDirectoryName(dest.StoragePath);
string newPath = Path.Combine(destinationPath, refPath);
if (@ref.TargetKind == ReferenceTargetKind.Directory)
{
DirectoryHelper.CopyDirectory(@ref.StoragePath, newPath);
// Update children
UpdateRenameChildren(copyRef, copyRef.StoragePath, newPath);
}
else
{
// Find a nonconflicting file name
newPath = GetNonConflictingPath(refPath, destinationPath);
// Copy
File.Copy(@ref.StoragePath, newPath);
}
// Parent reference
copyRef.Name = Path.GetFileName(newPath);
copyRef.StoragePath = newPath;
dest.Add(copyRef);
return copyRef;
}
private static string GetNonConflictingPath(string filename, string destinationPath)
{
// Initial path - destination path + file name
string newPath = Path.Combine(destinationPath, filename);
// Initial number
int i = 1;
// Try to find if there already is a number
var match = Regex.Match(newPath, "_([0-9])$");
if (match.Success)
{
i = Int32.Parse(match.Groups[1].Value);
}
// Find non-conflicting number
while (File.Exists(newPath))
{
++i;
newPath = Path.Combine(destinationPath, Path.GetFileNameWithoutExtension(filename) + "_" + i.ToString() + Path.GetExtension(filename));
}
return newPath;
}
public void ProjectItemRename(Reference @ref, string newName)
{
// Rename on disk
string refPath = @ref.StoragePath.TrimEnd('\\');
string refDir = Path.GetDirectoryName(refPath);
string newPath = Path.Combine(refDir, newName);
if (@ref.TargetKind == ReferenceTargetKind.Directory)
{
Directory.Move(refPath, newPath);
newPath += '\\';
}
else
{
File.Move(refPath, newPath);
}
// Set reference
@ref.Name = newName;
@ref.StoragePath = newPath;
}
/// <summary>
/// Deletes a project item
/// </summary>
/// <param name="ref"></param>
public void ProjectItemDelete(Reference @ref, bool fromDisk)
{
if (fromDisk)
{
if (@ref.TargetKind == ReferenceTargetKind.File)
File.Delete(@ref.StoragePath);
else Directory.Delete(@ref.StoragePath, true);
}
@ref.Unparent();
}
/// <summary>
/// Checks if there is a project item in the clipboard
/// </summary>
/// <returns>True if there is a project item in the clipboard</returns>
public bool HaveProjectItemInClipboard()
{
var dataFormat = DataFormats.GetDataFormat(typeof(ClipboardData).FullName);
return Clipboard.ContainsData(dataFormat.Name);
}
/// <summary>
/// Creates a new folder with given name
/// </summary>
/// <param name="name">Name of folder</param>
/// <param name="parent">Parent folder</param>
public void CreateFolder(string name, Reference parent)
{
string dir = (parent.TargetKind == ReferenceTargetKind.Directory) ?
parent.StoragePath : Path.GetDirectoryName(parent.StoragePath);
string newDirPath = Path.Combine(dir, name);
Directory.CreateDirectory(newDirPath);
parent.Add(new Reference(name, newDirPath, ReferenceTargetKind.Directory));
}
#endregion
}
}

View File

@ -7,6 +7,7 @@ using System.Xml.Serialization;
using RainmeterStudio.Core;
using RainmeterStudio.Core.Model;
using RainmeterStudio.Core.Storage;
using RainmeterStudio.Storage;
namespace RainmeterStudio.Editor.ProjectEditor
{
@ -14,60 +15,8 @@ namespace RainmeterStudio.Editor.ProjectEditor
/// Project storage, loads and saves project files
/// </summary>
[PluginExport]
public class ProjectStorage : IDocumentStorage
public class ProjectDocumentStorage : IDocumentStorage
{
/// <summary>
/// Loads a project from file
/// </summary>
/// <param name="path">Path to file to load</param>
/// <returns>Loaded project</returns>
public Project Read(string path)
{
// Open file
var file = File.OpenText(path);
// Deserialize file
var serializer = new XmlSerializer(typeof(Project), new XmlRootAttribute("project"));
Project project = serializer.Deserialize(file) as Project;
if (project != null)
{
project.Path = path;
}
// Clean up
file.Close();
return project;
}
/// <summary>
/// Saves a project to file
/// </summary>
/// <param name="project">Project to save</param>
/// <param name="path">File to save to</param>
public void Write(Project project, string path)
{
// Open file
var file = File.OpenWrite(path);
// Serialize file
var serializer = new XmlSerializer(typeof(Project), new XmlRootAttribute("project"));
serializer.Serialize(file, project);
// Clean up
file.Close();
project.Path = path;
}
/// <summary>
/// Saves a project
/// </summary>
/// <param name="project">Saves a project to the path specified in the 'Path' property</param>
public void Write(Project project)
{
Write(project, project.Path);
}
/// <summary>
/// Reads the project as a ProjectDocument.
/// Use Load to get only the Project.
@ -76,9 +25,9 @@ namespace RainmeterStudio.Editor.ProjectEditor
/// <returns>A project document</returns>
public IDocument ReadDocument(string path)
{
Project project = Read(path);
Project project = ProjectStorage.Read(path);
var document = new ProjectDocument(project);
document.Reference = new Reference(Path.GetFileName(path), path);
document.Reference = new Reference(Path.GetFileName(path), path, ReferenceTargetKind.Project);
return document;
}
@ -91,7 +40,7 @@ namespace RainmeterStudio.Editor.ProjectEditor
public void WriteDocument(IDocument document, string path)
{
var projectDocument = (ProjectDocument)document;
Write(projectDocument.Project, path);
ProjectStorage.Write(projectDocument.Project, path);
}
/// <summary>

View File

@ -23,11 +23,8 @@ namespace RainmeterStudio
SplashScreen splash = new SplashScreen("Resources/splash.png");
splash.Show(true);
// Initialize project manager
ProjectStorage projectStorage = new ProjectStorage();
ProjectManager projectManager = new ProjectManager(projectStorage);
// Initialize document manager
// Initialize project, document manager
ProjectManager projectManager = new ProjectManager();
DocumentManager documentManager = new DocumentManager();
// Initialize plugin manager

View File

@ -96,14 +96,12 @@
<DesignTime>True</DesignTime>
<DependentUpon>Strings.resx</DependentUpon>
</Compile>
<Compile Include="Editor\ProjectEditor\ProjectStorage.cs" />
<Compile Include="Editor\ProjectEditor\ProjectDocumentStorage.cs" />
<Compile Include="Storage\ProjectStorage.cs" />
<Compile Include="UI\Command.cs" />
<Compile Include="UI\CommandGroup.cs" />
<Compile Include="UI\Controller\IconProvider.cs" />
<Compile Include="UI\Controller\IContextMenuProvider.cs" />
<Compile Include="UI\Controller\ProjectController.cs" />
<Compile Include="Business\SettingsProvider.cs" />
<Compile Include="UI\Controller\ReferenceContextMenuProvider.cs" />
<Compile Include="UI\Dialogs\CloseUnsavedDialog.xaml.cs">
<DependentUpon>CloseUnsavedDialog.xaml</DependentUpon>
</Compile>
@ -114,6 +112,9 @@
<Compile Include="UI\Dialogs\CreateProjectDialog.xaml.cs">
<DependentUpon>CreateProjectDialog.xaml</DependentUpon>
</Compile>
<Compile Include="UI\Dialogs\InputDialog.xaml.cs">
<DependentUpon>InputDialog.xaml</DependentUpon>
</Compile>
<Compile Include="UI\Panels\ProjectPanel.xaml.cs">
<DependentUpon>ProjectPanel.xaml</DependentUpon>
</Compile>
@ -133,6 +134,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI\Dialogs\InputDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -260,9 +265,7 @@
<Resource Include="Resources\Icons\16\disk.png" />
<Resource Include="Resources\Icons\16\disk_multiple.png" />
</ItemGroup>
<ItemGroup>
<Folder Include="Storage\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- 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.

View File

@ -108,6 +108,15 @@ namespace RainmeterStudio.Resources {
/// <summary>
/// Looks up a localized string similar to _File....
/// </summary>
public static string Command_DocumentCreate_AltDisplayText {
get {
return ResourceManager.GetString("Command_DocumentCreate_AltDisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _New item.
/// </summary>
public static string Command_DocumentCreate_DisplayText {
get {
return ResourceManager.GetString("Command_DocumentCreate_DisplayText", resourceCulture);
@ -126,6 +135,15 @@ namespace RainmeterStudio.Resources {
/// <summary>
/// Looks up a localized string similar to _File....
/// </summary>
public static string Command_DocumentOpen_AltDisplayText {
get {
return ResourceManager.GetString("Command_DocumentOpen_AltDisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Open.
/// </summary>
public static string Command_DocumentOpen_DisplayText {
get {
return ResourceManager.GetString("Command_DocumentOpen_DisplayText", resourceCulture);
@ -234,6 +252,15 @@ namespace RainmeterStudio.Resources {
/// <summary>
/// Looks up a localized string similar to _Project....
/// </summary>
public static string Command_ProjectCreate_AltDisplayText {
get {
return ResourceManager.GetString("Command_ProjectCreate_AltDisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to New _Project.
/// </summary>
public static string Command_ProjectCreate_DisplayText {
get {
return ResourceManager.GetString("Command_ProjectCreate_DisplayText", resourceCulture);
@ -249,9 +276,144 @@ namespace RainmeterStudio.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to _Copy.
/// </summary>
public static string Command_ProjectItemCopy_DisplayText {
get {
return ResourceManager.GetString("Command_ProjectItemCopy_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Copy the selected item to clipboard.
/// </summary>
public static string Command_ProjectItemCopy_ToolTip {
get {
return ResourceManager.GetString("Command_ProjectItemCopy_ToolTip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cu_t.
/// </summary>
public static string Command_ProjectItemCut_DisplayText {
get {
return ResourceManager.GetString("Command_ProjectItemCut_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cut the selected item to clipboard.
/// </summary>
public static string Command_ProjectItemCut_ToolTip {
get {
return ResourceManager.GetString("Command_ProjectItemCut_ToolTip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Delete.
/// </summary>
public static string Command_ProjectItemDelete_DisplayText {
get {
return ResourceManager.GetString("Command_ProjectItemDelete_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Delete selected item.
/// </summary>
public static string Command_ProjectItemDelete_ToolTip {
get {
return ResourceManager.GetString("Command_ProjectItemDelete_ToolTip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open Containing _Folder.
/// </summary>
public static string Command_ProjectItemOpenContainingFolder_DisplayText {
get {
return ResourceManager.GetString("Command_ProjectItemOpenContainingFolder_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open containing folder of selected item in Explorer.
/// </summary>
public static string Command_ProjectItemOpenContainingFolder_ToolTip {
get {
return ResourceManager.GetString("Command_ProjectItemOpenContainingFolder_ToolTip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open in _Explorer.
/// </summary>
public static string Command_ProjectItemOpenInExplorer_DisplayText {
get {
return ResourceManager.GetString("Command_ProjectItemOpenInExplorer_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open selected folder in Explorer.
/// </summary>
public static string Command_ProjectItemOpenInExplorer_ToolTip {
get {
return ResourceManager.GetString("Command_ProjectItemOpenInExplorer_ToolTip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Paste.
/// </summary>
public static string Command_ProjectItemPaste_DisplayText {
get {
return ResourceManager.GetString("Command_ProjectItemPaste_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Paste the clipboard contents in selected folder.
/// </summary>
public static string Command_ProjectItemPaste_ToolTip {
get {
return ResourceManager.GetString("Command_ProjectItemPaste_ToolTip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Rename.
/// </summary>
public static string Command_ProjectItemRename_DisplayText {
get {
return ResourceManager.GetString("Command_ProjectItemRename_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Rename selected item.
/// </summary>
public static string Command_ProjectItemRename_ToolTip {
get {
return ResourceManager.GetString("Command_ProjectItemRename_ToolTip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Project....
/// </summary>
public static string Command_ProjectOpen_AltDisplayText {
get {
return ResourceManager.GetString("Command_ProjectOpen_AltDisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to O_pen Project.
/// </summary>
public static string Command_ProjectOpen_DisplayText {
get {
return ResourceManager.GetString("Command_ProjectOpen_DisplayText", resourceCulture);
@ -447,6 +609,24 @@ namespace RainmeterStudio.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Do you also want to delete the selected project items from disk?.
/// </summary>
public static string DeleteReferenceDialog_Caption {
get {
return ResourceManager.GetString("DeleteReferenceDialog_Caption", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Delete from disk?.
/// </summary>
public static string DeleteReferenceDialog_Prompt {
get {
return ResourceManager.GetString("DeleteReferenceDialog_Prompt", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Browse.
/// </summary>
@ -599,5 +779,32 @@ namespace RainmeterStudio.Resources {
return ResourceManager.GetString("ProjectTemplate_EmptyProject_DisplayText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Rename project item.
/// </summary>
public static string RenameReferenceDialog_Caption {
get {
return ResourceManager.GetString("RenameReferenceDialog_Caption", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Rename.
/// </summary>
public static string RenameReferenceDialog_OKCaption {
get {
return ResourceManager.GetString("RenameReferenceDialog_OKCaption", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Enter the new name:.
/// </summary>
public static string RenameReferenceDialog_Prompt {
get {
return ResourceManager.GetString("RenameReferenceDialog_Prompt", resourceCulture);
}
}
}
}

View File

@ -154,7 +154,7 @@
<value>Close active document</value>
</data>
<data name="Command_DocumentCreate_DisplayText" xml:space="preserve">
<value>_File...</value>
<value>_New item</value>
</data>
<data name="Command_DocumentCreate_ToolTip" xml:space="preserve">
<value>Create a new file</value>
@ -168,7 +168,7 @@
<data name="MainWindow_File_Open" xml:space="preserve">
<value>_Open</value>
</data>
<data name="Command_ProjectCreate_DisplayText" xml:space="preserve">
<data name="Command_ProjectCreate_AltDisplayText" xml:space="preserve">
<value>_Project...</value>
</data>
<data name="Command_ProjectCreate_ToolTip" xml:space="preserve">
@ -192,7 +192,7 @@
<data name="CreateProjectDialog_Title" xml:space="preserve">
<value>Create project</value>
</data>
<data name="Command_ProjectOpen_DisplayText" xml:space="preserve">
<data name="Command_ProjectOpen_AltDisplayText" xml:space="preserve">
<value>_Project...</value>
</data>
<data name="Command_ProjectOpen_ToolTip" xml:space="preserve">
@ -268,7 +268,7 @@
<value>Save document</value>
</data>
<data name="Command_DocumentOpen_DisplayText" xml:space="preserve">
<value>_File...</value>
<value>_Open</value>
</data>
<data name="Command_DocumentOpen_ToolTip" xml:space="preserve">
<value>Open a file</value>
@ -297,4 +297,73 @@
<data name="Command_DocumentSave_ToolTip" xml:space="preserve">
<value>Save the current document</value>
</data>
<data name="DeleteReferenceDialog_Caption" xml:space="preserve">
<value>Do you also want to delete the selected project items from disk?</value>
</data>
<data name="DeleteReferenceDialog_Prompt" xml:space="preserve">
<value>Delete from disk?</value>
</data>
<data name="RenameReferenceDialog_Caption" xml:space="preserve">
<value>Rename project item</value>
</data>
<data name="RenameReferenceDialog_OKCaption" xml:space="preserve">
<value>Rename</value>
</data>
<data name="RenameReferenceDialog_Prompt" xml:space="preserve">
<value>Enter the new name:</value>
</data>
<data name="Command_DocumentCreate_AltDisplayText" xml:space="preserve">
<value>_File...</value>
</data>
<data name="Command_DocumentOpen_AltDisplayText" xml:space="preserve">
<value>_File...</value>
</data>
<data name="Command_ProjectItemCopy_DisplayText" xml:space="preserve">
<value>_Copy</value>
</data>
<data name="Command_ProjectItemCopy_ToolTip" xml:space="preserve">
<value>Copy the selected item to clipboard</value>
</data>
<data name="Command_ProjectItemCut_DisplayText" xml:space="preserve">
<value>Cu_t</value>
</data>
<data name="Command_ProjectItemCut_ToolTip" xml:space="preserve">
<value>Cut the selected item to clipboard</value>
</data>
<data name="Command_ProjectItemDelete_DisplayText" xml:space="preserve">
<value>_Delete</value>
</data>
<data name="Command_ProjectItemDelete_ToolTip" xml:space="preserve">
<value>Delete selected item</value>
</data>
<data name="Command_ProjectItemOpenContainingFolder_DisplayText" xml:space="preserve">
<value>Open Containing _Folder</value>
</data>
<data name="Command_ProjectItemOpenContainingFolder_ToolTip" xml:space="preserve">
<value>Open containing folder of selected item in Explorer</value>
</data>
<data name="Command_ProjectItemOpenInExplorer_DisplayText" xml:space="preserve">
<value>Open in _Explorer</value>
</data>
<data name="Command_ProjectItemOpenInExplorer_ToolTip" xml:space="preserve">
<value>Open selected folder in Explorer</value>
</data>
<data name="Command_ProjectItemPaste_DisplayText" xml:space="preserve">
<value>_Paste</value>
</data>
<data name="Command_ProjectItemPaste_ToolTip" xml:space="preserve">
<value>Paste the clipboard contents in selected folder</value>
</data>
<data name="Command_ProjectItemRename_DisplayText" xml:space="preserve">
<value>_Rename</value>
</data>
<data name="Command_ProjectItemRename_ToolTip" xml:space="preserve">
<value>Rename selected item</value>
</data>
<data name="Command_ProjectCreate_DisplayText" xml:space="preserve">
<value>New _Project</value>
</data>
<data name="Command_ProjectOpen_DisplayText" xml:space="preserve">
<value>O_pen Project</value>
</data>
</root>

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using RainmeterStudio.Core.Model;
namespace RainmeterStudio.Storage
{
/// <summary>
/// Reads or writes projects
/// </summary>
public static class ProjectStorage
{
/// <summary>
/// Loads a project from file
/// </summary>
/// <param name="path">Path to file to load</param>
/// <returns>Loaded project</returns>
public static Project Read(string path)
{
// Open file
var file = File.OpenText(path);
// Deserialize file
var serializer = new XmlSerializer(typeof(Project), new XmlRootAttribute("project"));
Project project = serializer.Deserialize(file) as Project;
if (project != null)
{
project.Path = path;
}
// Clean up
file.Close();
return project;
}
/// <summary>
/// Saves a project
/// </summary>
/// <param name="project">Saves a project to the path specified in the 'Path' property</param>
public static void Write(Project project)
{
Write(project, project.Path);
}
/// <summary>
/// Saves a project to file
/// </summary>
/// <param name="project">Project to save</param>
/// <param name="path">File to save to</param>
public static void Write(Project project, string path)
{
// Open file
var file = File.OpenWrite(path);
// Serialize file
var serializer = new XmlSerializer(typeof(Project), new XmlRootAttribute("project"));
serializer.Serialize(file, project);
// Clean up
file.Close();
project.Path = path;
}
}
}

View File

@ -13,7 +13,13 @@
<Style TargetType="ToolBarTray">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style x:Key="CommandContextMenuItemStyle" TargetType="MenuItem">
<Setter Property="Command" Value="{Binding}" />
<Setter Property="Header" Value="{Binding DisplayText}" />
<Setter Property="ToolTip" Value="{Binding ToolTip}" />
</Style>
<Style x:Key="CommandMenuItemStyle" TargetType="MenuItem">
<Setter Property="Command" Value="{Binding}" />
<Setter Property="Header" Value="{Binding DisplayText}" />

View File

@ -114,7 +114,17 @@ namespace RainmeterStudio.UI.Controller
ProjectManager = projectManager;
DocumentCreateCommand = new Command("DocumentCreate", Create, () => ProjectManager.ActiveProject != null);
DocumentOpenCommand = new Command("DocumentOpen", Open);
DocumentOpenCommand = new Command("DocumentOpen", arg =>
{
if (arg is Reference)
{
Open((Reference)arg);
}
else
{
Open();
}
});
DocumentSaveCommand = new Command("DocumentSave", () => Save(), HasActiveDocumentEditor);
DocumentSaveAsCommand = new Command("DocumentSaveAs", () => SaveAs(), HasActiveDocumentEditor);
DocumentSaveACopyCommand = new Command("DocumentSaveACopy", () => SaveACopy(), HasActiveDocumentEditor);
@ -168,7 +178,7 @@ namespace RainmeterStudio.UI.Controller
if (!Directory.Exists(folder))
folder = Path.GetDirectoryName(folder);
var reference = new Reference(name, Path.Combine(folder, name), Reference.ReferenceTargetKind.File);
var reference = new Reference(name, Path.Combine(folder, name), ReferenceTargetKind.File);
editor.AttachedDocument.Reference = reference;
// Save document
@ -198,6 +208,15 @@ namespace RainmeterStudio.UI.Controller
}
}
/// <summary>
/// Opens the document pointed to by a reference
/// </summary>
/// <param name="reference"></param>
public void Open(Reference reference)
{
DocumentManager.Open(reference.StoragePath);
}
/// <summary>
/// Saves the active document
/// </summary>

View File

@ -33,7 +33,7 @@ namespace RainmeterStudio.UI.Controller
string key = "ProjectItem";
// Is a file?
if (item.TargetKind == Reference.ReferenceTargetKind.File || item.TargetKind == Reference.ReferenceTargetKind.Project)
if (item.TargetKind == ReferenceTargetKind.File || item.TargetKind == ReferenceTargetKind.Project)
{
var extension = Path.GetExtension(item.StoragePath);
@ -45,7 +45,7 @@ namespace RainmeterStudio.UI.Controller
}
// Not a file, try to figure out if a directory
else if (item.TargetKind == Reference.ReferenceTargetKind.Directory)
else if (item.TargetKind == ReferenceTargetKind.Directory)
{
key += "Directory";
}

View File

@ -9,6 +9,7 @@ using RainmeterStudio.Core.Model;
using RainmeterStudio.UI.Dialogs;
using RainmeterStudio.UI.ViewModel;
using RainmeterStudio.Properties;
using RainmeterStudio.Core.Utils;
namespace RainmeterStudio.UI.Controller
{
@ -97,6 +98,42 @@ namespace RainmeterStudio.UI.Controller
/// </summary>
public Command ProjectCloseCommand { get; private set; }
/// <summary>
/// Cut command
/// </summary>
public Command ProjectItemCutCommand { get; private set; }
/// <summary>
/// Copy command
/// </summary>
public Command ProjectItemCopyCommand { get; private set; }
/// <summary>
/// Paste command
/// </summary>
public Command ProjectItemPasteCommand { get; private set; }
/// <summary>
/// Rename command
/// </summary>
public Command ProjectItemRenameCommand { get; private set; }
/// <summary>
/// Delete command
/// </summary>
public Command ProjectItemDeleteCommand { get; private set; }
/// <summary>
/// Open folder command
/// </summary>
public Command ProjectItemOpenInExplorerCommand { get; private set; }
/// <summary>
/// Open folder command
/// </summary>
public Command ProjectItemOpenContainingFolderCommand { get; private set; }
#endregion
/// <summary>
@ -111,9 +148,19 @@ namespace RainmeterStudio.UI.Controller
ProjectCreateCommand = new Command("ProjectCreate", CreateProject);
ProjectOpenCommand = new Command("ProjectOpen", OpenProject);
ProjectCloseCommand = new Command("ProjectClose", CloseProject, () => ActiveProject != null);
ProjectItemCutCommand = new Command("ProjectItemCut", r => ProjectItemCutClipboard((Reference)r));
ProjectItemCopyCommand = new Command("ProjectItemCopy", r => ProjectItemCopyClipboard((Reference)r));
ProjectItemPasteCommand = new Command("ProjectItemPaste", r => ProjectItemPasteClipboard((Reference)r), r => Manager.HaveProjectItemInClipboard());
ProjectItemRenameCommand = new Command("ProjectItemRename", r => ProjectItemRename((Reference)r));
ProjectItemDeleteCommand = new Command("ProjectItemDelete", r => ProjectItemDelete((Reference)r));
ProjectItemOpenInExplorerCommand = new Command("ProjectItemOpenInExplorer", r => ProjectItemOpenInExplorer((Reference)r));
ProjectItemOpenContainingFolderCommand = new Command("ProjectItemOpenContainingFolder", r => ProjectItemOpenInExplorer((Reference)r));
ActiveProjectChanged += new EventHandler((sender, e) => ProjectCloseCommand.NotifyCanExecuteChanged());
}
#region Project operations
/// <summary>
/// Displays the 'create project' dialog and creates a new project
/// </summary>
@ -167,5 +214,144 @@ namespace RainmeterStudio.UI.Controller
{
Manager.Close();
}
#endregion
#region Project item operations
protected struct ClipboardData
{
public bool Cut;
public Reference Ref;
}
/// <summary>
/// Places a project item in the clipboard, and marks it for deletion
/// </summary>
/// <param name="ref">Project item to cut</param>
public void ProjectItemCutClipboard(Reference @ref)
{
try
{
Manager.ProjectItemCutClipboard(@ref);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
/// <summary>
/// Places a project item in the clipboard
/// </summary>
/// <param name="ref">Project item to copy</param>
public void ProjectItemCopyClipboard(Reference @ref)
{
try
{
Manager.ProjectItemCopyClipboard(@ref);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
/// <summary>
/// Pastes a project item from clipboard
/// </summary>
/// <param name="ref">Destination</param>
public void ProjectItemPasteClipboard(Reference @ref)
{
try
{
Manager.ProjectItemPasteClipboard(@ref);
Manager.SaveActiveProject();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
/// <summary>
/// Renames a project item
/// </summary>
/// <param name="ref">Reference to project item</param>
public void ProjectItemRename(Reference @ref)
{
string initialValue = Path.GetFileName(@ref.StoragePath.TrimEnd('\\'));
// Show an input dialog
var newName = InputDialog.Show(Resources.Strings.RenameReferenceDialog_Prompt,
Resources.Strings.RenameReferenceDialog_Caption,
initialValue,
PathHelper.IsFileNameValid,
Resources.Strings.RenameReferenceDialog_OKCaption,
Resources.Strings.Dialog_Cancel);
if (newName != null)
{
try
{
Manager.ProjectItemRename(@ref, newName);
Manager.SaveActiveProject();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
}
/// <summary>
/// Deletes a project item
/// </summary>
/// <param name="ref">Reference to project item</param>
public void ProjectItemDelete(Reference @ref)
{
var res = MessageBox.Show(Resources.Strings.DeleteReferenceDialog_Prompt,
Resources.Strings.DeleteReferenceDialog_Caption,
MessageBoxButton.YesNoCancel,
MessageBoxImage.Question);
try
{
switch(res)
{
case MessageBoxResult.Yes:
Manager.ProjectItemDelete(@ref, true);
Manager.SaveActiveProject();
break;
case MessageBoxResult.No:
Manager.ProjectItemDelete(@ref, false);
Manager.SaveActiveProject();
break;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
/// <summary>
/// Opens the containing folder if reference is a file, or folder if reference is a folder in windows explorer
/// </summary>
/// <param name="ref">Reference</param>
public void ProjectItemOpenInExplorer(Reference @ref)
{
if (@ref.TargetKind == ReferenceTargetKind.Directory)
{
System.Diagnostics.Process.Start(@ref.StoragePath);
}
else
{
System.Diagnostics.Process.Start(Path.GetDirectoryName(@ref.StoragePath));
}
}
#endregion
}
}

View File

@ -0,0 +1,29 @@
<Window x:Class="RainmeterStudio.UI.Dialogs.InputDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:r="clr-namespace:RainmeterStudio.Resources"
Height="100" Width="360"
WindowStartupLocation="CenterOwner"
WindowStyle="ToolWindow" ShowInTaskbar="False"
Background="WhiteSmoke" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Name="textPrompt" Grid.Row="0"
Text="[placeholder]" Margin="4" Grid.ColumnSpan="2"/>
<TextBox Name="textInput" Grid.Row="1" Margin="3"
TextChanged="textInput_TextChanged" Grid.ColumnSpan="2"/>
<StackPanel Grid.Row="2" Orientation="Horizontal"
HorizontalAlignment="Right" Grid.Column="1">
<Button Name="buttonOK" Content="{x:Static r:Strings.Dialog_OK}" IsDefault="True" Margin="1px" Click="buttonOK_Click" />
<Button Name="buttonCancel" Content="{x:Static r:Strings.Dialog_Cancel}" IsCancel="True" Margin="1px" Click="buttonCancel_Click" />
</StackPanel>
</Grid>
</Window>

View File

@ -0,0 +1,380 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using RainmeterStudio.Resources;
namespace RainmeterStudio.UI.Dialogs
{
/// <summary>
/// Interaction logic for InputDialog.xaml
/// </summary>
public partial class InputDialog : Window
{
private Func<string, bool> _validateFunction;
/// <summary>
/// A validate function that always returns true
/// </summary>
public static readonly Func<string, bool> AlwaysValid = (str => true);
#region Properties
/// <summary>
/// Gets or sets the prompt text
/// </summary>
public string Prompt
{
get
{
return textPrompt.Text;
}
set
{
textPrompt.Text = value;
}
}
/// <summary>
/// Gets or sets the text on the 'ok' button
/// </summary>
public string OKCaption
{
get
{
return (string)buttonOK.Content;
}
set
{
buttonOK.Content = value;
}
}
/// <summary>
/// Gets or sets the text on the 'cancel' button
/// </summary>
public string CancelCaption
{
get
{
return (string)buttonCancel.Content;
}
set
{
buttonCancel.Content = value;
}
}
/// <summary>
/// Gets or sets the text inputted by the user
/// </summary>
public string InputText
{
get
{
return textInput.Text;
}
set
{
textInput.Text = value;
Validate();
}
}
/// <summary>
/// Gets or sets a function used to validate the input
/// </summary>
public Func<string, bool> ValidateFunction
{
get
{
return _validateFunction;
}
set
{
_validateFunction = value;
Validate();
}
}
#endregion
/// <summary>
/// Initializes the input dialog
/// </summary>
/// <param name="prompt">Message displayed to user</param>
public InputDialog(string prompt)
:this(prompt, String.Empty, String.Empty, AlwaysValid)
{
}
/// <summary>
/// Initializes the input dialog
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
public InputDialog(string prompt, string caption)
: this(prompt, caption, String.Empty, AlwaysValid)
{
}
/// <summary>
/// Initializes the input dialog
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="okCaption">Caption of the 'OK' button</param>
/// <param name="cancelCaption">Caption of the 'Cancel' button</param>
public InputDialog(string prompt, string caption, string okCaption, string cancelCaption)
: this(prompt, caption, String.Empty, AlwaysValid, okCaption, cancelCaption)
{
}
/// <summary>
/// Initializes the input dialog
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="validateFunction">Callback function which validates the inputted text</param>
public InputDialog(string prompt, string caption, Func<string, bool> validateFunction)
: this(prompt, caption, String.Empty, validateFunction)
{
}
/// <summary>
/// Initializes the input dialog
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="validateFunction">Callback function which validates the inputted text</param>
/// <param name="okCaption">Caption of the 'OK' button</param>
/// <param name="cancelCaption">Caption of the 'Cancel' button</param>
public InputDialog(string prompt, string caption, Func<string, bool> validateFunction, string okCaption, string cancelCaption)
: this(prompt, caption, String.Empty, validateFunction, okCaption, cancelCaption)
{
}
/// <summary>
/// Initializes the input dialog
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="initialValue">Initial value of the input dialog</param>
public InputDialog(string prompt, string caption, string initialValue)
: this(prompt, caption, initialValue, AlwaysValid)
{
}
/// <summary>
/// Initializes the input dialog
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="initialValue">Initial value of the input dialog</param>
/// <param name="okCaption">Caption of the 'OK' button</param>
/// <param name="cancelCaption">Caption of the 'Cancel' button</param>
public InputDialog(string prompt, string caption, string initialValue, string okCaption, string cancelCaption)
: this(prompt, caption, initialValue, AlwaysValid, okCaption, cancelCaption)
{
}
/// <summary>
/// Initializes the input dialog
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="initialValue">Initial value of the input dialog</param>
/// <param name="validateFunction">Callback function which validates the inputted text</param>
public InputDialog(string prompt, string caption, string initialValue, Func<string, bool> validateFunction)
: this(prompt, caption, initialValue, validateFunction, Strings.Dialog_OK, Strings.Dialog_Cancel)
{
}
/// <summary>
/// Initializes the input dialog
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="initialValue">Initial value of the input dialog</param>
/// <param name="validateFunction">Callback function which validates the inputted text</param>
/// <param name="okCaption">Caption of the 'OK' button</param>
/// <param name="cancelCaption">Caption of the 'Cancel' button</param>
public InputDialog(string prompt, string caption, string initialValue, Func<string, bool> validateFunction, string okCaption, string cancelCaption)
{
InitializeComponent();
Prompt = prompt;
Title = caption;
InputText = initialValue;
ValidateFunction = validateFunction;
OKCaption = okCaption;
CancelCaption = cancelCaption;
}
private void buttonOK_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
Close();
}
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void textInput_TextChanged(object sender, TextChangedEventArgs e)
{
Validate();
}
private void Validate()
{
bool res = true;
if (ValidateFunction != null)
res = ValidateFunction(textInput.Text);
buttonOK.IsEnabled = res;
}
#region Static show
/// <summary>
/// Shows a dialog prompting the user for input
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <returns>Input text, or null if canceled</returns>
public static string Show(string prompt)
{
return ShowCommon(new InputDialog(prompt));
}
/// <summary>
/// Shows a dialog prompting the user for input
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <returns>Input text, or null if canceled</returns>
public static string Show(string prompt, string caption)
{
return ShowCommon(new InputDialog(prompt, caption));
}
/// <summary>
/// Shows a dialog prompting the user for input
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="okCaption">Caption of the 'OK' button</param>
/// <param name="cancelCaption">Caption of the 'Cancel' button</param>
/// <returns>Input text, or null if canceled</returns>
public static string Show(string prompt, string caption, string okCaption, string cancelCaption)
{
return ShowCommon(new InputDialog(prompt, caption, okCaption, cancelCaption));
}
/// <summary>
/// Shows a dialog prompting the user for input
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="validateFunction">Callback function which validates the inputted text</param>
/// <returns>Input text, or null if canceled</returns>
public static string Show(string prompt, string caption, Func<string, bool> validateFunction)
{
return ShowCommon(new InputDialog(prompt, caption, validateFunction));
}
/// <summary>
/// Shows a dialog prompting the user for input
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="validateFunction">Callback function which validates the inputted text</param>
/// <param name="okCaption">Caption of the 'OK' button</param>
/// <param name="cancelCaption">Caption of the 'Cancel' button</param>
/// <returns>Input text, or null if canceled</returns>
public static string Show(string prompt, string caption, Func<string, bool> validateFunction, string okCaption, string cancelCaption)
{
return ShowCommon(new InputDialog(prompt, caption, validateFunction, okCaption, cancelCaption));
}
/// <summary>
/// Shows a dialog prompting the user for input
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="initialValue">Initial value of the input dialog</param>
/// <returns>Input text, or null if canceled</returns>
public static string Show(string prompt, string caption, string initialValue)
{
return ShowCommon(new InputDialog(prompt, caption, initialValue));
}
/// <summary>
/// Shows a dialog prompting the user for input
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="initialValue">Initial value of the input dialog</param>
/// <param name="okCaption">Caption of the 'OK' button</param>
/// <param name="cancelCaption">Caption of the 'Cancel' button</param>
/// <returns>Input text, or null if canceled</returns>
public static string Show(string prompt, string caption, string initialValue, string okCaption, string cancelCaption)
{
return ShowCommon(new InputDialog(prompt, caption, initialValue, okCaption, cancelCaption));
}
/// <summary>
/// Shows a dialog prompting the user for input
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="initialValue">Initial value of the input dialog</param>
/// <param name="validateFunction">Callback function which validates the inputted text</param>
/// <returns>Input text, or null if canceled</returns>
public static string Show(string prompt, string caption, string initialValue, Func<string, bool> validateFunction)
{
return ShowCommon(new InputDialog(prompt, caption, initialValue, validateFunction));
}
/// <summary>
/// Shows a dialog prompting the user for input
/// </summary>
/// <param name="prompt">Message displayed to user</param>
/// <param name="caption">Title of dialog</param>
/// <param name="initialValue">Initial value of the input dialog</param>
/// <param name="validateFunction">Callback function which validates the inputted text</param>
/// <param name="okCaption">Caption of the 'OK' button</param>
/// <param name="cancelCaption">Caption of the 'Cancel' button</param>
/// <returns>Input text, or null if canceled</returns>
public static string Show(string prompt, string caption, string initialValue, Func<string, bool> validateFunction, string okCaption, string cancelCaption)
{
return ShowCommon(new InputDialog(prompt, caption, initialValue, validateFunction, okCaption, cancelCaption));
}
private static string ShowCommon(InputDialog dialog)
{
bool? res = dialog.ShowDialog();
if (res.HasValue && res.Value)
{
return dialog.InputText;
}
return null;
}
#endregion
}
}

View File

@ -34,13 +34,15 @@
<MenuItem Header="{x:Static r:Strings.MainWindow_File}">
<MenuItem Header="{x:Static r:Strings.MainWindow_File_New}">
<MenuItem DataContext="{Binding DocumentController.DocumentCreateCommand}"
Style="{StaticResource CommandMenuItemStyle}" >
Style="{StaticResource CommandMenuItemStyle}"
Header="{x:Static r:Strings.Command_DocumentCreate_AltDisplayText}">
<MenuItem.Icon>
<Image Source="{Binding Icon}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem DataContext="{Binding ProjectController.ProjectCreateCommand}"
Style="{StaticResource CommandMenuItemStyle}">
Style="{StaticResource CommandMenuItemStyle}"
Header="{x:Static r:Strings.Command_ProjectCreate_AltDisplayText}">
<MenuItem.Icon>
<Image Source="{Binding Icon}" />
</MenuItem.Icon>
@ -49,13 +51,15 @@
<Separator />
<MenuItem Header="{x:Static r:Strings.MainWindow_File_Open}">
<MenuItem DataContext="{Binding DocumentController.DocumentOpenCommand}"
Style="{StaticResource CommandMenuItemStyle}">
Style="{StaticResource CommandMenuItemStyle}"
Header="{x:Static r:Strings.Command_DocumentOpen_AltDisplayText}">
<MenuItem.Icon>
<Image Source="{Binding Icon}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem DataContext="{Binding ProjectController.ProjectOpenCommand}"
Style="{StaticResource CommandMenuItemStyle}">
Style="{StaticResource CommandMenuItemStyle}"
Header="{x:Static r:Strings.Command_ProjectOpen_AltDisplayText}">
<MenuItem.Icon>
<Image Source="{Binding Icon}" />
</MenuItem.Icon>

View File

@ -55,7 +55,8 @@ namespace RainmeterStudio.UI
DocumentController.DocumentOpened += documentController_DocumentOpened;
// Initialize panels
projectPanel.Controller = ProjectController;
projectPanel.ProjectController = ProjectController;
projectPanel.DocumentController = DocumentController;
}
void documentController_DocumentOpened(object sender, DocumentOpenedEventArgs e)

View File

@ -44,12 +44,15 @@
<!-- Project item tree -->
<TreeView Grid.Row="2" Name="treeProjectItems">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<EventSetter Event="Expanded" Handler="TreeViewItem_ExpandedOrCollapsed" />
<EventSetter Event="Collapsed" Handler="TreeViewItem_ExpandedOrCollapsed" />
<EventSetter Event="PreviewMouseRightButtonDown" Handler="TreeViewItem_PreviewMouseRightButtonDown" />
<EventSetter Event="PreviewMouseDoubleClick" Handler="TreeViewItem_PreviewMouseDoubleClick" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>

View File

@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using RainmeterStudio.Core.Model;
using RainmeterStudio.Core.Utils;
using RainmeterStudio.UI.Controller;
@ -13,28 +16,31 @@ namespace RainmeterStudio.UI.Panels
/// </summary>
public partial class ProjectPanel : UserControl
{
private ProjectController _controller;
public ProjectController Controller
private ProjectController _projectController;
public ProjectController ProjectController
{
get
{
return _controller;
return _projectController;
}
set
{
// Unsubscribe from old controller
if (_controller != null)
if (_projectController != null)
{
Controller.ActiveProjectChanged -= Controller_ActiveProjectChanged;
ProjectController.ActiveProjectChanged -= Controller_ActiveProjectChanged;
}
// Set new project
_controller = value;
_controller.ActiveProjectChanged += Controller_ActiveProjectChanged;
_projectController = value;
_projectController.ActiveProjectChanged += Controller_ActiveProjectChanged;
Refresh();
}
}
public DocumentController DocumentController { get; set; }
#region Commands
public Command SyncWithActiveViewCommand { get; private set; }
@ -60,7 +66,7 @@ namespace RainmeterStudio.UI.Panels
if (selected == null)
{
return Controller.ActiveProject.Root;
return ProjectController.ActiveProject.Root;
}
else
{
@ -85,7 +91,6 @@ namespace RainmeterStudio.UI.Panels
}
}
public ProjectPanel()
{
InitializeComponent();
@ -116,7 +121,7 @@ namespace RainmeterStudio.UI.Panels
treeProjectItems.Items.Clear();
// No project
if (Controller == null || Controller.ActiveProject == null)
if (ProjectController == null || ProjectController.ActiveProject == null)
{
this.IsEnabled = false;
}
@ -130,14 +135,14 @@ namespace RainmeterStudio.UI.Panels
if (toggleShowAllFiles.IsChecked.HasValue && toggleShowAllFiles.IsChecked.Value)
{
// Get directory name
string projectFolder = System.IO.Path.GetDirectoryName(Controller.ActiveProjectPath);
string projectFolder = System.IO.Path.GetDirectoryName(ProjectController.ActiveProjectPath);
// Get folder tree
refTree = DirectoryHelper.GetFolderTree(projectFolder);
}
else
{
refTree = Controller.ActiveProject.Root;
refTree = ProjectController.ActiveProject.Root;
}
// Add tree to tree view
@ -183,5 +188,106 @@ namespace RainmeterStudio.UI.Panels
// We can expand if the root is not expanded
CanExpand = (!tree.IsExpanded);
}
private void TreeViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
var treeViewItem = sender as TreeViewItem;
var referenceViewModel = treeViewItem.Header as ReferenceViewModel;
if (referenceViewModel != null)
{
treeViewItem.ContextMenu = new ContextMenu();
treeViewItem.ContextMenu.ItemsSource = GetContextMenuItems(referenceViewModel.Reference);
}
}
private void TreeViewItem_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var treeViewItem = sender as TreeViewItem;
var refViewModel = treeViewItem.Header as ReferenceViewModel;
if (refViewModel != null)
{
Command command = GetDefaultCommand(refViewModel.Reference);
command.Execute(refViewModel.Reference);
}
}
/// <summary>
/// Gets the default command (double click) for a specific reference
/// </summary>
/// <param name="reference">The reference</param>
/// <returns>The command</returns>
public Command GetDefaultCommand(Reference reference)
{
switch (reference.TargetKind)
{
case ReferenceTargetKind.File:
return DocumentController.DocumentOpenCommand;
case ReferenceTargetKind.Project:
return DocumentController.DocumentOpenCommand;
case ReferenceTargetKind.Directory:
return null; // TODO: expand command
default:
return null;
}
}
private MenuItem GetMenuItem(Command cmd, Reference reference)
{
var icon = new Image();
icon.Source = cmd.Icon;
icon.Width = 16;
icon.Height = 16;
var menuItem = new MenuItem();
menuItem.DataContext = cmd;
menuItem.Style = Application.Current.TryFindResource("CommandContextMenuItemStyle") as Style;
menuItem.Icon = icon;
menuItem.CommandParameter = reference;
if (GetDefaultCommand(reference) == cmd)
menuItem.FontWeight = FontWeights.Bold;
return menuItem;
}
public IEnumerable<UIElement> GetContextMenuItems(Reference @ref)
{
if (@ref.TargetKind == ReferenceTargetKind.File || @ref.TargetKind == ReferenceTargetKind.Project)
{
yield return GetMenuItem(DocumentController.DocumentOpenCommand, @ref);
}
if (@ref.TargetKind == ReferenceTargetKind.Directory || @ref.TargetKind == ReferenceTargetKind.Project)
{
// TODO: expand command
}
yield return new Separator();
if (@ref.TargetKind != ReferenceTargetKind.Project)
{
yield return GetMenuItem(ProjectController.ProjectItemCutCommand, @ref);
yield return GetMenuItem(ProjectController.ProjectItemCopyCommand, @ref);
if (@ref.TargetKind == ReferenceTargetKind.Directory)
yield return GetMenuItem(ProjectController.ProjectItemPasteCommand, @ref);
}
yield return GetMenuItem(ProjectController.ProjectItemRenameCommand, @ref);
if (@ref.TargetKind != ReferenceTargetKind.Project)
yield return GetMenuItem(ProjectController.ProjectItemDeleteCommand, @ref);
yield return new Separator();
if (@ref.TargetKind == ReferenceTargetKind.Directory)
yield return GetMenuItem(ProjectController.ProjectItemOpenInExplorerCommand, @ref);
else
yield return GetMenuItem(ProjectController.ProjectItemOpenContainingFolderCommand, @ref);
}
}
}