diff options
author | Samuel Mehrbrodt <samuel.mehrbrodt@allotropia.de> | 2022-04-25 10:53:09 +0200 |
---|---|---|
committer | Samuel Mehrbrodt <samuel.mehrbrodt@allotropia.de> | 2022-04-26 11:46:17 +0200 |
commit | 675788b208a7c775f8eaa51cd90528b1bb92ed79 (patch) | |
tree | 35d508928327bcc2b7d557811d7cc8032732ae65 /shell | |
parent | 90057e372cd07b41c8dbba4e7b7f107568a5f451 (diff) |
Extend UNO API for custom jump lists
* Allow to display the recent/frequent files
* Allow adding items to the "Tasks" category
* Allow adding multiple categories
Follow-up to 7efd22c912262f7bf4e4735dae70db0b31ab3d5b
Change-Id: I860d44c1a0d9bc8200529c908b6103741dc37bb5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133367
Tested-by: Jenkins
Reviewed-by: Samuel Mehrbrodt <samuel.mehrbrodt@allotropia.de>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/source/win32/jumplist/JumpList.cxx | 224 |
1 files changed, 202 insertions, 22 deletions
diff --git a/shell/source/win32/jumplist/JumpList.cxx b/shell/source/win32/jumplist/JumpList.cxx index f5d8ca8532cd..06a62a11038d 100644 --- a/shell/source/win32/jumplist/JumpList.cxx +++ b/shell/source/win32/jumplist/JumpList.cxx @@ -30,6 +30,7 @@ #include <com/sun/star/system/windows/JumpListItem.hpp> #include <com/sun/star/system/windows/XJumpList.hpp> #include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/InvalidStateException.hpp> #include <prewin.h> #include <Shlobj.h> @@ -43,6 +44,7 @@ using namespace css; using namespace css::uno; using namespace css::lang; using namespace css::system::windows; +using namespace css::util; using namespace osl; using namespace sal::systools; @@ -51,15 +53,23 @@ namespace class JumpListImpl : public BaseMutex, public WeakComponentImplHelper<XJumpList, XServiceInfo> { Reference<XComponentContext> m_xContext; + COMReference<ICustomDestinationList> m_aDestinationList; + COMReference<IObjectArray> m_aRemoved; + bool m_isListOpen; public: explicit JumpListImpl(const Reference<XComponentContext>& xContext); // XJumpList + virtual void SAL_CALL beginList(const OUString& sApplication) override; virtual void SAL_CALL appendCategory(const OUString& sCategory, - const Sequence<JumpListItem>& aJumpListItems, - const OUString& sApplication) override; - virtual void SAL_CALL deleteCategory(const OUString& sApplication) override; + const Sequence<JumpListItem>& aJumpListItems) override; + virtual void SAL_CALL addTasks(const Sequence<JumpListItem>& aJumpListItems) override; + virtual void SAL_CALL showRecentFiles() override; + virtual void SAL_CALL showFrequentFiles() override; + virtual void SAL_CALL commitList() override; + virtual void SAL_CALL abortList() override; + virtual void SAL_CALL deleteList(const OUString& sApplication) override; virtual Sequence<JumpListItem> SAL_CALL getRemovedItems(const OUString& sApplication) override; // XServiceInfo @@ -71,6 +81,8 @@ public: JumpListImpl::JumpListImpl(const Reference<XComponentContext>& xContext) : WeakComponentImplHelper(m_aMutex) , m_xContext(xContext) + , m_aDestinationList(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER) + , m_isListOpen(false) { } @@ -105,15 +117,11 @@ bool lcl_isItemInArray(COMReference<IShellLinkW> pShellLinkItem, } } -void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, - const Sequence<JumpListItem>& aJumpListItems, - const OUString& sApplication) +void SAL_CALL JumpListImpl::beginList(const OUString& sApplication) { - if (sCategory.isEmpty()) - { - throw IllegalArgumentException("Parameter 'category' must not be empty", - static_cast<OWeakObject*>(this), 1); - } + if (m_isListOpen) + throw InvalidStateException("There is already a list open. Close it with 'commitList'"); + if (sApplication != "Writer" && sApplication != "Calc" && sApplication != "Impress" && sApplication != "Draw" && sApplication != "Math" && sApplication != "Base" && sApplication != "Startcenter") @@ -127,16 +135,34 @@ void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, try { - COMReference<ICustomDestinationList> aDestinationList(CLSID_DestinationList, nullptr, - CLSCTX_INPROC_SERVER); - - aDestinationList->SetAppID(o3tl::toW(sApplicationID.getStr())); + m_aDestinationList->SetAppID(o3tl::toW(sApplicationID.getStr())); UINT min_slots; - COMReference<IObjectArray> removed; - ThrowIfFailed(aDestinationList->BeginList(&min_slots, IID_PPV_ARGS(&removed)), + + ThrowIfFailed(m_aDestinationList->BeginList(&min_slots, IID_PPV_ARGS(&m_aRemoved)), "BeginList failed"); + m_isListOpen = true; + } + catch (const ComError& e) + { + SAL_WARN("shell.jumplist", e.what()); + } +} +void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, + const Sequence<JumpListItem>& aJumpListItems) +{ + if (!m_isListOpen) + throw InvalidStateException("No list open. Open it with 'beginList'"); + + if (sCategory.isEmpty()) + { + throw IllegalArgumentException("Parameter 'category' must not be empty", + static_cast<OWeakObject*>(this), 1); + } + + try + { OUString sofficeURL; OUString sofficePath; oslProcessError err = osl_getExecutableFile(&sofficeURL.pData); @@ -191,7 +217,7 @@ void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, OStringConcatenation("Setting icon path '" + item.iconPath.toUtf8() + "' failed.")); - if (lcl_isItemInArray(pShellLinkItem, removed)) + if (lcl_isItemInArray(pShellLinkItem, m_aRemoved)) { SAL_INFO("shell.jumplist", "Ignoring item '" << item.name @@ -219,10 +245,96 @@ void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, static_cast<OWeakObject*>(this), 1); } - ThrowIfFailed(aDestinationList->AppendCategory(o3tl::toW(sCategory.getStr()), pObjectArray), - "AppendCategory failed."); + ThrowIfFailed( + m_aDestinationList->AppendCategory(o3tl::toW(sCategory.getStr()), pObjectArray), + "AppendCategory failed."); + } + catch (const ComError& e) + { + SAL_WARN("shell.jumplist", e.what()); + } +} + +void SAL_CALL JumpListImpl::addTasks(const Sequence<JumpListItem>& aJumpListItems) +{ + if (!m_isListOpen) + throw InvalidStateException("No list open. Open it with 'beginList'"); + + try + { + OUString sofficeURL; + OUString sofficePath; + oslProcessError err = osl_getExecutableFile(&sofficeURL.pData); + FileBase::getSystemPathFromFileURL(sofficeURL, sofficePath); + if (err != osl_Process_E_None) + { + SAL_WARN("shell.jumplist", "osl_getExecutableFile failed"); + return; + } + // We need to run soffice.exe, not soffice.bin + sofficePath = sofficePath.replaceFirst("soffice.bin", "soffice.exe"); + + COMReference<IObjectCollection> aCollection(CLSID_EnumerableObjectCollection, nullptr, + CLSCTX_INPROC_SERVER); - ThrowIfFailed(aDestinationList->CommitList(), "CommitList failed."); + for (auto const& item : aJumpListItems) + { + if (item.name.isEmpty()) + continue; + try + { + COMReference<IShellLinkW> pShellLinkItem(CLSID_ShellLink, nullptr, + CLSCTX_INPROC_SERVER); + + { + COMReference<IPropertyStore> pps(pShellLinkItem, COM_QUERY_THROW); + + PROPVARIANT propvar; + ThrowIfFailed( + InitPropVariantFromString(o3tl::toW(item.name.getStr()), &propvar), + "InitPropVariantFromString failed."); + + ThrowIfFailed(pps->SetValue(PKEY_Title, propvar), "SetValue failed."); + + ThrowIfFailed(pps->Commit(), "Commit failed."); + + PropVariantClear(&propvar); + } + ThrowIfFailed(pShellLinkItem->SetDescription(o3tl::toW(item.description.getStr())), + OStringConcatenation("Setting description '" + + item.description.toUtf8() + "' failed.")); + + ThrowIfFailed( + pShellLinkItem->SetPath(o3tl::toW(sofficePath.getStr())), + OStringConcatenation("Setting path '" + sofficePath.toUtf8() + "' failed.")); + + ThrowIfFailed(pShellLinkItem->SetArguments(o3tl::toW(item.arguments.getStr())), + OStringConcatenation("Setting arguments '" + item.arguments.toUtf8() + + "' failed.")); + + ThrowIfFailed(pShellLinkItem->SetIconLocation(o3tl::toW(item.iconPath.getStr()), 0), + OStringConcatenation("Setting icon path '" + item.iconPath.toUtf8() + + "' failed.")); + + aCollection->AddObject(pShellLinkItem); + } + catch (const ComError& e) + { + SAL_WARN("shell.jumplist", e.what()); + continue; + } + } + + 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 empty.", + static_cast<OWeakObject*>(this), 1); + } + + ThrowIfFailed(m_aDestinationList->AddUserTasks(pObjectArray), "AddUserTasks failed."); } catch (const ComError& e) { @@ -230,8 +342,76 @@ void SAL_CALL JumpListImpl::appendCategory(const OUString& sCategory, } } -void SAL_CALL JumpListImpl::deleteCategory(const OUString& sApplication) +void SAL_CALL JumpListImpl::showRecentFiles() { + if (!m_isListOpen) + throw InvalidStateException("No list open. Open it with 'beginList'"); + + try + { + ThrowIfFailed(m_aDestinationList->AppendKnownCategory(KDC_RECENT), + "AppendKnownCategory(KDC_RECENT) failed."); + } + catch (const ComError& e) + { + SAL_WARN("shell.jumplist", e.what()); + } +} + +void SAL_CALL JumpListImpl::showFrequentFiles() +{ + if (!m_isListOpen) + throw InvalidStateException("No list open. Open it with 'beginList'"); + + try + { + ThrowIfFailed(m_aDestinationList->AppendKnownCategory(KDC_FREQUENT), + "AppendKnownCategory(KDC_FREQUENT) failed."); + } + catch (const ComError& e) + { + SAL_WARN("shell.jumplist", e.what()); + } +} + +void SAL_CALL JumpListImpl::commitList() +{ + if (!m_isListOpen) + throw InvalidStateException("No list open. Open it with 'beginList'"); + + try + { + ThrowIfFailed(m_aDestinationList->CommitList(), "CommitList failed."); + m_isListOpen = false; + } + catch (const ComError& e) + { + SAL_WARN("shell.jumplist", e.what()); + } +} + +void SAL_CALL JumpListImpl::abortList() +{ + if (!m_isListOpen) + throw InvalidStateException("No list open."); + + try + { + ThrowIfFailed(m_aDestinationList->AbortList(), "AbortList failed."); + m_isListOpen = false; + } + catch (const ComError& e) + { + SAL_WARN("shell.jumplist", e.what()); + } +} + +void SAL_CALL JumpListImpl::deleteList(const OUString& sApplication) +{ + if (m_isListOpen) + throw InvalidStateException("You are in a list building session. Close it with " + "'commitList', or abort with 'abortList'"); + if (sApplication != "Writer" && sApplication != "Calc" && sApplication != "Impress" && sApplication != "Draw" && sApplication != "Math" && sApplication != "Base" && sApplication != "Startcenter") |