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"

Reply via email to