Compare commits

...

20 Commits

Author SHA1 Message Date
eb4ef3f092 Delete '.gitlab-ci.yml' 2022-02-09 19:23:29 +00:00
a358e557c3 Update 'README.md' 2022-02-09 19:18:58 +00:00
Adrian Schlett
3919c185a8 Update README.md 2022-01-21 21:09:47 +00:00
Adrian Schlett
cd84ba89ce Update README.md 2022-01-21 20:59:37 +00:00
adroslice
18a2d7154f Improved Drag+Drop & Dark Mode testing
- Drag+Drop now shows a black line where the item is going to be dropped as an additional visual cue to make it more intuitive
- Avalonia's dark default style is lacking two things:
-- Highlights on ListBoxItem are too bright (easy fix)
-- The window decoration remains white (could be disabled and replaced with custom title bar)
2019-12-03 20:12:00 +01:00
adroslice
e107be13c4 Fixed #12 2019-12-01 20:16:46 +01:00
adroslice
4119cb9eac Added pre-sorting
- Pre-sorting uses ascending natural sorting
- Previously, the files would initially be displayed in the order the operating system returned
2019-12-01 20:10:47 +01:00
adroslice
10153a9bd2 Attempt to fix File Path handling
- Now uses unix standard frontslashes for directories internally
- Converts the backslashes windows returns to frontslashes
- Changed default paths
2019-12-01 17:05:00 +01:00
adroslice
3545afad51 UI Overhaul
- You can now Drag-Drop re-order operations
- The delete buttons are now on the operations themselves
- These two together mean that you now dont have to (and cant) select operations anymore
- Added ability to view the path on a filename in the before- and after-lists
- Also updated Avalonia to preview8
2019-12-01 14:08:01 +01:00
Adrian Schlett
18f3c6f70d Update README.md
- Removed upcoming feature that was added
2019-11-24 02:30:05 +00:00
adroslice
00b4f26a3d Fixed Natural Sorting causing an infinite loop 2019-11-24 02:45:09 +01:00
adroslice
0d56d66809 Added Tooltips, minor improvements/fixes 2019-11-24 01:16:34 +01:00
Adrian Schlett
845723dbc7 Update README.md 2019-11-23 23:26:48 +00:00
Adrian Schlett
dbc1c9abec Update README.md
- Shorter links using relative paths
2019-11-23 22:58:05 +00:00
Adrian Schlett
2bc6f79e8c Update README.md
- Linked every issue related to an upcoming feature
2019-11-23 22:52:03 +00:00
Adrian Schlett
89637d0069 Update README.md 2019-11-23 21:36:34 +00:00
Adrian Schlett
f55f439597 Update README.md 2019-11-23 21:23:44 +00:00
Adrian Schlett
530378aac3 Update README.md
- Fixed Link
2019-11-23 21:01:25 +00:00
Adrian Schlett
f32b3454d8 Update README.md
- Added Upcoming Features
- Fixed Typo
2019-11-23 20:59:58 +00:00
Adrian Schlett
33497f3d16 Update README.md 2019-11-23 20:15:04 +00:00
7 changed files with 214 additions and 129 deletions

View File

@ -1,8 +0,0 @@
image: ilyasemenov/gitlab-ci-git-push
stages:
- deploy
deploy to production:
stage: deploy
script: git-push git@github.com:adroslice/bfr.git

View File

@ -12,7 +12,7 @@
</AvaloniaResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.9.0-preview7" />
<PackageReference Include="Avalonia.Desktop" Version="0.9.0-preview7" />
<PackageReference Include="Avalonia" Version="0.9.0-preview8" />
<PackageReference Include="Avalonia.Desktop" Version="0.9.0-preview8" />
</ItemGroup>
</Project>

View File

