Commit Graph

18 Commits

Author SHA1 Message Date
moooyo
70e1177a6a [PowerRename] Support using photo metadata to replace in the PowerRename (#41728)
<!-- 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. Introduce WIC for power rename and add new class WICMetadataExtractor
to use WIC to extract metadata.
2. Add some patterns for metadata extract.
3. Support XMP and EXIF metadata extract.
4. Add test data for xmp and exif extractor
5. Add attribution for the test data uploader.

UI:
<img width="2052" height="1415" alt="image"
src="https://github.com/user-attachments/assets/9051b12e-4e66-4fdc-a4d4-3bada661c235"
/>
<img width="284" height="170" alt="image"
src="https://github.com/user-attachments/assets/2fd67193-77a7-48f0-a5ac-08a69fe64e55"
/>
<img width="715" height="1160" alt="image"
src="https://github.com/user-attachments/assets/5fa68a8c-d129-44dd-b747-099dfbcded12"
/>

demo:


https://github.com/user-attachments/assets/e90bc206-62e5-4101-ada2-3187ee7e2039



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

- [x] Closes: #5612
- [x] **Communication:** I've discussed this with core contributors
already. If the 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 <yuleng@microsoft.com>
2025-11-04 09:27:16 +08:00
Dave Rayment
3b4007d299 [PowerRename] Fix issue where counter does not update if the filename and replacement result matched (#42006)
This PR fixes an issue which has been reported a number of times under
slightly different guises. The bug manifests as a counter "stall" or
"skip" under certain circumstances, not advancing the counter if the
result of the rename operation happens to match the original filename.

<!-- 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

This issue occurs if all the following are true:
- Enumeration features are enabled
- Regular expression matching is enabled
- The replacement string includes a counter, for example `${}` or
`${start=1}` or `${start=10,increment=10}` etc.
- There are one or more original filenames which coincide with the
result of the renaming operations

Previously, the counter was not updated when the renaming operation
result was the same as the original filename. For example, here the
first rename result matches the original filename and the counter
remains at `1` for the second file, whereas it should be `2`:

<img width="1002" height="759" alt="image"
src="https://github.com/user-attachments/assets/2766f448-adc3-4fe7-9c13-f4c5505ae1d9"
/>

This fix increments the counter irrespective of these coincidences.

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

- [x] Closes: #41950, #31950, #33884
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **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

**Before discussing the detail of the fix, I'd like to acknowledge the
incredible coincidence that it resolves two issues (31950 and 41950)
_which are exactly 10,000 issues (and 18 months) apart_.**

Now, back to the issue at hand, if you'll forgive the pun...

The original flawed code is here:

```cpp
    bool replacedSomething = false;
    if (m_flags & UseRegularExpressions)
    {
        replaceTerm = regex_replace(replaceTerm, zeroGroupRegex, L"$1$$$0");
        replaceTerm = regex_replace(replaceTerm, otherGroupsRegex, L"$1$0$4");

        res = RegexReplaceDispatch[_useBoostLib](source, m_searchTerm, replaceTerm, m_flags & MatchAllOccurrences, !(m_flags & CaseSensitive));
        replacedSomething = originalSource != res;
    }
```

Here `replacedSomething` controls whether the counter variable is
incremented later in the code. The problem lies in the assumption that
only a replacement result which differs from the original string implies
a match. This is incorrect, as a successful match and replace operation
can still produce a result which coincides with `originalSource` (the
source filename), i.e. `originalSource == res`.

The solution is to separate the regex matching from the replacement
operation, and to advance the counter when the match is successful
irrespective of whether the result is the same as the filename. This is
what the fix does:

```cpp
    bool shouldIncrementCounter = false;
    if (m_flags & UseRegularExpressions)
    {
        replaceTerm = regex_replace(replaceTerm, zeroGroupRegex, L"$1$$$0");
        replaceTerm = regex_replace(replaceTerm, otherGroupsRegex, L"$1$0$4");

        res = RegexReplaceDispatch[_useBoostLib](source, m_searchTerm, replaceTerm, m_flags & MatchAllOccurrences, !(m_flags & CaseSensitive));

        // Use regex search to determine if a match exists. This is the basis for incrementing
        // the counter.
        if (_useBoostLib)
        {
            boost::wregex pattern(m_searchTerm, boost::wregex::ECMAScript | (!(m_flags & CaseSensitive) ? boost::wregex::icase : boost::wregex::normal));
            shouldIncrementCounter = boost::regex_search(sourceToUse, pattern);
        }
        else
        {
            auto regexFlags = std::wregex::ECMAScript;
            if (!(m_flags & CaseSensitive))
            {
                regexFlags |= std::wregex::icase;
            }
            std::wregex pattern(m_searchTerm, regexFlags);
            shouldIncrementCounter = std::regex_search(sourceToUse, pattern);
        }
    }
```

The `regex_search()` call on both the boost and std paths tests whether
the regex pattern can be found in the original filename (`sourceToUse`).
`shouldIncrementCounter` tracks whether the counter will be incremented
later, renamed from `replacedSomething` to reflect the change in
behaviour.

## Validation Steps Performed

The fix includes an additional unit test for both the std and boost
regex paths. Without the fix, the test fails:

<img width="1509" height="506" alt="Screenshot 2025-09-25 063611"
src="https://github.com/user-attachments/assets/14dbf817-b1d3-456d-80f2-abcd28266b8d"
/>

and with the fix, all tests pass:

<img width="897" height="492" alt="Screenshot 2025-09-25 063749"
src="https://github.com/user-attachments/assets/9a587495-d54c-47d3-bc55-ccc64a805a88"
/>
2025-09-29 10:05:21 +08:00
Jaakko Hirvioja
c148b51698 [PowerRename]Add random string values to file names (#32836)
* Add randomizer cheat sheet texts to UI tooltip

* Add randomizer icon (shuffle) + hint to main window

* Add randomizer logic + helpers, regex parsing

* Fix: remove unnecessary throw

* Fix: remove todo comment

* Fix: iffing logic

* Fix: add offset to randomizer onchange

* Update: guid generating to single function, handle bracket removing there

* Update: toggle off enum feat when random values are selected

* Update: main window UI tooltip texts to be more descriptive

* Update: remove unnecessary sstream include

* Fix: return empty string if chars has no value to avoid memory access violation

* Add unit tests

* Add PowerRename random string generating keywords

* Update: generating value names to be in line with POSIX conventions

* Allow to used with Enumerate at the same time

* Fix spellcheck

* Fix tests to take into account we no longer eat up empty expressions
with randomizer

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2024-06-20 16:26:31 +01:00
Andrey Nekrasov
268614ccd9 [PowerRename] Introduce advanced counter functionality (#27895) 2023-08-14 16:53:49 +02:00
Josh Soref
3cb0638c7e [ci]Upgrade to check-spelling 0.0.20alpha7 (#19127)
* spelling: added

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: and

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: another

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: color

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: file

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: github

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: not

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: occurrences

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: stamp

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: suppressions

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: the

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: up to

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: whether

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: whichdoes

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* Upgrade check-spelling to v0.0.20-alpha7

Config based on:
a5001170a7

* Adding duplicate detection to patterns.txt
* Adding line_forbidden.patterns
* Adding reject.txt
* Updated excludes (and sorted)
* Switching to unified workflow

* moving `wil` to allow.txt to clarify that it's a term of art
  (https://github.com/microsoft/wil), whereas often it's a typo for `will`.

* Update src/runner/main.cpp

Co-authored-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2022-07-01 15:09:41 +01:00
Stefan Markovic
5cfbd72fa8 [PowerRename] Fluent UX (#13678)
* PowerRename new UI

* Add scrollviewer

* Don't deploy PowerRenameUI_new

* Visual updates

* Visual updates

* Updates

* Update Resources.resw

* Added docs button

* Update MainWindow.xaml

* Wire Docs button

* RegEx -> regular expressions

* Update Show only renamed list on search/replace text changed

* Update Show only renamed list on search/replace text changed - proper fix
Set searchTerm to NULL when cleared - fix Show only renamed files on clear searchTerm

* Files/folders input error handling

* Fix renaming with keeping UI window opened

After renaming folder, all of it's children need path update.
Without path update, further renaming of children items would
fail.

* Update only children, not all items with greater depth

* Fix dictionary false positives

* Remove .NET dep

* Rename PowerRenameUI_new to PowerRenameUILib
Rename executable PowerRenameUIHost to PowerRename

Co-authored-by: Laute <Niels.Laute@philips.com>
2021-10-25 14:40:19 +01:00
Andrey Nekrasov
063e704321 build: Treat warnings as errors in the remaining projects (#8689)
* build: remove #pragma comment(lib

* build: treat warnings as errors for all src projects
2020-12-21 18:51:48 +03:00
Mehmet Murat Akburak
da22e21a0e [PowerRename] Fix tests inconsistency, improve test performance (#8129)
* Move retrieveing file attibutes to PowerRenameRegex
Move file attributes unit tests to PowerRenameRegexTests
Add file time field to MockPowerRenameItem

* Add file attributes unittests to PowerRenameManagerTests

* Change variable name

* Rearrange function arguments

* Check if file attributes are used only once

* Change variable name LocalTime -> fileTime, date -> time

* Set fileTime as a member of PowerRenameRegEx rather than passing as an argument

* Change function name isFileAttributesUsed() -> isFileTimeUsed()
Check before resetting fileTime

* Fix small bugs

* Fix typos

* Refactor for readability, move free calls to reachable places

* Fix search for area empty bug
searchTerm being empty is not an invalid argument rather it must return OK without any operation
Tests must check if Replace()  returns S_OK becuase later it checks its result

* Check return values of method calls in PowerRenameManager
Remove received argments checks from some methods because argument being null or empty string doesnt mean it is invalid or method fails

* Fix formatting. Remove overlooked comment. Fix error message.

* Change HRESULT declarations according to coding style

* Fix unhandled case. Refactor.
2020-12-14 10:28:12 +01:00
Raphael Horber
8c7f2b6a74 PowerRename: Add Lookbehind (#7571)
* Add boost-regex library

* If enabled use boost lib for regex

Add property `_useBoostLib` to `CPowerRenameRegEx`. If enabled for
replacements with regular expressions the Boost Library is used instead
of the Standard Library.

* Extend signatures to create RegEx with Boost

Extend create and constructor singatures of `CPowerRenameRegEx` with an
option to enable (or disabled, which is default) the Boost Library.

* Verify Lookbehind fails with STD library

To verify that the boost library is disabled as expected, check if a
lookbehind fails.

* Add Unit tests for RegEx with Boost

Add unit tests to verify regex replacement with Boost Library. They are
copied and adapted from the Standard Library tests.

* Improve verify capturing groups test with Boost

It is possible to use a capturing group followed by numbers as
replacement if the group number is enclosed in curly braces.
Added test cases based on the Standard Library tests.

* Add useBoostLib to settings interface

* Get library option from settings object

* Reduce signatures of RegEx by "useBoost"

Remove the parameter added in 19105cf, as it became obsolete.

* Settings: Read useBoostLib from JSON file

* Add UseBoostLib Option to UI

* Boost Lib label states the regex syntax difference

* Fix Regex with Boost Lib tests

- Do not load settings another time in CPowerRenameRegEx ctor
- Set flag correctly in standard library regex tests

* Add "lookbehind" to dictionary

* change Library to lowercase, and also add a comment

As suggested by @enricogior.

Co-authored-by: Enrico Giordani <enricogior@users.noreply.github.com>

* Change Library to lowercase and add a comment

 As suggested by @enricogior.

Co-authored-by: Enrico Giordani <enricogior@users.noreply.github.com>
2020-11-09 19:13:43 +01:00
Mehmet Murat Akburak
d3b80b26e3 [PowerRename] Add Filtering Feature (#6017)
* Implement basic functionality

* Change approach.
move filter controls to manager
edit redrawing to always work with new GetVisibleItemCount() and GetVisibleItemByIndex() calls

* Fix performance issues. Some refactoring.

* Handle toggleAll correctly

* Handle dangling elements when filter is on

Make an item visible if it has at least one visible subitem

* Support filtering for selected and shouldRename

* Refactor for readability, remove useless member from PowerRenameUI

* Change variable names in PowerRenameUI for clarity

Use wrapper function RedrawItems() and SetItemCount() for consistency

* Handle result value properly in getVisibleItemByIndex()

* Add FlagsApplicable filter

* Add visual indication of filters

* Improve performance

Check if no filter is selected
Call SetItemCount() only when necessary

* Refactor for readability

* Get lock in setVisible()

* Change function names to camel case

* Change function names to start with uppercase

* Change filter behaviour when search area is empty

Show all elements when search area is empty and ShouldRename filter is selected
Avoid warnings

* Resolve conflicts
2020-08-25 08:22:05 +03:00
Mehmet Murat Akburak
35a214603f [PowerRename] Clear capturing groups with more than 1 digit (#5116)
User has actually signed CLA, see #4722

* Clear capturing groups with more than 1 digit

* Fix issue in regex pattern

* Add unittest

* Fix regex patterns

* Edit unittest

* Fix regex pattern, add some tests
2020-07-22 14:12:46 -07:00
Mehmet Murat Akburak
30f442d774 [PowerRename] upper/lower/titlecase transform feature (#4183)
* Add basic transform functionality

* Add basic transform functionality

* Change toupper/tolower/isspace to towupper/towlower/towisspace. For loops omitted if possible.

* Avoid wcslen() in for statement

* Avoid wcslen() in for statement

* Add basic transform functionality

* Change toupper/tolower/isspace to towupper/towlower/towisspace. For loops omitted if possible.

* Avoid wcslen() in for statement

* Avoid wcslen() in for statement

* Add basic transform functionality

* Change toupper/tolower/isspace to towupper/towlower/towisspace. For loops omitted if possible.

* Avoid wcslen() in for statement

* Adjust Powerrename Interface

* Add trimming rename string

* Remove leading and trailing spaces from rename string

* Add support for transforming only item name or extension. Temporarily remove trimming to refactor. Change CAPITALIZED to TITLECASE

* Fix bug when search for area is empty

* Add trimming back with refactor(leading spaces, trailing spaces, trailing dots)

* Now supports transforming when search area is empty

* Add smarter titlecase

Transformation breaks when new filename contains an unusable character (\/?:*?"<>|)
These characters need to be removed from new name anyway.

* minor bugfix

* Add unittests, contains failing tests

* Remove unnecessary/failing tests

* remove generated file

* some code formatting and fix memory leak issues

* Use proper allocation, change int to size_t

* Refactor. Move transforming to Helpers.cpp

* Refactor. Move trimming to Helpers.cpp

* Change StrDup to SHStrDup. Some refactoring.

* Fix memery leak, add proper result controls, use newNameToUse in functon calls becaause it is where the final form of the string is tracked

* Change declarations of strings, add proper result controls

* Slightly widen the labels to cover the whole text

* Add extended characters support

* Rename a variable

* Correctly identify the last word for titlecase

* Add empty line to last line of resource.h
2020-07-02 11:52:01 +03:00
Mehmet Murat Akburak
014f3b9873 [PowerRename] capturing groups fix (#4181)
* Fix capturing group bug when Match All Occurrences is not checked

* Capture groups are now available when Match All Occurences option is not selected

* Bug fix when capture group is indicated with leading zeros. $01 should be considered as $1 etc

* Use flags in regex_replace() when Match All Occurences is not selected

Now the behaviour is consistent with how regex works when Match All Occurences is selected.
2020-06-16 11:04:14 +03:00
Rafael Rivera
d16ebba9e0 Move from sdk-provided cppwinrt-1.x to cppwinrt-2.x nuget package (#2246) 2020-04-29 22:02:18 +02:00
Chris Davis
e328c5d505 * Fix crashing bug in event vector cleanup
* Fix warnings in settings.cpp
* Add settings to ui of powertoys
2019-11-11 20:58:39 -08:00
Chris Davis
1e89054897 * Ensure rename dialog is centered
* Ensure children are renamed before parent items
* Add settings handler
* Replace old text referencing smart rename with power rename
2019-11-11 11:00:42 -08:00
Chris Davis
1efe5bff9f Fix single regex search replace
Fix an issue where regular expression search and replace was not being done correctly when MatchAllOccurences is not specified.
2019-11-01 23:56:29 -07:00
Chris Davis
e1d5dd263a Initial add of PowerRename from SmartRename repo (#499)
* Initial add of PowerRename from SmartRename repo
2019-10-17 20:57:19 -07:00