Skip to content

Commit a4247f9

Browse files
committed
Add UI for RenameFolder
1 parent 126ffa4 commit a4247f9

File tree

11 files changed

+559
-6
lines changed

11 files changed

+559
-6
lines changed

Rubberduck.Core/Rubberduck.Core.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@
126126
<Compile Update="UI\Refactorings\MoveToFolder\MoveMultipleToFolderView.xaml.cs">
127127
<DependentUpon>MoveMultipleToFolderView.xaml</DependentUpon>
128128
</Compile>
129+
<Compile Update="UI\Refactorings\RenameFolder\RenameFolderView.xaml.cs">
130+
<DependentUpon>RenameFolderView.xaml</DependentUpon>
131+
</Compile>
129132
</ItemGroup>
130133
<ItemGroup>
131134
<EmbeddedResource Update="Properties\Resources.resx">
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Rubberduck.Refactorings.RenameFolder;
2+
using Rubberduck.Resources;
3+
4+
namespace Rubberduck.UI.Refactorings.RenameFolder
5+
{
6+
public class RenameFolderPresenter : RefactoringPresenterBase<RenameFolderModel>, IRenameFolderPresenter
7+
{
8+
private static readonly DialogData DialogData = DialogData.Create(RubberduckUI.RenameDialog_Caption, 164, 684);
9+
10+
public RenameFolderPresenter(RenameFolderModel model, IRefactoringDialogFactory dialogFactory) :
11+
base(DialogData, model, dialogFactory)
12+
{ }
13+
}
14+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<UserControl x:Class="Rubberduck.UI.Refactorings.RenameFolder.RenameFolderView"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
mc:Ignorable="d"
7+
d:DesignHeight="300" d:DesignWidth="300">
8+
<UserControl.Resources>
9+
<ResourceDictionary>
10+
<ResourceDictionary.MergedDictionaries>
11+
<ResourceDictionary Source="../../Controls/ToolBar.xaml"/>
12+
</ResourceDictionary.MergedDictionaries>
13+
</ResourceDictionary>
14+
</UserControl.Resources>
15+
<Grid>
16+
<Grid.RowDefinitions>
17+
<RowDefinition Height="50" />
18+
<RowDefinition Height="auto" />
19+
<RowDefinition Height="*" />
20+
<RowDefinition Height="40" />
21+
</Grid.RowDefinitions>
22+
<StackPanel Background="{StaticResource BackgroundLightBrush}">
23+
<Label Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=RenameDialog_TitleText_Folder}" FontWeight="Bold" />
24+
<TextBlock Text="{Binding Instructions}" Margin="5,0" />
25+
</StackPanel>
26+
<Grid Grid.Row="1" Margin="5,10,10,5">
27+
<Grid.ColumnDefinitions>
28+
<ColumnDefinition Width="auto" />
29+
<ColumnDefinition Width="*" />
30+
</Grid.ColumnDefinitions>
31+
<TextBlock Text="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=RenameDialog_FolderLabel}"
32+
VerticalAlignment="Top"
33+
Margin="0,0,5,0" />
34+
<TextBox Name="RenameFolderTextBox"
35+
Grid.Column="1"
36+
Style="{StaticResource TextBoxErrorStyle}"
37+
Text="{Binding NewFolderName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
38+
Height="22"
39+
VerticalAlignment="Top"
40+
VerticalContentAlignment="Center"
41+
HorizontalAlignment="Stretch" />
42+
</Grid>
43+
<StackPanel Grid.Row="2"
44+
Margin="5,10,10,5"
45+
Orientation="Horizontal">
46+
<TextBlock Text="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=FullNewFolderLabel}"
47+
VerticalAlignment="Top"
48+
Margin="0,0,5,0" />
49+
<TextBlock Text="{Binding FullNewFolderName}"
50+
VerticalAlignment="Top"/>
51+
</StackPanel>
52+
<Grid Grid.Row="3" Background="{x:Static SystemColors.ControlDarkBrush}" Grid.IsSharedSizeScope="True">
53+
<Grid HorizontalAlignment="Right"
54+
Margin="5,0">
55+
<Grid.ColumnDefinitions>
56+
<ColumnDefinition SharedSizeGroup="SettingsButtons" />
57+
<ColumnDefinition SharedSizeGroup="SettingsButtons" />
58+
</Grid.ColumnDefinitions>
59+
<Button Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=OK}"
60+
Grid.Column="0"
61+
Height="20"
62+
Margin="5,0"
63+
Padding="10,0"
64+
IsEnabled="{Binding IsValidFolder}"
65+
IsDefault="True"
66+
Command="{Binding OkButtonCommand}" />
67+
<Button Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=CancelButtonText}"
68+
Grid.Column="1"
69+
Height="20"
70+
Margin="5,0"
71+
Padding="10,0"
72+
IsCancel="True"
73+
Command="{Binding CancelButtonCommand}">
74+
</Button>
75+
</Grid>
76+
</Grid>
77+
</Grid>
78+
</UserControl>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Windows;
2+
using Rubberduck.Refactorings;
3+
4+
namespace Rubberduck.UI.Refactorings.RenameFolder
5+
{
6+
public partial class RenameFolderView : IRefactoringView<RenameFolderView>
7+
{
8+
public RenameFolderView()
9+
{
10+
InitializeComponent();
11+
12+
Loaded += AfterLoadHandler;
13+
}
14+
15+
private void AfterLoadHandler(object sender, RoutedEventArgs e)
16+
{
17+
RenameFolderTextBox.Focus();
18+
RenameFolderTextBox.SelectAll();
19+
Loaded -= AfterLoadHandler;
20+
}
21+
}
22+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Rubberduck.Interaction;
4+
using Rubberduck.JunkDrawer.Extensions;
5+
using Rubberduck.Parsing.Symbols;
6+
using Rubberduck.Parsing.VBA;
7+
using Rubberduck.Refactorings.RenameFolder;
8+
using Rubberduck.Resources;
9+
10+
namespace Rubberduck.UI.Refactorings.RenameFolder
11+
{
12+
public class RenameFolderViewModel : RefactoringViewModelBase<RenameFolderModel>
13+
{
14+
private readonly IDeclarationFinderProvider _declarationFinderProvider;
15+
private readonly IMessageBox _messageBox;
16+
17+
public RenameFolderViewModel(RenameFolderModel model, IMessageBox messageBox, IDeclarationFinderProvider declarationFinderProvider)
18+
: base(model)
19+
{
20+
_declarationFinderProvider = declarationFinderProvider;
21+
_messageBox = messageBox;
22+
}
23+
24+
public string Instructions
25+
{
26+
get
27+
{
28+
if (string.IsNullOrEmpty(Model?.OriginalFolder))
29+
{
30+
return string.Empty;
31+
}
32+
33+
var folderToRename = Model.OriginalFolder;
34+
35+
return string.Format(
36+
RubberduckUI.RenameDialog_InstructionsLabelText,
37+
folderToRename,
38+
RubberduckUI.RenameDialog_Folder);
39+
}
40+
}
41+
42+
public string NewFolderName
43+
{
44+
get => Model.NewSubFolder;
45+
set
46+
{
47+
Model.NewSubFolder = value;
48+
ValidateFolder();
49+
OnPropertyChanged();
50+
OnPropertyChanged(nameof(IsValidFolder));
51+
OnPropertyChanged(nameof(FullNewFolderName));
52+
}
53+
}
54+
55+
public string FullNewFolderName => Model.OriginalFolder.Contains(FolderExtensions.FolderDelimiter)
56+
? $"{Model.OriginalFolder.ParentFolder()}{FolderExtensions.FolderDelimiter}{NewFolderName}"
57+
: NewFolderName;
58+
59+
private void ValidateFolder()
60+
{
61+
var errors = new List<string>();
62+
63+
if (string.IsNullOrEmpty(NewFolderName))
64+
{
65+
//We generally already rename a subfolder, here.
66+
errors.Add(RubberduckUI.MoveFolders_EmptySubfolderName);
67+
}
68+
else
69+
{
70+
if (NewFolderName.Any(char.IsControl))
71+
{
72+
errors.Add(RubberduckUI.MoveFolders_ControlCharacter);
73+
}
74+
75+
if (NewFolderName.Split(FolderExtensions.FolderDelimiter).Any(string.IsNullOrEmpty))
76+
{
77+
errors.Add(RubberduckUI.MoveFolders_EmptySubfolderName);
78+
}
79+
}
80+
81+
if (errors.Any())
82+
{
83+
SetErrors(nameof(NewFolderName), errors);
84+
}
85+
else
86+
{
87+
ClearErrors();
88+
}
89+
}
90+
91+
public bool IsValidFolder => Model?.ModulesToMove != null
92+
&& Model.ModulesToMove.Any()
93+
&& !HasErrors;
94+
95+
protected override void DialogOk()
96+
{
97+
if (Model?.ModulesToMove == null
98+
|| !Model.ModulesToMove.Any()
99+
|| !Model.SubFolderToRename.Equals(Model.NewSubFolder)
100+
&& FolderAlreadyExists(FullNewFolderName)
101+
&& !UserConfirmsToProceedWithFolderMerge(FullNewFolderName, Model.SubFolderToRename, NewFolderName))
102+
{
103+
base.DialogCancel();
104+
}
105+
else
106+
{
107+
base.DialogOk();
108+
}
109+
}
110+
111+
private bool FolderAlreadyExists(string fullFolderName)
112+
{
113+
return _declarationFinderProvider.DeclarationFinder
114+
.UserDeclarations(DeclarationType.Module)
115+
.OfType<ModuleDeclaration>()
116+
.Select(module => module.CustomFolder)
117+
.Any(folder => folder.Equals(fullFolderName)
118+
|| folder.IsSubFolderOf(fullFolderName));
119+
}
120+
121+
private bool UserConfirmsToProceedWithFolderMerge(string fullTargetFolder, string partToRename, string newFolderPart)
122+
{
123+
var message = string.Format(
124+
RubberduckUI.RenameDialog_FolderAlreadyExists,
125+
fullTargetFolder,
126+
partToRename,
127+
newFolderPart);
128+
return _messageBox?.ConfirmYesNo(message, RubberduckUI.RenameDialog_Caption) ?? false;
129+
}
130+
}
131+
}

Rubberduck.Resources/RubberduckUI.Designer.cs

Lines changed: 47 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Rubberduck.Resources/RubberduckUI.de.resx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,4 +1706,20 @@ Wollen Sie fortfahren?</value>
17061706
<data name="MoveFolders_EmptySubfolderName" xml:space="preserve">
17071707
<value>Die Namen individueller Unterordner dürfen nicht leer sein.</value>
17081708
</data>
1709+
<data name="RenameDialog_Folder" xml:space="preserve">
1710+
<value>Ordner</value>
1711+
</data>
1712+
<data name="RenameDialog_FolderAlreadyExists" xml:space="preserve">
1713+
<value>Der Ordner '{0}' existiert bereits. '{1}' in '{2}. umzubenennen wird die Ordner verschmelzen.
1714+
Wollen Sie fortfahren?</value>
1715+
</data>
1716+
<data name="RenameDialog_FolderLabel" xml:space="preserve">
1717+
<value>Ordner:</value>
1718+
</data>
1719+
<data name="RenameDialog_FullNewFolderLabel" xml:space="preserve">
1720+
<value>Kompletter Ordnername:</value>
1721+
</data>
1722+
<data name="RenameDialog_TitleText_Folder" xml:space="preserve">
1723+
<value>Ordner umbenennen</value>
1724+
</data>
17091725
</root>

Rubberduck.Resources/RubberduckUI.resx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1496,7 +1496,7 @@ NOTE: Restart is required for the setting to take effect.</value>
14961496
<comment>{0}: Variable Name</comment>
14971497
</data>
14981498
<data name="MoveCloserToUsageFailure_TargetIsInOtherNonStandardModule" xml:space="preserve">
1499-
<value>'{0}' is defined neither in the component component it is used nor in a standard module. </value>
1499+
<value>'{0}' is defined neither in the component component it is used nor in a standard module.</value>
15001500
<comment>{0}: Variable Name</comment>
15011501
</data>
15021502
<data name="MoveCloserToUsageFailure_TargetIsNonPrivateInNonStandardModule" xml:space="preserve">
@@ -1923,4 +1923,21 @@ Do you want to proceed?</value>
19231923
<data name="MoveFolders_EmptySubfolderName" xml:space="preserve">
19241924
<value>The names of individual subfolders cannot be empty.</value>
19251925
</data>
1926+
<data name="RenameDialog_Folder" xml:space="preserve">
1927+
<value>folder</value>
1928+
</data>
1929+
<data name="RenameDialog_FolderAlreadyExists" xml:space="preserve">
1930+
<value>The folder '{0}' already exists. Renaming '{1}' to '{2}' will lead to a merge with the existing folder.
1931+
Do you want to proceed?</value>
1932+
<comment>{0} new full folder name; {1} folder part to rename; {2} new folder part name</comment>
1933+
</data>
1934+
<data name="RenameDialog_FolderLabel" xml:space="preserve">
1935+
<value>Folder:</value>
1936+
</data>
1937+
<data name="RenameDialog_FullNewFolderLabel" xml:space="preserve">
1938+
<value>Full new folder:</value>
1939+
</data>
1940+
<data name="RenameDialog_TitleText_Folder" xml:space="preserve">
1941+
<value>Rename folder</value>
1942+
</data>
19261943
</root>

RubberduckTests/Refactoring/MoveFolders/MoveMultipleFoldersViewModelTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
using System;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
32
using System.Linq;
4-
using Castle.Core.Smtp;
53
using Moq;
64
using NUnit.Framework;
75
using Rubberduck.Interaction;

0 commit comments

Comments
 (0)