@ -11,20 +11,20 @@
<!-- Directory Selection + Filters -->
<Border Grid.Row="0" Grid.ColumnSpan="3">
<Grid RowDefinitions="*,auto" ColumnDefinitions="auto,*,auto">
<Expander Grid.Column="0" Name="FilterExpander" Header="Filter"/>
<Expander Grid.Column="0" Name="FilterExpander" Header="Filter" ToolTip.Tip="Various options for filtering the files to be modified."/>
<TextBox Grid.Column="1" IsEnabled="False" Text="{Binding WorkingDirectory}"/>
<Button Grid.Column="2" Content=" ... " Command="{Binding OpenDirectoryButtonClick}"/>
<Button Grid.Column="2" Content=" ... " Command="{Binding OpenDirectoryButtonClick}" ToolTip.Tip="Loads all files from a specific folder."/>
<!-- Filters -->
<Grid Grid.Row="1" Grid.ColumnSpan="3" ColumnDefinitions="auto,*,auto,*,auto,auto,auto,auto" IsVisible="{Binding #FilterExpander.IsExpanded}">
<TextBlock Grid.Column="0" Text="Extension:"/>
<TextBox Grid.Column="1" Text="{Binding FilterExtension}" PropertyChanged="FilterChanged"/>
<TextBox Grid.Column="1" Text="{Binding FilterExtension}" PropertyChanged="FilterChanged" ToolTip.Tip="Matches the file extension *exactly*."/>
<TextBlock Grid.Column="2" Text="Name:"/>
<TextBox Grid.Column="3" Text="{Binding FilterPattern}" PropertyChanged="FilterChanged"/>
<TextBox Grid.Column="3" Text="{Binding FilterPattern}" PropertyChanged="FilterChanged" ToolTip.Tip="Matches against a part of the file name."/>
<TextBlock Grid.Column="4" Text="Full Name:"/>
<CheckBox Grid.Column="5" IsChecked="{Binding FilterFullName}" PropertyChanged="FilterChanged"/>
<CheckBox Grid.Column="5" IsChecked="{Binding FilterFullName}" PropertyChanged="FilterChanged" ToolTip.Tip="Whether to include the file extension."/>
<TextBlock Grid.Column="6" Text="Regex:"/>
<CheckBox Grid.Column="7" IsChecked="{Binding FilterRegex}" PropertyChanged="FilterChanged" Margin="4,4,5,4"/>
<CheckBox Grid.Column="7" IsChecked="{Binding FilterRegex}" PropertyChanged="FilterChanged" Margin="4,4,5,4" ToolTip.Tip="Whether to match using RegEx."/>
</Grid>
</Grid>
</Border>
@ -35,17 +35,17 @@
<TextBox Classes="HeaderTextBox" Grid.Row="1" Grid.Column="2" Text="After"/>
<!-- Current and Preview ListBoxes -->
<ListBox Grid.Row="2" Grid.Column="0" Items="{Binding Files}" IsEnabled="False">
<ListBox Grid.Row="2" Grid.Column="0" Items="{Binding Files}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding OldFullName}"/>
<TextBlock Text="{Binding OldFullName}" ToolTip.Tip="{Binding OldPath}" Background="Transparent"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Grid.Row="2" Grid.Column="2" Items="{Binding Files}" IsEnabled="False">
<ListBox Grid.Row="2" Grid.Column="2" Items="{Binding Files}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FullName}"/>
<TextBlock Text="{Binding FullName}" ToolTip.Tip="{Binding Path}" Background="Transparent"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
@ -55,22 +55,19 @@
<!-- Operations ListBox -->
<ListBox Grid.Row="0" Items="{Binding Operations}" Name="OperationsListBox" SelectedIndex="{Binding SelectedOperation}"/>
<!-- Operations Controls -->
<!-- Add Operation -->
<Border Grid.Row="1" Classes="ConnectUp">
<Grid ColumnDefinitions="auto,*,auto,auto,auto">
<TextBlock Grid.Column="0" Text="New:"/>
<ComboBox Grid.Column="1" Items="{Binding OperationTypes}" SelectedIndex="{Binding SelectedOperationType}"/>
<Button Grid.Column="2" Content=" + " Command="{Binding AddOperation}"/>
<Button Grid.Column="3" Content=" - " Command="{Binding RemoveOperation}"/>
<ButtonSpinner Grid.Column="4" Spin="MoveOperation"/>
<Grid ColumnDefinitions="*,auto">
<ComboBox Grid.Column="0" Items="{Binding OperationTypes}" SelectedIndex="{Binding SelectedOperationType}" ToolTip.Tip="The type of the operation to add."/>
<Button Grid.Column="1" Content="Add" Command="{Binding AddOperation}" ToolTip.Tip="Adds a new operation after the one selected (or at the end)."/>
</Grid>
</Border>
<!-- Commit and Undo Buttons -->
<Border Grid.Row="2" Classes="ConnectUp">
<Grid ColumnDefinitions="*,*">
<Button Grid.Column="0" Content="Undo" Command="{Binding Undo}" IsEnabled="{Binding !!UndoCount}"/>
<Button Grid.Column="1" Content="Rename All" Command="{Binding Commit}" IsEnabled="{Binding IsCommitButtonEnabled}"/>
<Button Grid.Column="0" Content="Undo" Command="{Binding Undo}" IsEnabled="{Binding !!UndoCount}" ToolTip.Tip="Undoes the last operation. Works multiple times."/>
<Button Grid.Column="1" Content="Rename All" Command="{Binding Commit}" IsEnabled="{Binding IsCommitButtonEnabled}" ToolTip.Tip="Renames all the files according to the preview. This button is disabled if the preview is invalid."/>
</Grid>
</Border>
</Grid>
@ -117,6 +114,7 @@
<Setter Property="Margin" Value="4,4,4,-5"/>
<Setter Property="TextAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="IsEnabled" Value="False"/>
</Style>
<Style Selector="Grid.StyleBorders > Border">
<Setter Property="Margin" Value="4"/>
@ -128,19 +126,58 @@
<Setter Property="Margin" Value="4,-5,4,4"/>
</Style>
<!-- Operation Styles -->
<Style Selector="Expander.OperationExpander">
<Setter Property="Header">
<Template>
<Grid ColumnDefinitions="auto,*,auto">
<CheckBox Grid.Column="0" Margin="0,0,8,0" IsChecked="{Binding IsEnabled}" Command="{Binding $parent[6].DataContext.Preview}"/>
<TextBlock Grid.Column="1" Margin="0,0,8,0" Text="{Binding Name}"/>
<Grid Grid.Column="2" ToolTip.Tip="{Binding Error}" IsVisible="{Binding !!Error.Length}">
<!-- Drag + Drop -->
<Style Selector="ListBoxItem.BlackBottom">
<Setter Property="BorderThickness" Value="0,0,0,2"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Margin" Value="0,0,0,-2"/>
</Style>
<Style Selector="ListBoxItem.BlackTop">
<Setter Property="BorderThickness" Value="0,2,0,0"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Margin" Value="0,-2,0,0"/>
</Style>
<!-- Expander Fix -->
<Style Selector="Expander /template/ ToggleButton#PART_toggle /template/ Border">
<Setter Property="Background" Value="Transparent"/>
</Style>
<!-- List Destyling -->
<Style Selector="ListBoxItem:not(:pointerover):selected /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="ListBoxItem:pointerover:selected /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
</Style>
<!-- Operation Control (Wrapper) -->
<Style Selector="ContentControl.OperationControl">
<Setter Property="Template">
<ControlTemplate>
<Grid ColumnDefinitions="*,auto,auto,auto" RowDefinitions="auto,auto" Name="OperationGrid" Margin="0" Background="Transparent">
<Expander Grid.Column="0" Name="OperationExpander" Margin="0">
<Expander.Header>
<CheckBox Margin="0" Content="{Binding Name}" IsChecked="{Binding IsEnabled}" PropertyChanged="PreviewChanged"/>
</Expander.Header>
</Expander>
<Grid Grid.Column="1" ToolTip.Tip="{Binding Error}" IsVisible="{Binding !!Error.Length}" Background="Transparent">
<Ellipse Width="18" Height="18" Margin="0" Stroke="DarkRed" StrokeThickness="2"/>
<TextBlock Width="18" Height="18" Margin="0" Foreground="DarkRed" Text="!" FontWeight="Black" TextAlignment="Center"/>
</Grid>
<Button Grid.Column="2" Background="Transparent" VerticalAlignment="Center" BorderBrush="Transparent" IsVisible="{Binding $parent.IsPointerOver}" ToolTip.Tip="Click to delete this operation." Padding="0">
<Button.Content>
<Grid Width="16" Height="16" Background="Transparent" PointerReleased="DeleteOperation">
<Path Data="M0,0 L8,8 M0,8 L8,0" Stroke="Black" StrokeThickness="2" Height="8" HorizontalAlignment="Center"/>
</Grid>
</Button.Content>
</Button>
<Grid Grid.Column="3" Background="Transparent" Cursor="SizeAll" IsVisible="{Binding $parent.IsPointerOver}" ToolTip.Tip="Click and drag to move this operation." PointerPressed="StartMoveOperation" PointerReleased="EndMoveOperation" PointerMoved="MoveOperation">
<Path Data="M0,0 L12,0 M0,4 L12,4 M0,8 L12,8" Height="8" VerticalAlignment="Center" Margin="4" Stroke="Black" StrokeThickness="2"/>
</Grid>
<ContentPresenter Grid.ColumnSpan="4" Grid.Row="1" Content="{TemplateBinding Content}" IsVisible="{Binding #OperationExpander.IsExpanded}"/>
</Grid>
</Template>
</ControlTemplate>
</Setter>
</Style>
</Window.Styles>
@ -148,155 +185,153 @@
<Window.DataTemplates>
<!-- Operation Type (For the selector) -->
<DataTemplate DataType="{x:Type ops:OperationType}">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Name}" ToolTip.Tip="{Binding Description}"/>
</DataTemplate>
<!-- Operations -->
<DataTemplate DataType="{x:Type ops:Overwrite}">
<Expander Classes="OperationExpander">
<ContentControl Classes="OperationControl">
<Grid ColumnDefinitions="auto,*" RowDefinitions="*,*">
<TextBlock Grid.Row="0" Text="Replacement:"/>
<TextBox Grid.Row="0" Text="{Binding Replacement}" PropertyChanged="PreviewChanged"/>
<TextBox Grid.Row="0" Text="{Binding Replacement}" PropertyChanged="PreviewChanged" ToolTip.Tip="The text to overwrite the entire file name with."/>
<TextBlock Grid.Row="1" Text="Full Name:"/>
<CheckBox Grid.Row="1" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="1" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to overwrite the file extension as well."/>
</Grid>
</Expander>
</ContentControl>
</DataTemplate>
<DataTemplate DataType="{x:Type ops:Remove}">
<Expander Classes="OperationExpander">
<ContentControl Classes="OperationControl">
<Grid ColumnDefinitions="auto,*" RowDefinitions="auto,auto,auto,auto,auto,auto,auto,auto,auto,auto,auto">
<TextBlock Grid.Row="0" Text="Mode:"/>
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged">
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged" ToolTip.Tip="How to select the parts removed.">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Name}" ToolTip.Tip="{Binding Description}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="1" Text="Pattern:" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}"/>
<TextBox Grid.Row="1" Text="{Binding Pattern}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged"/>
<TextBox Grid.Row="1" Text="{Binding Pattern}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged" ToolTip.Tip="The pattern to remove."/>
<TextBlock Grid.Row="2" Text="Characters:" IsVisible="{Binding #ModeSelector.SelectedItem.IsCharacters}"/>
<TextBox Grid.Row="2" Text="{Binding Characters}" IsVisible="{Binding #ModeSelector.SelectedItem.IsCharacters}" PropertyChanged="PreviewChanged"/>
<TextBox Grid.Row="2" Text="{Binding Characters}" IsVisible="{Binding #ModeSelector.SelectedItem.IsCharacters}" PropertyChanged="PreviewChanged" ToolTip.Tip="All the characters to remove."/>
<TextBlock Grid.Row="3" Text="From N:" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}"/>
<NumericUpDown Grid.Row="3" Value="{Binding FromN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="3" Value="{Binding FromN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}" PropertyChanged="PreviewChanged" ToolTip.Tip="Zero-based start index for the part to remove."/>
<TextBlock Grid.Row="4" Text="To N:" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}"/>
<NumericUpDown Grid.Row="4" Value="{Binding ToN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="4" Value="{Binding ToN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}" PropertyChanged="PreviewChanged" ToolTip.Tip="Zero-based end index for the part to remove."/>
<TextBlock Grid.Row="5" Text="First N:" IsVisible="{Binding #ModeSelector.SelectedItem.IsFirstN}"/>
<NumericUpDown Grid.Row="5" Value="{Binding FirstN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFirstN}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="5" Value="{Binding FirstN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFirstN}" PropertyChanged="PreviewChanged" ToolTip.Tip="The number of characters to remove at the start of the file name."/>
<TextBlock Grid.Row="6" Text="Last N:" IsVisible="{Binding #ModeSelector.SelectedItem.IsLastN}"/>
<NumericUpDown Grid.Row="6" Value="{Binding LastN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsLastN}" PropertyChanged="PreviewChanged"/>
<!--TextBlock Grid.Row="7" Text="Replacement:"/>
<TextBox Grid.Row="7" Text="{Binding Replacement}" PropertyChanged="PreviewChanged"/-->
<NumericUpDown Grid.Row="6" Value="{Binding LastN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsLastN}" PropertyChanged="PreviewChanged" ToolTip.Tip="The number of characters to remove at the end of the file name."/>
<TextBlock Grid.Row="8" Text="Regex:" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}"/>
<CheckBox Grid.Row="8" IsChecked="{Binding UseRegex}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged"/>
<TextBlock Grid.Row="9" Text="Replace Regex:" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}"/>
<CheckBox Grid.Row="9" IsChecked="{Binding UseRegexReplace}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="8" IsChecked="{Binding UseRegex}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to match using RegEx."/>
<TextBlock Grid.Row="10" Text="Full Name:"/>
<CheckBox Grid.Row="10" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="10" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to consider the file extension as well."/>
</Grid>
</Expander>
</ContentControl>
</DataTemplate>
<DataTemplate DataType="{x:Type ops:Replace}">
<Expander Classes="OperationExpander">
<ContentControl Classes="OperationControl">
<Grid ColumnDefinitions="auto,*" RowDefinitions="auto,auto,auto,auto,auto,auto,auto,auto,auto,auto,auto">
<TextBlock Grid.Row="0" Text="Mode:"/>
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged">
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged" ToolTip.Tip="How to select the parts replaced.">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Name}" ToolTip.Tip="{Binding Description}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="1" Text="Pattern:" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}"/>
<TextBox Grid.Row="1" Text="{Binding Pattern}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged"/>
<TextBox Grid.Row="1" Text="{Binding Pattern}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged" ToolTip.Tip="The pattern to replace."/>
<TextBlock Grid.Row="2" Text="Characters:" IsVisible="{Binding #ModeSelector.SelectedItem.IsCharacters}"/>
<TextBox Grid.Row="2" Text="{Binding Characters}" IsVisible="{Binding #ModeSelector.SelectedItem.IsCharacters}" PropertyChanged="PreviewChanged"/>
<TextBox Grid.Row="2" Text="{Binding Characters}" IsVisible="{Binding #ModeSelector.SelectedItem.IsCharacters}" PropertyChanged="PreviewChanged" ToolTip.Tip="All the characters to replace."/>
<TextBlock Grid.Row="3" Text="From N:" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}"/>
<NumericUpDown Grid.Row="3" Value="{Binding FromN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="3" Value="{Binding FromN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}" PropertyChanged="PreviewChanged" ToolTip.Tip="Zero-based start index for the part to replace."/>
<TextBlock Grid.Row="4" Text="To N:" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}"/>
<NumericUpDown Grid.Row="4" Value="{Binding ToN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="4" Value="{Binding ToN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFromNToN}" PropertyChanged="PreviewChanged" ToolTip.Tip="Zero-based end index for the part to replace."/>
<TextBlock Grid.Row="5" Text="First N:" IsVisible="{Binding #ModeSelector.SelectedItem.IsFirstN}"/>
<NumericUpDown Grid.Row="5" Value="{Binding FirstN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFirstN}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="5" Value="{Binding FirstN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsFirstN}" PropertyChanged="PreviewChanged" ToolTip.Tip="The number of characters to replace at the start of the file name."/>
<TextBlock Grid.Row="6" Text="Last N:" IsVisible="{Binding #ModeSelector.SelectedItem.IsLastN}"/>
<NumericUpDown Grid.Row="6" Value="{Binding LastN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsLastN}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="6" Value="{Binding LastN}" IsVisible="{Binding #ModeSelector.SelectedItem.IsLastN}" PropertyChanged="PreviewChanged" ToolTip.Tip="The number of characters to replace at the end of the file name."/>
<TextBlock Grid.Row="7" Text="Replacement:"/>
<TextBox Grid.Row="7" Text="{Binding Replacement}" PropertyChanged="PreviewChanged"/>
<TextBox Grid.Row="7" Text="{Binding Replacement}" PropertyChanged="PreviewChanged" ToolTip.Tip="The replacement to insert at the matched position/-s."/>
<TextBlock Grid.Row="8" Text="Regex:" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}"/>
<CheckBox Grid.Row="8" IsChecked="{Binding UseRegex}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="8" IsChecked="{Binding UseRegex}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to match using RegEx."/>
<TextBlock Grid.Row="9" Text="Replace Regex:" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}"/>
<CheckBox Grid.Row="9" IsChecked="{Binding UseRegexReplace}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="9" IsChecked="{Binding UseRegexReplace}" IsVisible="{Binding #ModeSelector.SelectedItem.IsPattern}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to consider Replacement as a RegEx replacement string ($)."/>
<TextBlock Grid.Row="10" Text="Full Name:"/>
<CheckBox Grid.Row="10" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="10" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to consider the file extension as well."/>
</Grid>
</Expander>
</ContentControl>
</DataTemplate>
<DataTemplate DataType="{x:Type ops:Number}">
<Expander Classes="OperationExpander">
<ContentControl Classes="OperationControl">
<Grid ColumnDefinitions="auto,*" RowDefinitions="auto,auto,auto,auto,auto,auto,auto,auto,auto">
<TextBlock Grid.Row="0" Text="Mode:"/>
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged">
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged" ToolTip.Tip="Where to insert the numbering.">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Name}" ToolTip.Tip="{Binding Description}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="1" Text="Pattern:" IsVisible="{Binding #ModeSelector.SelectedItem.IsReplace}"/>
<TextBox Grid.Row="1" Text="{Binding Pattern}" IsVisible="{Binding #ModeSelector.SelectedItem.IsReplace}" PropertyChanged="PreviewChanged"/>
<TextBox Grid.Row="1" Text="{Binding Pattern}" IsVisible="{Binding #ModeSelector.SelectedItem.IsReplace}" PropertyChanged="PreviewChanged" ToolTip.Tip="The pattern to replace with the numbering."/>
<TextBlock Grid.Row="2" Text="Position:" IsVisible="{Binding #ModeSelector.SelectedItem.IsInsert}"/>
<NumericUpDown Grid.Row="2" Value="{Binding InsertPosition}" IsVisible="{Binding #ModeSelector.SelectedItem.IsInsert}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="2" Value="{Binding InsertPosition}" IsVisible="{Binding #ModeSelector.SelectedItem.IsInsert}" PropertyChanged="PreviewChanged" ToolTip.Tip="The zero-based index where to insert the numbering."/>
<TextBlock Grid.Row="3" Text="Start Index:"/>
<NumericUpDown Grid.Row="3" Value="{Binding StartIndex}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="3" Value="{Binding StartIndex}" PropertyChanged="PreviewChanged" ToolTip.Tip="The number of the first file name."/>
<TextBlock Grid.Row="4" Text="Increment:"/>
<NumericUpDown Grid.Row="4" Value="{Binding Increment}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="4" Value="{Binding Increment}" PropertyChanged="PreviewChanged" ToolTip.Tip="The increment to each successive file name (can be negative)."/>
<TextBlock Grid.Row="5" Text="Padding:"/>
<NumericUpDown Grid.Row="5" Value="{Binding Padding}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="5" Value="{Binding Padding}" PropertyChanged="PreviewChanged" ToolTip.Tip="The minimum number of digits for each number (pads with 0s)."/>
<TextBlock Grid.Row="6" Text="Auto Padding:"/>
<CheckBox Grid.Row="6" IsChecked="{Binding AutoPadding}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="6" IsChecked="{Binding AutoPadding}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to automatically apply padding based on the highest number."/>
<TextBlock Grid.Row="7" Text="Regex:" IsVisible="{Binding #ModeSelector.SelectedItem.IsReplace}"/>
<CheckBox Grid.Row="7" IsChecked="{Binding UseRegex}" IsVisible="{Binding #ModeSelector.SelectedItem.IsReplace}" PropertyChanged="PreviewChanged"/>
<TextBlock Grid.Row="8" Text="Full Name:" IsVisible="{Binding #ModeSelector.SelectedItem.IsReplace}"/>
<CheckBox Grid.Row="8" IsChecked="{Binding FullName}" IsVisible="{Binding #ModeSelector.SelectedItem.IsReplace}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="7" IsChecked="{Binding UseRegex}" IsVisible="{Binding #ModeSelector.SelectedItem.IsReplace}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to match using RegEx."/>
<TextBlock Grid.Row="8" Text="Full Name:"/>
<CheckBox Grid.Row="8" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to consider the file extension as well."/>
</Grid>
</Expander>
</ContentControl>
</DataTemplate>
<DataTemplate DataType="{x:Type ops:Add}">
<Expander Classes="OperationExpander">
<ContentControl Classes="OperationControl">
<Grid ColumnDefinitions="auto,*" RowDefinitions="auto,auto,auto,auto">
<TextBlock Grid.Row="0" Text="Mode:"/>
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged">
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged" ToolTip.Tip="Where to add the new text.">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Name}" ToolTip.Tip="{Binding Description}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="1" Text="Position:" IsVisible="{Binding #ModeSelector.SelectedItem.IsInsert}"/>
<NumericUpDown Grid.Row="1" Value="{Binding InsertPosition}" IsVisible="{Binding #ModeSelector.SelectedItem.IsInsert}" PropertyChanged="PreviewChanged"/>
<NumericUpDown Grid.Row="1" Value="{Binding InsertPosition}" IsVisible="{Binding #ModeSelector.SelectedItem.IsInsert}" PropertyChanged="PreviewChanged" ToolTip.Tip="The zero-based index at which to insert the new text."/>
<TextBlock Grid.Row="2" Text="Text:"/>
<TextBox Grid.Row="2" Text="{Binding Text}" PropertyChanged="PreviewChanged"/>
<TextBox Grid.Row="2" Text="{Binding Text}" PropertyChanged="PreviewChanged" ToolTip.Tip="The text to add to the file name."/>
<TextBlock Grid.Row="3" Text="Full Name:"/>
<CheckBox Grid.Row="3" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="3" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to consider the file extension as well."/>
</Grid>
</Expander>
</ContentControl>
</DataTemplate>
<DataTemplate DataType="{x:Type ops:Sort}">
<Expander Classes="OperationExpander">
<ContentControl Classes="OperationControl">
<Grid ColumnDefinitions="auto,*" RowDefinitions="auto,auto,auto">
<TextBlock Grid.Row="0" Text="Mode:"/>
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged">
<ComboBox Grid.Row="0" Items="{Binding Modes}" Name="ModeSelector" SelectedIndex="{Binding Mode}" PropertyChanged="PreviewChanged" ToolTip.Tip="The method that is used to compare and sort the file names.">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Name}" ToolTip.Tip="{Binding Description}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="1" Text="Direction:" IsVisible="{Binding !#ModeSelector.SelectedItem.IsReverse}"/>
<ComboBox Grid.Row="1" Items="{Binding Directions}" SelectedIndex="{Binding Direction}" IsVisible="{Binding !#ModeSelector.SelectedItem.IsReverse}" PropertyChanged="PreviewChanged"/>
<ComboBox Grid.Row="1" Items="{Binding Directions}" SelectedIndex="{Binding Direction}" IsVisible="{Binding !#ModeSelector.SelectedItem.IsReverse}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to sort in ascending or descending order."/>
<TextBlock Grid.Row="2" Text="Full Name:" IsVisible="{Binding !#ModeSelector.SelectedItem.IsReverse}"/>
<CheckBox Grid.Row="2" IsChecked="{Binding FullName}" IsVisible="{Binding !#ModeSelector.SelectedItem.IsReverse}" PropertyChanged="PreviewChanged"/>
<CheckBox Grid.Row="2" IsChecked="{Binding FullName}" IsVisible="{Binding !#ModeSelector.SelectedItem.IsReverse}" PropertyChanged="PreviewChanged" ToolTip.Tip="Whether to consider the file extension as well."/>
</Grid>
</Expander>
</ContentControl>
</DataTemplate>
</Window.DataTemplates>
</Window>

View File

@ -6,11 +6,16 @@ using System.Collections.Generic;
using System.Text.RegularExpressions;
using Avalonia;
using Avalonia.Input;
using Avalonia.Controls;
using Avalonia.VisualTree;
using Avalonia.Markup.Xaml;
using Avalonia.LogicalTree;
using BFR.Helpers;
using BFR.DataModels;
using BFR.Operations;
using Avalonia.Markup.Xaml.Styling;
namespace BFR
{
@ -22,8 +27,9 @@ namespace BFR
public async Task OpenDirectoryButtonClick() => OpenDirectory(await new OpenFolderDialog() { Directory = WorkingDirectory }.ShowAsync(this));
public void OpenDirectory(string directory)
{
WorkingDirectory = directory;
AllFiles.ReplaceAll(Directory.GetFiles(WorkingDirectory).Select(x => new FileModel(x)));
WorkingDirectory = directory.Replace('\\', '/');
AllFiles.ReplaceAll(Directory.GetFiles(WorkingDirectory).Select(x => new FileModel(x.Replace('\\', '/'))));
new Sort() { Mode = SortMode.Natural }.ApplyTo(AllFiles);
Filter();
}
@ -80,24 +86,49 @@ namespace BFR
Preview();
}
public void RemoveOperation()
private ListBox OperationsListBox;
private ListBoxItem DragItem;
public void DeleteOperation(object sender, PointerReleasedEventArgs e)
{
if (SelectedOperation >= 0)
Operations.RemoveAt(SelectedOperation);
else Operations.RemoveAt(0);
var hoveredItem = (ListBoxItem)OperationsListBox.GetLogicalChildren().FirstOrDefault(x => this.GetVisualsAt(e.GetPosition(this)).Contains(((IVisual)x).GetVisualChildren().First()));
if(hoveredItem != null) Operations.RemoveAt(OperationsListBox.GetLogicalChildren().ToList().IndexOf(hoveredItem));
Preview();
}
public void MoveOperation(object sender, SpinEventArgs e)
private void ClearDropStyling()
{
HandleEvents = false;
if (Operations.Count > 1)
if (e.Direction == SpinDirection.Increase && SelectedOperation > 0)
Operations.Move(SelectedOperation, SelectedOperation - 1);
else if (e.Direction == SpinDirection.Decrease && SelectedOperation < Operations.Count - 1)
Operations.Move(SelectedOperation, SelectedOperation + 1);
HandleEvents = true;
Preview();
foreach (ListBoxItem item in OperationsListBox.GetLogicalChildren())
item.Classes.RemoveAll(new[] { "BlackTop", "BlackBottom" });
}
public void StartMoveOperation(object sender, PointerPressedEventArgs e) =>
DragItem = OperationsListBox.GetLogicalChildren().Cast<ListBoxItem>().Single(x => x.IsPointerOver);
public void MoveOperation(object sender, PointerEventArgs e)
{
if (DragItem == null) return;
var hoveredItem = (ListBoxItem)OperationsListBox.GetLogicalChildren().FirstOrDefault(x => this.GetVisualsAt(e.GetPosition(this)).Contains(((IVisual)x).GetVisualChildren().First()));
var dragItemIndex = OperationsListBox.GetLogicalChildren().ToList().IndexOf(DragItem);
var hoveredItemIndex = OperationsListBox.GetLogicalChildren().ToList().IndexOf(hoveredItem);
ClearDropStyling();
if (hoveredItem != DragItem) hoveredItem?.Classes.Add(dragItemIndex > hoveredItemIndex ? "BlackTop" : "BlackBottom");
}
public void EndMoveOperation(object sender, PointerReleasedEventArgs e)
{
var hoveredItem = (ListBoxItem)OperationsListBox.GetLogicalChildren().FirstOrDefault(x => this.GetVisualsAt(e.GetPosition(this)).Contains(((IVisual)x).GetVisualChildren().First()));
if (DragItem != null && hoveredItem != null && DragItem != hoveredItem)
{
Operations.Move(
OperationsListBox.GetLogicalChildren().ToList().IndexOf(DragItem),
OperationsListBox.GetLogicalChildren().ToList().IndexOf(hoveredItem));
Preview();
}
ClearDropStyling();
DragItem = null;
}
public void Commit()
@ -126,8 +157,15 @@ namespace BFR
{
AvaloniaXamlLoader.Load(this);
DataContext = this;
OpenDirectory(Environment.OSVersion.Platform == PlatformID.Win32NT ? @"C:\Users" : @"\home");
OpenDirectory(Environment.OSVersion.Platform == PlatformID.Win32NT ? @"C:/Users/" : @"/home/");
HandleEvents = true;
OperationsListBox = this.Find<ListBox>("OperationsListBox");
/*var dark = new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseDark.xaml?assembly=Avalonia.Themes.Default")
};
Styles[0] = dark;/**/
}
}
}

View File

@ -27,8 +27,8 @@
get => $"{Directory}{FullName}";
set
{
FullName = value.Substring(value.LastIndexOf('\\') + 1);
Directory = value.Substring(0, value.LastIndexOf('\\') + 1);
FullName = value.Substring(value.LastIndexOf('/') + 1);
Directory = value.Substring(0, value.LastIndexOf('/') + 1);
}
}

View File

@ -46,16 +46,15 @@ namespace BFR.Operations
files.ReplaceAll(new List<FileModel>(files.Reverse()));
}
// Code taken and slightly modified from https://git.lastassault.de/speatzle/BulkFileRenamer
// Using code from stackoverflow
// https://stackoverflow.com/questions/248603/natural-sort-order-in-c-sharp
public static int CompareNatural(string strA, string strB) =>
CompareNatural(strA, strB, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase);
public static int CompareNatural(string strA, string strB, CultureInfo culture, CompareOptions options)
{
var cmp = culture.CompareInfo;
var (iA, iB) = (0, 0);
var softResult = 0;
var softResultWeight = 0;
var (iA, iB, softResult, softResultWeight) = (0, 0, 0, 0);
while (iA < strA.Length && iB < strB.Length)
{
var isDigitA = char.IsDigit(strA[iA]);
@ -64,8 +63,7 @@ namespace BFR.Operations
return cmp.Compare(strA, iA, strB, iB, options);
else if (!isDigitA && !isDigitB)
{
var jA = iA + 1;
var jB = iB + 1;
var (jA, jB) = (iA + 1, iB + 1);
while (jA < strA.Length && !char.IsDigit(strA[jA])) jA++;
while (jB < strB.Length && !char.IsDigit(strB[jB])) jB++;
var cmpResult = cmp.Compare(strA, iA, jA - iA, strB, iB, jB - iB, options);
@ -81,7 +79,8 @@ namespace BFR.Operations
softResultWeight = 1;
}
}
(iA, jA) = (iB, jB);
iA = jA;
iB = jB;
}
else
{
@ -90,7 +89,7 @@ namespace BFR.Operations
var (jA, jB) = (iA, iB);
while (jA < strA.Length && strA[jA] == zeroA) jA++;
while (jB < strB.Length && strB[jB] == zeroB) jB++;
int resultIfSameLength = 0;
var resultIfSameLength = 0;
do
{
isDigitA = jA < strA.Length && char.IsDigit(strA[jA]);
@ -106,8 +105,7 @@ namespace BFR.Operations
jA++;
jB++;
}
}
while (isDigitA && isDigitB);
} while (isDigitA && isDigitB);
if (isDigitA != isDigitB)
return isDigitA ? 1 : -1;
else if (resultIfSameLength != 0)

View File

@ -1,2 +1,24 @@
# BFR (Working Title)
A modular bulk file renaming utility inspired by git.lastassault.de/speatzle/BulkFileRenamer
# BFR - A Modular Bulk File Renaming Utility
Inspired by [this project](https://git.lastassault.de/speatzle/BulkFileRenamer) by speatzle_.
## Features
- Mordern scalable UI (Avalonia)
- Extremely flexible
- Indefinite undo
- Fast automatic preview
- Crossplatform and portable
- Supports RegEx
### Operations
- Add, Remove, Replace, Overwrite, Number, Sort
### Planned Features
- Case Conversion #1
- Save-/Loadable Profiles #3
- Operations based on file Metadata #4
- Optional Subdirectory Scanning #5
- Anything good that gets [requested](https://git.ulra.eu/adrian/bfr/issues)!
## [Releases](https://git.ulra.eu/adrian/bfr/releases)
## Screenshot
![](https://i.imgur.com/qHRTmJH.png)