From e07e1931ac3d2e270d7696f631aba39ea54ba3c4 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 15 Sep 2013 16:10:13 +0200 Subject: Add QWinJumpList::identifier Change-Id: I38576256f2f90f9528a7210537255e35e4c598a9 Reviewed-by: Friedemann Kleint --- src/winextras/qwinjumplist.cpp | 72 +++++++++++++++++++++++++++++++--- src/winextras/qwinjumplist.h | 4 ++ src/winextras/qwinjumplist_p.h | 1 + src/winextras/qwinjumplistcategory.cpp | 49 ++++++++++++++++------- src/winextras/qwinjumplistcategory_p.h | 2 - src/winextras/winshobjidl_p.h | 12 ++++++ 6 files changed, 119 insertions(+), 21 deletions(-) diff --git a/src/winextras/qwinjumplist.cpp b/src/winextras/qwinjumplist.cpp index b0c4277..cc05c0e 100644 --- a/src/winextras/qwinjumplist.cpp +++ b/src/winextras/qwinjumplist.cpp @@ -69,6 +69,11 @@ QT_BEGIN_NAMESPACE files or to display shortcuts to tasks or commands. */ +/*! + \title Application User Model IDs + \externalpage http://msdn.microsoft.com/en-us/library/windows/desktop/dd378459%28v=vs.85%29.aspx + */ + // partial copy of qprocess_win.cpp:qt_create_commandline() static QString createArguments(const QStringList &arguments) { @@ -92,6 +97,17 @@ static QString createArguments(const QStringList &arguments) return args; } +static QString defaultIdentifier() +{ + // CompanyName.ProductName(.SubProduct).VersionInformation + QStringList identifier(QCoreApplication::applicationName()); + if (!QCoreApplication::organizationName().isEmpty()) + identifier.prepend(QCoreApplication::organizationName()); + if (!QCoreApplication::applicationVersion().isEmpty()) + identifier.append(QCoreApplication::applicationVersion()); + return identifier.join(QLatin1Char('.')); +} + QWinJumpListPrivate::QWinJumpListPrivate() : pDestList(0), recent(0), frequent(0), tasks(0), dirty(false) { @@ -155,13 +171,21 @@ void QWinJumpListPrivate::destroy() bool QWinJumpListPrivate::beginList() { - UINT maxSlots; - IUnknown *array = 0; - HRESULT hresult = pDestList->BeginList(&maxSlots, IID_IUnknown, reinterpret_cast(&array)); + HRESULT hresult = S_OK; + if (!identifier.isEmpty()) { + wchar_t *id = qt_qstringToNullTerminated(identifier); + hresult = pDestList->SetAppID(id); + delete[] id; + } + if (SUCCEEDED(hresult)) { + UINT maxSlots = 0; + IUnknown *array = 0; + hresult = pDestList->BeginList(&maxSlots, IID_IUnknown, reinterpret_cast(&array)); + if (array) + array->Release(); + } if (FAILED(hresult)) QWinJumpListPrivate::warning("BeginList", hresult); - if (array) - array->Release(); return SUCCEEDED(hresult); } @@ -409,6 +433,7 @@ QWinJumpList::QWinJumpList(QObject *parent) : HRESULT hresult = CoCreateInstance(CLSID_DestinationList, 0, CLSCTX_INPROC_SERVER, IID_ICustomDestinationList, reinterpret_cast(&d_ptr->pDestList)); if (FAILED(hresult)) QWinJumpListPrivate::warning("CoCreateInstance", hresult); + setIdentifier(defaultIdentifier()); d->invalidate(); } @@ -427,6 +452,43 @@ QWinJumpList::~QWinJumpList() d->destroy(); } +/*! + \property QWinJumpList::identifier + \brief the jump list identifier + + Specifies a unique identifier for the application jump list. + See \l {Application User Model IDs} on MSDN for further details. + + The default value is based on: + \list + \li QCoreApplication::organizationName + \li QCoreApplication::applicationName + \li QCoreApplication::applicationVersion + \endlist + + \note The identifier cannot have more than \c 128 characters and + cannot contain spaces. A too long identifier is automatically truncated + to \c 128 characters, and spaces are replaced by underscores. + */ +QString QWinJumpList::identifier() const +{ + Q_D(const QWinJumpList); + return d->identifier; +} + +void QWinJumpList::setIdentifier(const QString &identifier) +{ + Q_D(QWinJumpList); + QString id = identifier; + id.replace(QLatin1Char(' '), QLatin1Char('_')); + if (id.size() > 128) + id.truncate(128); + if (d->identifier != id) { + d->identifier = id; + d->invalidate(); + } +} + /*! Returns the recent items category in the jump list. */ diff --git a/src/winextras/qwinjumplist.h b/src/winextras/qwinjumplist.h index bc4f431..08dfa3e 100644 --- a/src/winextras/qwinjumplist.h +++ b/src/winextras/qwinjumplist.h @@ -57,11 +57,15 @@ class QWinJumpListCategory; class Q_WINEXTRAS_EXPORT QWinJumpList : public QObject { Q_OBJECT + Q_PROPERTY(QString identifier READ identifier WRITE setIdentifier) public: explicit QWinJumpList(QObject *parent = 0); ~QWinJumpList(); + QString identifier() const; + void setIdentifier(const QString &identifier); + QWinJumpListCategory *recent() const; QWinJumpListCategory *frequent() const; QWinJumpListCategory *tasks() const; diff --git a/src/winextras/qwinjumplist_p.h b/src/winextras/qwinjumplist_p.h index ca21e33..aa3a754 100644 --- a/src/winextras/qwinjumplist_p.h +++ b/src/winextras/qwinjumplist_p.h @@ -89,6 +89,7 @@ public: QWinJumpListCategory *frequent; QWinJumpListCategory *tasks; QList categories; + QString identifier; bool dirty; }; diff --git a/src/winextras/qwinjumplistcategory.cpp b/src/winextras/qwinjumplistcategory.cpp index c338bf6..25b10a2 100644 --- a/src/winextras/qwinjumplistcategory.cpp +++ b/src/winextras/qwinjumplistcategory.cpp @@ -45,6 +45,7 @@ #include "qwinjumplistitem_p.h" #include "qwinfunctions_p.h" #include "qwinjumplist_p.h" +#include "winshobjidl_p.h" #include @@ -73,7 +74,7 @@ QT_BEGIN_NAMESPACE */ QWinJumpListCategoryPrivate::QWinJumpListCategoryPrivate() : - visible(false), jumpList(0), type(QWinJumpListCategory::Custom), pDocList(0) + visible(false), jumpList(0), type(QWinJumpListCategory::Custom) { } @@ -95,15 +96,25 @@ void QWinJumpListCategoryPrivate::invalidate() void QWinJumpListCategoryPrivate::loadRecents() { + Q_ASSERT(jumpList); + IApplicationDocumentLists *pDocList = 0; HRESULT hresult = CoCreateInstance(CLSID_ApplicationDocumentLists, 0, CLSCTX_INPROC_SERVER, IID_IApplicationDocumentLists, reinterpret_cast(&pDocList)); if (SUCCEEDED(hresult)) { - IObjectArray *array = 0; - hresult = pDocList->GetList(type == QWinJumpListCategory::Recent ? ADLT_RECENT : ADLT_FREQUENT, - 0, IID_IObjectArray, reinterpret_cast(&array)); + if (!jumpList->identifier().isEmpty()) { + wchar_t *id = qt_qstringToNullTerminated(jumpList->identifier()); + hresult = pDocList->SetAppID(id); + delete[] id; + } if (SUCCEEDED(hresult)) { - items = QWinJumpListPrivate::fromComCollection(array); - array->Release(); + IObjectArray *array = 0; + hresult = pDocList->GetList(type == QWinJumpListCategory::Recent ? ADLT_RECENT : ADLT_FREQUENT, + 0, IID_IObjectArray, reinterpret_cast(&array)); + if (SUCCEEDED(hresult)) { + items = QWinJumpListPrivate::fromComCollection(array); + array->Release(); + } } + pDocList->Release(); } if (FAILED(hresult)) QWinJumpListPrivate::warning("loadRecents", hresult); @@ -111,10 +122,18 @@ void QWinJumpListCategoryPrivate::loadRecents() void QWinJumpListCategoryPrivate::addRecent(QWinJumpListItem *item) { - if (item->type() == QWinJumpListItem::Link) - SHAddToRecentDocs(SHARD_LINK, QWinJumpListPrivate::toIShellLink(item)); - else if (item->type() == QWinJumpListItem::Destination) - SHAddToRecentDocs(SHARD_SHELLITEM, QWinJumpListPrivate::toIShellItem(item)); + Q_ASSERT(item->type() == QWinJumpListItem::Link); + const QString identifier = jumpList ? jumpList->identifier() : QString(); + wchar_t *id = qt_qstringToNullTerminated(identifier); + + SHARDAPPIDINFOLINK info; + info.pszAppID = id; + info.psl = QWinJumpListPrivate::toIShellLink(item); + if (info.psl) { + SHAddToRecentDocs(SHARD_APPIDINFOLINK, &info); + info.psl->Release(); + } + delete[] id; } void QWinJumpListCategoryPrivate::clearRecents() @@ -122,6 +141,12 @@ void QWinJumpListCategoryPrivate::clearRecents() IApplicationDestinations *pDest = 0; HRESULT hresult = CoCreateInstance(CLSID_ApplicationDestinations, 0, CLSCTX_INPROC_SERVER, IID_IApplicationDestinations, reinterpret_cast(&pDest)); if (SUCCEEDED(hresult)) { + const QString identifier = jumpList ? jumpList->identifier() : QString(); + if (!identifier.isEmpty()) { + wchar_t *id = qt_qstringToNullTerminated(identifier); + hresult = pDest->SetAppID(id); + delete[] id; + } hresult = pDest->RemoveAllDestinations(); pDest->Release(); } @@ -144,10 +169,6 @@ QWinJumpListCategory::QWinJumpListCategory(const QString &title) : QWinJumpListCategory::~QWinJumpListCategory() { Q_D(QWinJumpListCategory); - if (d->pDocList) { - d->pDocList->Release(); - d->pDocList = 0; - } qDeleteAll(d->items); d->items.clear(); } diff --git a/src/winextras/qwinjumplistcategory_p.h b/src/winextras/qwinjumplistcategory_p.h index d49c6f6..7dcef1c 100644 --- a/src/winextras/qwinjumplistcategory_p.h +++ b/src/winextras/qwinjumplistcategory_p.h @@ -44,7 +44,6 @@ #define QWINJUMPLISTCATEGORY_P_H #include "qwinjumplistcategory.h" -#include "winshobjidl_p.h" QT_BEGIN_NAMESPACE @@ -72,7 +71,6 @@ public: QWinJumpList *jumpList; QWinJumpListCategory::Type type; QList items; - IApplicationDocumentLists *pDocList; }; QT_END_NAMESPACE diff --git a/src/winextras/winshobjidl_p.h b/src/winextras/winshobjidl_p.h index f0f8857..29d27aa 100644 --- a/src/winextras/winshobjidl_p.h +++ b/src/winextras/winshobjidl_p.h @@ -242,4 +242,16 @@ public: #endif +#if (defined _MSC_VER && _MSC_VER < 1600) || defined(Q_CC_MINGW) + +typedef struct SHARDAPPIDINFOLINK +{ + IShellLink *psl; // An IShellLink instance that when launched opens a recently used item in the specified + // application. This link is not added to the recent docs folder, but will be added to the + // specified application's destination list. + PCWSTR pszAppID; // The id of the application that should be associated with this recent doc. +} SHARDAPPIDINFOLINK; + +#endif + #endif // ITASKBARLIST_H -- cgit v1.2.3