Repository.mk | 2 offapi/com/sun/star/system/windows/JumpListItem.idl | 18 ++- offapi/com/sun/star/system/windows/XJumpList.idl | 43 ++++++++ shell/source/win32/jumplist/JumpList.cxx | 100 +++++++++++++++++--- 4 files changed, 142 insertions(+), 21 deletions(-)
New commits: commit 22b315c3cf59b697e5b6e1c06d9cb60985fc21fb Author: Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de> AuthorDate: Mon Mar 14 10:04:17 2022 +0100 Commit: Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de> CommitDate: Wed Mar 30 11:10:05 2022 +0200 Add UNO API for custom Jump Lists Backport of changes to commit after it was cherry-picked to this branch Change-Id: I13b6c3ad5de386cf74e2b346f10889bc46a8ad4e diff --git a/Repository.mk b/Repository.mk index 6a6b8bd12e06..e869694cde21 100644 --- a/Repository.mk +++ b/Repository.mk @@ -391,7 +391,7 @@ $(eval $(call gb_Helper_register_libraries_for_install,OOOLIBS,ooo, \ hyphen \ icg \ $(if $(ENABLE_JAVA),jdbc) \ - $(if $(filter $(OS),WNT),jumplist) \ + $(if $(filter WNT,$(OS)),jumplist) \ $(if $(ENABLE_LDAP),ldapbe2) \ $(if $(filter WNT,$(OS)),WinUserInfoBe) \ localebe1 \ diff --git a/offapi/com/sun/star/system/windows/JumpListItem.idl b/offapi/com/sun/star/system/windows/JumpListItem.idl index 310e5551911a..30a8bdd6f7e4 100755 --- a/offapi/com/sun/star/system/windows/JumpListItem.idl +++ b/offapi/com/sun/star/system/windows/JumpListItem.idl @@ -24,17 +24,27 @@ module com { module sun { module star { module system { module windows { struct JumpListItem { - /** Item name. Appears in the JumpList. Has to be unique per category. */ + /** Item name. Appears in the JumpList. + Has to be unique per category. + Must not include embedded NULs ('\\0'). */ string name; - /** Item description, appears as tooltip */ + /** Item description, appears as tooltip. + Must not include embedded NULs ('\\0'). + */ string description; /** Arguments to be passed to LibreOffice. - This can be a file to be loaded, or any command line parameter supported by LibreOffice, and any combination of the two. */ + This can be a file to be loaded, or any command line parameter supported by LibreOffice, and any combination of the two. + Add multiple arguments separated by space. + Must not include embedded NULs ('\\0'). + */ string arguments; - /** Icon to be displayed along the name. This should be a local path name like `C:\path\to\icon` */ + /** Icon to be displayed along the name. + Must be a local path name like `C:\\path\\to\\icon.ico`. + Icon must be in ICO format. + */ string iconPath; }; diff --git a/offapi/com/sun/star/system/windows/XJumpList.idl b/offapi/com/sun/star/system/windows/XJumpList.idl index c483149e5dd8..80fef03b60aa 100755 --- a/offapi/com/sun/star/system/windows/XJumpList.idl +++ b/offapi/com/sun/star/system/windows/XJumpList.idl @@ -23,16 +23,26 @@ module com { module sun { module star { module system { module windows { */ interface XJumpList: com::sun::star::uno::XInterface { - /** Add a jump list category + /** Add (or update) a jump list category. + + Note that it is only possible to have one jump list category per `application`. + + When there is already a jump list for the given `application`, + that jump list will be cleared, and the new `category` and `jumpListItems` will be added. @param category Specifies the category name. It will appear as the title of the custom jump list. + Must not include embedded NULs ('\\0') @param jumpListItems Specifies a list of com::sun::star::system::JumpListItem. + Must contain at least one item. These will be added as entries below the category name in the custom jump list. + Make sure you don't add items which the user has removed before (check the result of `getRemovedItems` before updating a category). + If you try to add items which the user removed before, + they will be silently ignored and not added to the list. @param application Used to map the jump list to the correct application. Use one of the following values: @@ -49,16 +59,43 @@ interface XJumpList: com::sun::star::uno::XInterface "Startcenter" will map to the generic "LibreOffice" icon. @throws com::sun::star::lang::IllegalArgumentException - When an empty category name, or an invalid application name is given. + When one of the following applies: + <ul> + <li>`category` is empty</li> + <li>`jumpListItems` is empty or contains only items which were removed by the user</li> + <li>`application` is invalid</li> + </ul> */ void appendCategory( [in] string category, [in] sequence<com::sun::star::system::windows::JumpListItem> jumpListItems, [in] string application ) raises( ::com::sun::star::lang::IllegalArgumentException ); + /** Delete a jump list category + + @param application + Used to map the jump list to the correct application. Use one of the following values: + <ul> + <li>Writer</li> + <li>Calc</li> + <li>Impress</li> + <li>Draw</li> + <li>Math</li> + <li>Base</li> + <li>Startcenter</li> + </ul> + + "Startcenter" will map to the generic "LibreOffice" icon. + + @throws com::sun::star::lang::IllegalArgumentException + When `application` is invalid + */ + void deleteCategory( [in] string application ) + raises( ::com::sun::star::lang::IllegalArgumentException ); + /** Returns items that were removed from the jump list by the user. - `appendCategory` will fail if you try to reinsert an item which was removed by the user before. + `appendCategory` will ignore items which were removed by the user before. Use this method to learn which items were removed by the user. @param application diff --git a/shell/source/win32/jumplist/JumpList.cxx b/shell/source/win32/jumplist/JumpList.cxx index 74874c8bc53e..cbc72299b41a 100755 --- a/shell/source/win32/jumplist/JumpList.cxx +++ b/shell/source/win32/jumplist/JumpList.cxx @@ -12,10 +12,10 @@ #include <algorithm> #include <cassert> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> #include <comphelper/sequence.hxx> #include <cppuhelper/supportsservice.hxx> -#include <cppuhelper/compbase.hxx> - #include <o3tl/char16_t2wchar_t.hxx> #include <o3tl/runtimetooustring.hxx> #include <o3tl/safeCoInitUninit.hxx> @@ -23,6 +23,7 @@ #include <osl/mutex.hxx> #include <osl/process.h> #include <sal/log.hxx> +#include <systools/win32/comtools.hxx> #include <com/sun/star/lang/IllegalArgumentException.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> @@ -34,7 +35,6 @@ #include <Shlobj.h> #include <propkey.h> #include <propvarutil.h> -#include <systools/win32/comtools.hxx> #include <postwin.h> using namespace comphelper; @@ -44,16 +44,14 @@ using namespace css::uno; using namespace css::lang; using namespace css::system::windows; using namespace osl; - using sal::systools::COMReference; using sal::systools::COM_QUERY_THROW; using sal::systools::ComError; using sal::systools::ThrowIfFailed; -class JumpListImpl : public WeakComponentImplHelper<XJumpList, XServiceInfo> +class JumpListImpl : public BaseMutex, public WeakComponentImplHelper<XJumpList, XServiceInfo> { Reference<XComponentContext> m_xContext; - Mutex m_aMutex; public: explicit JumpListImpl(const Reference<XComponentContext>& xContext); @@ -62,9 +60,9 @@ public: // XJumpList virtual void SAL_CALL appendCategory(const OUString& sCategory, const Sequence<JumpListItem>& aJumpListItems, - const OUString& sDocumentService) override; - virtual Sequence<JumpListItem> - SAL_CALL getRemovedItems(const OUString& sDocumentService) override; + const OUString& sApplication) override; + virtual void SAL_CALL deleteCategory(const OUString& sApplication) override; + virtual Sequence<JumpListItem> SAL_CALL getRemovedItems(const OUString& sApplication) override; // XServiceInfo virtual OUString SAL_CALL getImplementationName() override; @@ -80,6 +78,39 @@ JumpListImpl::JumpListImpl(const Reference<XComponentContext>& xContext) JumpListImpl::~JumpListImpl() {} +namespace +{ +// Determines if the provided IShellLinkItem is listed in the array of items that the user has removed +bool lcl_isItemInArray(COMReference<IShellLinkW> pShellLinkItem, + COMReference<IObjectArray> poaRemoved) +{ + UINT nItems; + ThrowIfFailed(poaRemoved->GetCount(&nItems), "GetCount failed."); + + COMReference<IShellLinkW> pShellLinkItemCompare; + for (UINT i = 0; i < nItems; i++) + { + if (!SUCCEEDED(poaRemoved->GetAt(i, IID_PPV_ARGS(&pShellLinkItemCompare)))) + continue; + + PROPVARIANT propvar; + COMReference<IPropertyStore> pps(pShellLinkItem, COM_QUERY_THROW); + ThrowIfFailed(pps->GetValue(PKEY_Title, &propvar), "GetValue failed."); + OUString title(o3tl::toU(PropVariantToStringWithDefault(propvar, L""))); + + COMReference<IPropertyStore> ppsCompare(pShellLinkItemCompare, COM_QUERY_THROW); + ThrowIfFailed(ppsCompare->GetValue(PKEY_Title, &propvar), "GetValue failed."); + OUString titleCompare(o3tl::toU(PropVariantToStringWithDefault(propvar, L""))); + PropVariantClear(&propvar); + + if (title == titleCompare) + return true; + } + + return false; +} +} + void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, const Sequence<JumpListItem>& aJumpListItems, const OUString& sApplication) @@ -143,7 +174,7 @@ void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, COMReference<IPropertyStore> pps(pShellLinkItem, COM_QUERY_THROW); PROPVARIANT propvar; - sal::systools::ThrowIfFailed( + ThrowIfFailed( InitPropVariantFromString(o3tl::toW(item.name.getStr()), &propvar), "InitPropVariantFromString failed."); @@ -168,6 +199,14 @@ void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, pShellLinkItem->SetIconLocation(o3tl::toW(item.iconPath.getStr()), 0), OString("Setting icon path '" + item.iconPath.toUtf8() + "' failed.")); + if (lcl_isItemInArray(pShellLinkItem, removed)) + { + SAL_INFO("shell.jumplist", "Ignoring item '" + << item.name + << "' (was removed by user). See output of " + "XJumpList::getRemovedItems()."); + continue; + } aCollection->AddObject(pShellLinkItem.get()); } catch (const ComError& e) @@ -177,11 +216,20 @@ void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, } } - sal::systools::COMReference<IObjectArray> pObjectArray(aCollection, COM_QUERY_THROW); + COMReference<IObjectArray> pObjectArray(aCollection, COM_QUERY_THROW); + UINT nItems; + ThrowIfFailed(pObjectArray->GetCount(&nItems), "GetCount failed."); + if (nItems == 0) + { + throw IllegalArgumentException( + "No valid items given. `jumpListItems` is either empty, or contains only items " + "which were removed by the user. See `XJumpList::getRemovedItems()`.", + static_cast<OWeakObject*>(this), 1); + } + ThrowIfFailed( aDestinationList->AppendCategory(o3tl::toW(sCategory.getStr()), pObjectArray.get()), - "AppendCategory failed. You are not allowed to immediately re-insert entries which " - "were removed by the user. Please see the output of `getRemovedItems`."); + "AppendCategory failed."); ThrowIfFailed(aDestinationList->CommitList(), "CommitList failed."); } @@ -191,6 +239,32 @@ void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, } } +void SAL_CALL JumpListImpl::deleteCategory(const OUString& sApplication) +{ + if (sApplication != "Writer" && sApplication != "Calc" && sApplication != "Impress" + && sApplication != "Draw" && sApplication != "Math" && sApplication != "Base" + && sApplication != "Startcenter") + { + throw IllegalArgumentException( + "Parameter 'application' must be one of 'Writer', 'Calc', 'Impress', 'Draw', " + "'Math', 'Base', 'Startcenter'.", + static_cast<OWeakObject*>(this), 1); + } + OUString sApplicationID("TheDocumentFoundation.LibreOffice." + sApplication); + + try + { + COMReference<ICustomDestinationList> aDestinationList; + CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&aDestinationList)); + aDestinationList->DeleteList(o3tl::toW(sApplicationID.getStr())); + } + catch (const ComError& e) + { + SAL_WARN("shell.jumplist", e.what()); + } +} + Sequence<JumpListItem> SAL_CALL JumpListImpl::getRemovedItems(const OUString& sApplication) { if (sApplication != "Writer" && sApplication != "Calc" && sApplication != "Impress"