diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 375a764c79..89c1e67af8 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -192,6 +192,7 @@ buildtransitive BValue bytearray callbackptr +capitalized CANRENAME Captureascreenshot CAPTURECHANGED diff --git a/src/modules/powerrename/lib/Helpers.cpp b/src/modules/powerrename/lib/Helpers.cpp index 30447d34f8..47dafe0d82 100644 --- a/src/modules/powerrename/lib/Helpers.cpp +++ b/src/modules/powerrename/lib/Helpers.cpp @@ -159,6 +159,42 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour { hr = StringCchCopy(result, cchMax, source); } + } + else if (flags & Capitalized) + { + if (!(flags & ExtensionOnly)) + { + std::wstring stem = fs::path(source).stem().wstring(); + std::wstring extension = fs::path(source).extension().wstring(); + + size_t stemLength = stem.length(); + + while (stemLength > 0 && (iswspace(stem[stemLength - 1]) || iswpunct(stem[stemLength - 1]))) + { + stemLength--; + } + + for (size_t i = 0; i < stemLength; i++) + { + if (!i || iswspace(stem[i - 1]) || iswpunct(stem[i - 1])) + { + if (iswspace(stem[i]) || iswpunct(stem[i])) + { + continue; + } + stem[i] = towupper(stem[i]); + } + else + { + stem[i] = towlower(stem[i]); + } + } + hr = StringCchPrintf(result, cchMax, L"%s%s", stem.c_str(), extension.c_str()); + } + else + { + hr = StringCchCopy(result, cchMax, source); + } } else { diff --git a/src/modules/powerrename/lib/PowerRenameInterfaces.h b/src/modules/powerrename/lib/PowerRenameInterfaces.h index c274cdb99b..c9a03b23c6 100644 --- a/src/modules/powerrename/lib/PowerRenameInterfaces.h +++ b/src/modules/powerrename/lib/PowerRenameInterfaces.h @@ -14,7 +14,8 @@ enum PowerRenameFlags ExtensionOnly = 0x100, Uppercase = 0x200, Lowercase = 0x400, - Titlecase = 0x800 + Titlecase = 0x800, + Capitalized = 0x1000 }; enum PowerRenameFilters diff --git a/src/modules/powerrename/lib/PowerRenameManager.cpp b/src/modules/powerrename/lib/PowerRenameManager.cpp index bdf62fe1df..7b20b5dd52 100644 --- a/src/modules/powerrename/lib/PowerRenameManager.cpp +++ b/src/modules/powerrename/lib/PowerRenameManager.cpp @@ -945,7 +945,7 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv) // as nullptr so we clear the renamed column // Except string transformation is selected. - if (newName == nullptr && (flags & Uppercase || flags & Lowercase || flags & Titlecase)) + if (newName == nullptr && (flags & Uppercase || flags & Lowercase || flags & Titlecase || flags & Capitalized)) { SHStrDup(sourceName, &newName); } @@ -983,7 +983,7 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv) } wchar_t transformedName[MAX_PATH] = { 0 }; - if (newNameToUse != nullptr && (flags & Uppercase || flags & Lowercase || flags & Titlecase)) + if (newNameToUse != nullptr && (flags & Uppercase || flags & Lowercase || flags & Titlecase || flags & Capitalized)) { winrt::check_hresult(GetTransformedFileName(transformedName, ARRAYSIZE(transformedName), newNameToUse, flags)); newNameToUse = transformedName; diff --git a/src/modules/powerrename/ui/PowerRenameUI.base.rc b/src/modules/powerrename/ui/PowerRenameUI.base.rc index 0369a50812..67f9fb973b 100644 --- a/src/modules/powerrename/ui/PowerRenameUI.base.rc +++ b/src/modules/powerrename/ui/PowerRenameUI.base.rc @@ -29,9 +29,9 @@ ///////////////////////////////////////////////////////////////////////////// // // Dialog -// +// XPOS YPOS WIDTH HEIGHT -IDD_MAIN DIALOGEX 0, 0, 364, 347 +IDD_MAIN DIALOGEX 0, 0, 364, 359 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "" FONT 8, "MS Shell Dlg", 400, 0, 0x1 @@ -44,22 +44,23 @@ CONTROL "",IDC_CHECK_ENUMITEMS, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 21, 119, 150, 10 CONTROL "",IDC_CHECK_NAMEONLY, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 21, 131, 150, 10 CONTROL "",IDC_CHECK_EXTENSIONONLY, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 21, 143, 150, 10 - CONTROL "",IDC_CHECK_EXCLUDEFOLDERS, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 83, 150, 10 - CONTROL "",IDC_CHECK_EXCLUDEFILES, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 95, 150, 10 - CONTROL "",IDC_CHECK_EXCLUDESUBFOLDERS, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 107, 150, 10 - CONTROL "",IDC_TRANSFORM_UPPERCASE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 119, 150, 10 - CONTROL "",IDC_TRANSFORM_LOWERCASE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 131, 150, 10 - CONTROL "",IDC_TRANSFORM_TITLECASE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 143, 150, 10 - CONTROL "",IDC_LIST_PREVIEW,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP,22,190,308,116 - DEFPUSHBUTTON "",ID_RENAME,178,325,50,14 - PUSHBUTTON "",ID_ABOUT,234,325,50,14 - PUSHBUTTON "",IDCANCEL,290,325,50,14 + CONTROL "",IDC_CHECK_EXCLUDEFOLDERS, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 21, 155, 150, 10 + CONTROL "",IDC_CHECK_EXCLUDEFILES, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 83, 150, 10 + CONTROL "",IDC_CHECK_EXCLUDESUBFOLDERS, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 95, 150, 10 + CONTROL "",IDC_TRANSFORM_UPPERCASE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 107, 150, 10 + CONTROL "",IDC_TRANSFORM_LOWERCASE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 119, 150, 10 + CONTROL "",IDC_TRANSFORM_TITLECASE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 131, 150, 10 + CONTROL "",IDC_TRANSFORM_CAPITALIZED, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 181, 143, 150, 10 + CONTROL "",IDC_LIST_PREVIEW,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP,22,202,308,116 + DEFPUSHBUTTON "",ID_RENAME,178,337,50,14 + PUSHBUTTON "",ID_ABOUT,234,337,50,14 + PUSHBUTTON "",IDCANCEL,290,337,50,14 RTEXT "",IDC_SEARCH_FOR,21,23,75,8 RTEXT "",IDC_REPLACE_WITH,21,40,75,8 - LTEXT "",IDC_STATUS_MESSAGE_SELECTED, 11, 323, 137, 13 - LTEXT "",IDC_STATUS_MESSAGE_RENAMING, 11, 333, 137, 13 - GROUPBOX "",IDC_OPTIONSGROUP,11,68,329,94 - GROUPBOX "",IDC_PREVIEWGROUP,11,175,329,142 + LTEXT "",IDC_STATUS_MESSAGE_SELECTED, 11, 335, 137, 13 + LTEXT "",IDC_STATUS_MESSAGE_RENAMING, 11, 345, 137, 13 + GROUPBOX "",IDC_OPTIONSGROUP,11,68,329,106 + GROUPBOX "",IDC_PREVIEWGROUP,11,187,329,142 GROUPBOX "",IDC_SEARCHREPLACEGROUP,11,7,329,55 END diff --git a/src/modules/powerrename/ui/PowerRenameUI.cpp b/src/modules/powerrename/ui/PowerRenameUI.cpp index c6f1245c38..7f063b49f1 100644 --- a/src/modules/powerrename/ui/PowerRenameUI.cpp +++ b/src/modules/powerrename/ui/PowerRenameUI.cpp @@ -39,7 +39,8 @@ FlagCheckboxMap g_flagCheckboxMap[] = { { ExtensionOnly, IDC_CHECK_EXTENSIONONLY }, { Uppercase, IDC_TRANSFORM_UPPERCASE }, { Lowercase, IDC_TRANSFORM_LOWERCASE }, - { Titlecase, IDC_TRANSFORM_TITLECASE } + { Titlecase, IDC_TRANSFORM_TITLECASE }, + { Capitalized, IDC_TRANSFORM_CAPITALIZED } }; struct RepositionMap @@ -708,6 +709,7 @@ void CPowerRenameUI::_InitDlgText() UpdateDlgControl(m_hwnd, IDC_CHECK_NAMEONLY, IDS_ITEM_NAME_ONLY); UpdateDlgControl(m_hwnd, IDC_CHECK_EXTENSIONONLY, IDS_ITEM_EXTENSION_ONLY); UpdateDlgControl(m_hwnd, IDC_TRANSFORM_TITLECASE, IDS_MAKE_TITLECASE); + UpdateDlgControl(m_hwnd, IDC_TRANSFORM_CAPITALIZED, IDS_MAKE_CAPITALIZED); UpdateDlgControl(m_hwnd, ID_RENAME, IDS_RENAME_BUTTON); UpdateDlgControl(m_hwnd, ID_ABOUT, IDS_HELP_BUTTON); UpdateDlgControl(m_hwnd, IDCANCEL, IDS_CANCEL_BUTTON); @@ -756,6 +758,7 @@ void CPowerRenameUI::_OnCommand(_In_ WPARAM wParam, _In_ LPARAM lParam) case IDC_CHECK_NAMEONLY: case IDC_TRANSFORM_UPPERCASE: case IDC_TRANSFORM_LOWERCASE: + case IDC_TRANSFORM_CAPITALIZED: case IDC_TRANSFORM_TITLECASE: if (BN_CLICKED == HIWORD(wParam)) { @@ -981,6 +984,7 @@ void CPowerRenameUI::_ValidateFlagCheckbox(_In_ DWORD checkBoxId) { Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_LOWERCASE), FALSE); Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_TITLECASE), FALSE); + Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_CAPITALIZED), FALSE); } } else if (checkBoxId == IDC_TRANSFORM_LOWERCASE) @@ -989,6 +993,7 @@ void CPowerRenameUI::_ValidateFlagCheckbox(_In_ DWORD checkBoxId) { Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_UPPERCASE), FALSE); Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_TITLECASE), FALSE); + Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_CAPITALIZED), FALSE); } } else if (checkBoxId == IDC_TRANSFORM_TITLECASE) @@ -997,6 +1002,16 @@ void CPowerRenameUI::_ValidateFlagCheckbox(_In_ DWORD checkBoxId) { Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_UPPERCASE), FALSE); Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_LOWERCASE), FALSE); + Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_CAPITALIZED), FALSE); + } + } + else if (checkBoxId == IDC_TRANSFORM_CAPITALIZED) + { + if (Button_GetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_CAPITALIZED)) == BST_CHECKED) + { + Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_UPPERCASE), FALSE); + Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_LOWERCASE), FALSE); + Button_SetCheck(GetDlgItem(m_hwnd, IDC_TRANSFORM_TITLECASE), FALSE); } } else if (checkBoxId == IDC_CHECK_NAMEONLY) diff --git a/src/modules/powerrename/ui/Resources.resx b/src/modules/powerrename/ui/Resources.resx index 28b645e29e..3eeb24bf29 100644 --- a/src/modules/powerrename/ui/Resources.resx +++ b/src/modules/powerrename/ui/Resources.resx @@ -175,6 +175,9 @@ Please select from the options above to show items. Make Titlecase + + Make Capitalized + &Rename diff --git a/src/modules/powerrename/ui/resource.base.h b/src/modules/powerrename/ui/resource.base.h index a79a44208c..7b99147efe 100644 --- a/src/modules/powerrename/ui/resource.base.h +++ b/src/modules/powerrename/ui/resource.base.h @@ -26,9 +26,10 @@ #define IDC_TRANSFORM_UPPERCASE 3019 #define IDC_TRANSFORM_LOWERCASE 3020 #define IDC_TRANSFORM_TITLECASE 3021 -#define IDC_SEARCH_FOR 3022 -#define IDC_REPLACE_WITH 3023 +#define IDC_TRANSFORM_CAPITALIZED 3022 +#define IDC_SEARCH_FOR 3023 +#define IDC_REPLACE_WITH 3024 #define IDC_STATIC -1 -#define IDR_MAINFRAME 3024 -#define IDD_MAIN 3025 +#define IDR_MAINFRAME 3025 +#define IDD_MAIN 3026 #define IDI_RENAME 2001 diff --git a/src/modules/powerrename/unittests/PowerRenameManagerTests.cpp b/src/modules/powerrename/unittests/PowerRenameManagerTests.cpp index dad75999db..86746bbdf6 100644 --- a/src/modules/powerrename/unittests/PowerRenameManagerTests.cpp +++ b/src/modules/powerrename/unittests/PowerRenameManagerTests.cpp @@ -270,6 +270,16 @@ namespace PowerRenameManagerTests RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Titlecase); } + TEST_METHOD (VerifyCapitalizedTransform) + { + rename_pairs renamePairs[] = { + { L"foo and the to", L"Bar And The To", false, true, 0 }, + { L"Test", L"Test_norename", false, false, 0 } + }; + + RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Capitalized); + } + TEST_METHOD (VerifyNameOnlyTransform) { rename_pairs renamePairs[] = {