[PowerRename] Add ModificationTime and AccessTime support when renaming with $YY-$MM-$DD patterns (#39653)

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
1. Add new configuration to control this behaviour. By default, set to
creation time to align with previous version
2. Add UI in PowerRename's MainWindow
3. Implement the logic


![image](https://github.com/user-attachments/assets/fde6731b-73f9-453f-8b68-6ce66589f44a)


Original discussion here:
https://github.com/microsoft/PowerToys/pull/38186

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] **Closes:** #36040
- [x] **Communication:** I've discussed this with core contributors
already. If work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end user facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com>
This commit is contained in:
Yu Leng
2025-05-30 13:07:20 +08:00
committed by GitHub
parent 498ef676f4
commit c9922302e5
7 changed files with 117 additions and 9 deletions

View File

@@ -184,6 +184,7 @@
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="48" />
<RowDefinition Height="48" />
</Grid.RowDefinitions>
<StackPanel
@@ -558,6 +559,33 @@
Content="&#xE8B1;"
FontFamily="{ThemeResource SymbolThemeFontFamily}" />
</StackPanel>
<TextBlock
x:Name="FileTimeLabel"
x:Uid="TextBlock_FileTime"
Margin="0,16,0,8"
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<StackPanel
Grid.Row="2"
Grid.Column="1"
Orientation="Horizontal"
Spacing="4">
<ComboBox
x:Name="comboBox_fileTimeParts"
Grid.Row="1"
Grid.Column="0"
Width="200"
HorizontalAlignment="Stretch"
AutomationProperties.LabeledBy="{Binding ElementName=FileDateLabel}"
SelectedIndex="0">
<ComboBoxItem x:Uid="FileTimeParts_CreationTime" />
<ComboBoxItem x:Uid="FileTimeParts_ModificationTime" />
<ComboBoxItem x:Uid="FileTimeParts_AccessTime" />
</ComboBox>
</StackPanel>
</StackPanel>
<Rectangle

View File

@@ -792,6 +792,32 @@ namespace winrt::PowerRenameUI::implementation
button_settings().Click([&](auto const&, auto const&) {
OpenSettingsApp();
});
// ComboBox RenameParts
comboBox_fileTimeParts().SelectionChanged([&](auto const&, auto const&) {
int selectedIndex = comboBox_fileTimeParts().SelectedIndex();
if (selectedIndex == 0)
{
// default behaviour. Date Created
UpdateFlag(CreationTime, UpdateFlagCommand::Set);
UpdateFlag(ModificationTime, UpdateFlagCommand::Reset);
UpdateFlag(AccessTime, UpdateFlagCommand::Reset);
}
else if (selectedIndex == 1)
{
// Date Modified
UpdateFlag(ModificationTime, UpdateFlagCommand::Set);
UpdateFlag(CreationTime, UpdateFlagCommand::Reset);
UpdateFlag(AccessTime, UpdateFlagCommand::Reset);
}
else if (selectedIndex == 2)
{
// Accessed
UpdateFlag(AccessTime, UpdateFlagCommand::Set);
UpdateFlag(CreationTime, UpdateFlagCommand::Reset);
UpdateFlag(ModificationTime, UpdateFlagCommand::Reset);
}
});
}
void MainWindow::ToggleItem(int32_t id, bool checked)

View File

@@ -411,4 +411,16 @@
<data name="ToggleButton_RandItems.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Random string features</value>
</data>
<data name="TextBlock_FileTime.Text" xml:space="preserve">
<value>Time used for replacement</value>
</data>
<data name="FileTimeParts_CreationTime.Content" xml:space="preserve">
<value>Creation Time</value>
</data>
<data name="FileTimeParts_ModificationTime.Content" xml:space="preserve">
<value>Modification Time</value>
</data>
<data name="FileTimeParts_AccessTime.Content" xml:space="preserve">
<value>Access Time</value>
</data>
</root>

View File

@@ -18,7 +18,10 @@ enum PowerRenameFlags
Lowercase = 0x400,
Titlecase = 0x800,
Capitalized = 0x1000,
RandomizeItems = 0x2000
RandomizeItems = 0x2000,
CreationTime = 0x4000,
ModificationTime = 0x8000,
AccessTime = 0x10000,
};
enum PowerRenameFilters
@@ -67,7 +70,7 @@ interface __declspec(uuid("C7F59201-4DE1-4855-A3A2-26FC3279C8A5")) IPowerRenameI
public:
IFACEMETHOD(PutPath)(_In_opt_ PCWSTR newPath) = 0;
IFACEMETHOD(GetPath)(_Outptr_ PWSTR * path) = 0;
IFACEMETHOD(GetTime)(_Outptr_ SYSTEMTIME* time) = 0;
IFACEMETHOD(GetTime)(_In_ DWORD flags, _Outptr_ SYSTEMTIME * time) = 0;
IFACEMETHOD(GetShellItem)(_Outptr_ IShellItem** ppsi) = 0;
IFACEMETHOD(GetOriginalName)(_Outptr_ PWSTR * originalName) = 0;
IFACEMETHOD(PutOriginalName)(_In_opt_ PCWSTR originalName) = 0;

View File

@@ -56,12 +56,28 @@ IFACEMETHODIMP CPowerRenameItem::GetPath(_Outptr_ PWSTR* path)
return hr;
}
IFACEMETHODIMP CPowerRenameItem::GetTime(_Outptr_ SYSTEMTIME* time)
IFACEMETHODIMP CPowerRenameItem::GetTime(_In_ DWORD flags, _Outptr_ SYSTEMTIME* time)
{
CSRWSharedAutoLock lock(&m_lock);
HRESULT hr = E_FAIL;
PowerRenameFlags parsedTimeType;
if (m_isTimeParsed)
// Get Time by PowerRenameFlags
if (flags & PowerRenameFlags::ModificationTime)
{
parsedTimeType = PowerRenameFlags::ModificationTime;
}
else if (flags & PowerRenameFlags::AccessTime)
{
parsedTimeType = PowerRenameFlags::AccessTime;
}
else
{
// Default to modification time if no specific flag is set
parsedTimeType = PowerRenameFlags::CreationTime;
}
if (m_isTimeParsed && parsedTimeType == m_parsedTimeType)
{
hr = S_OK;
}
@@ -70,21 +86,43 @@ IFACEMETHODIMP CPowerRenameItem::GetTime(_Outptr_ SYSTEMTIME* time)
HANDLE hFile = CreateFileW(m_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
FILETIME CreationTime;
if (GetFileTime(hFile, &CreationTime, NULL, NULL))
FILETIME FileTime;
bool success = false;
// Get Time by PowerRenameFlags
switch (parsedTimeType)
{
case PowerRenameFlags::CreationTime:
success = GetFileTime(hFile, &FileTime, NULL, NULL);
break;
case PowerRenameFlags::ModificationTime:
success = GetFileTime(hFile, NULL, NULL, &FileTime);
break;
case PowerRenameFlags::AccessTime:
success = GetFileTime(hFile, NULL, &FileTime, NULL);
break;
default:
// Default to modification time if no specific flag is set
success = GetFileTime(hFile, NULL, NULL, &FileTime);
break;
}
if (success)
{
SYSTEMTIME SystemTime, LocalTime;
if (FileTimeToSystemTime(&CreationTime, &SystemTime))
if (FileTimeToSystemTime(&FileTime, &SystemTime))
{
if (SystemTimeToTzSpecificLocalTime(NULL, &SystemTime, &LocalTime))
{
m_time = LocalTime;
m_isTimeParsed = true;
m_parsedTimeType = parsedTimeType;
hr = S_OK;
}
}
}
}
CloseHandle(hFile);
}
*time = m_time;

View File

@@ -16,7 +16,7 @@ public:
// IPowerRenameItem
IFACEMETHODIMP PutPath(_In_opt_ PCWSTR newPath);
IFACEMETHODIMP GetPath(_Outptr_ PWSTR* path);
IFACEMETHODIMP GetTime(_Outptr_ SYSTEMTIME* time);
IFACEMETHODIMP GetTime(_In_ DWORD flags, _Outptr_ SYSTEMTIME* time);
IFACEMETHODIMP GetShellItem(_Outptr_ IShellItem** ppsi);
IFACEMETHODIMP PutOriginalName(_In_opt_ PCWSTR originalName);
IFACEMETHODIMP GetOriginalName(_Outptr_ PWSTR* originalName);
@@ -54,6 +54,7 @@ protected:
bool m_selected = true;
bool m_isFolder = false;
bool m_isTimeParsed = false;
PowerRenameFlags m_parsedTimeType = PowerRenameFlags::CreationTime;
bool m_canRename = true;
int m_id = -1;
int m_iconIndex = -1;

View File

@@ -78,7 +78,7 @@ bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnum
if (useFileTime)
{
winrt::check_hresult(spItem->GetTime(&fileTime));
winrt::check_hresult(spItem->GetTime(flags, &fileTime));
winrt::check_hresult(spRenameRegEx->PutFileTime(fileTime));
}