/**************************************************************************** ** ** Copyright (C) 2016 Ivan Vizir ** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWinExtras module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ****************************************************************************/ #include #ifdef Q_CC_MINGW // MinGW: Include the correct definition of SHARDAPPIDINFOLINK # if defined(NTDDI_VERSION) && NTDDI_VERSION < 0x06010000 # undef NTDDI_VERSION # endif # ifndef NTDDI_VERSION # define NTDDI_VERSION 0x06010000 # endif #endif // Q_CC_MINGW #include "qwinjumplistcategory.h" #include "qwinjumplistcategory_p.h" #include "qwinjumplistitem_p.h" #include "qwinfunctions_p.h" #include "qwinjumplist_p.h" #include "winshobjidl_p.h" #include "windowsguidsdefs_p.h" #include #include QT_BEGIN_NAMESPACE /*! \class QWinJumpListCategory \inmodule QtWinExtras \since 5.2 \brief The QWinJumpListCategory class represents a jump list category. */ /*! \enum QWinJumpListCategory::Type This enum describes the available QWinJumpListCategory types. \value Custom A custom jump list category. \value Recent A jump list category of "recent" items. \value Frequent A jump list category of "frequent" items. \value Tasks A jump list category of tasks. */ QWinJumpListCategory *QWinJumpListCategoryPrivate::create(QWinJumpListCategory::Type type, QWinJumpList *jumpList) { QWinJumpListCategory *category = new QWinJumpListCategory; category->d_func()->type = type; category->d_func()->jumpList = jumpList; if (type == QWinJumpListCategory::Recent || type == QWinJumpListCategory::Frequent) category->d_func()->loadRecents(); return category; } void QWinJumpListCategoryPrivate::invalidate() { if (jumpList) QWinJumpListPrivate::get(jumpList)->invalidate(); } void QWinJumpListCategoryPrivate::loadRecents() { Q_ASSERT(jumpList); IApplicationDocumentLists *pDocList = nullptr; HRESULT hresult = CoCreateInstance(qCLSID_ApplicationDocumentLists, nullptr, CLSCTX_INPROC_SERVER, qIID_IApplicationDocumentLists, reinterpret_cast(&pDocList)); if (SUCCEEDED(hresult)) { if (!jumpList->identifier().isEmpty()) { wchar_t *id = qt_qstringToNullTerminated(jumpList->identifier()); hresult = pDocList->SetAppID(id); delete[] id; } if (SUCCEEDED(hresult)) { IObjectArray *array = nullptr; hresult = pDocList->GetList(type == QWinJumpListCategory::Recent ? ADLT_RECENT : ADLT_FREQUENT, 0, qIID_IObjectArray, reinterpret_cast(&array)); if (SUCCEEDED(hresult)) { items = QWinJumpListPrivate::fromComCollection(array); array->Release(); } } pDocList->Release(); } if (FAILED(hresult)) QWinJumpListPrivate::warning("loadRecents", hresult); } void QWinJumpListCategoryPrivate::addRecent(QWinJumpListItem *item) { Q_ASSERT(item->type() == QWinJumpListItem::Link); wchar_t *id = nullptr; if (jumpList && !jumpList->identifier().isEmpty()) id = qt_qstringToNullTerminated(jumpList->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() { IApplicationDestinations *pDest = nullptr; HRESULT hresult = CoCreateInstance(qCLSID_ApplicationDestinations, nullptr, CLSCTX_INPROC_SERVER, qIID_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(); } if (FAILED(hresult)) QWinJumpListPrivate::warning("clearRecents", hresult); } /*! Constructs a custom QWinJumpListCategory with the specified \a title. */ QWinJumpListCategory::QWinJumpListCategory(const QString &title) : d_ptr(new QWinJumpListCategoryPrivate) { d_ptr->title = title; } /*! Destroys the QWinJumpListCategory. */ QWinJumpListCategory::~QWinJumpListCategory() { Q_D(QWinJumpListCategory); qDeleteAll(d->items); d->items.clear(); } /*! Returns the category type. */ QWinJumpListCategory::Type QWinJumpListCategory::type() const { Q_D(const QWinJumpListCategory); return d->type; } /*! Returns whether the category is visible. */ bool QWinJumpListCategory::isVisible() const { Q_D(const QWinJumpListCategory); return d->visible; } /*! Sets the category \a visible. */ void QWinJumpListCategory::setVisible(bool visible) { Q_D(QWinJumpListCategory); if (d->visible != visible) { d->visible = visible; d->invalidate(); } } /*! Returns the category title. */ QString QWinJumpListCategory::title() const { Q_D(const QWinJumpListCategory); return d->title; } /*! Sets the category \a title. */ void QWinJumpListCategory::setTitle(const QString &title) { Q_D(QWinJumpListCategory); if (d->title != title) { d->title = title; d->invalidate(); } } /*! Returns the amount of items in the category. */ int QWinJumpListCategory::count() const { Q_D(const QWinJumpListCategory); return d->items.count(); } /*! Returns whether the category is empty. */ bool QWinJumpListCategory::isEmpty() const { Q_D(const QWinJumpListCategory); return d->items.isEmpty(); } /*! Returns the list of items in the category. */ QList QWinJumpListCategory::items() const { Q_D(const QWinJumpListCategory); return d->items; } /*! Adds an \a item to the category. */ void QWinJumpListCategory::addItem(QWinJumpListItem *item) { Q_D(QWinJumpListCategory); if (!item) return; if (d->type == Recent || d->type == Frequent) { if (item->type() == QWinJumpListItem::Separator) { qWarning("QWinJumpListCategory::addItem(): only tasks/custom categories support separators."); return; } if (item->type() == QWinJumpListItem::Destination) { qWarning("QWinJumpListCategory::addItem(): only tasks/custom categories support destinations."); return; } } QWinJumpListItemPrivate *p = QWinJumpListItemPrivate::get(item); if (p->category != this) { p->category = this; d->items.append(item); if (d->type == QWinJumpListCategory::Recent || d->type == QWinJumpListCategory::Frequent) d->addRecent(item); d->invalidate(); } } /*! Adds a destination to the category pointing to \a filePath. */ QWinJumpListItem *QWinJumpListCategory::addDestination(const QString &filePath) { auto *item = new QWinJumpListItem(QWinJumpListItem::Destination); item->setFilePath(filePath); addItem(item); return item; } /*! Adds a link to the category using \a title, \a executablePath, and optionally \a arguments. */ QWinJumpListItem *QWinJumpListCategory::addLink(const QString &title, const QString &executablePath, const QStringList &arguments) { return addLink(QIcon(), title, executablePath, arguments); } /*! \overload addLink() Adds a link to the category using \a icon, \a title, \a executablePath, and optionally \a arguments. */ QWinJumpListItem *QWinJumpListCategory::addLink(const QIcon &icon, const QString &title, const QString &executablePath, const QStringList &arguments) { auto *item = new QWinJumpListItem(QWinJumpListItem::Link); item->setFilePath(executablePath); item->setTitle(title); item->setArguments(arguments); item->setIcon(icon); addItem(item); return item; } /*! Adds a separator to the category. \note Only tasks category supports separators. */ QWinJumpListItem *QWinJumpListCategory::addSeparator() { auto *item = new QWinJumpListItem(QWinJumpListItem::Separator); addItem(item); return item; } /*! Clears the category. */ void QWinJumpListCategory::clear() { Q_D(QWinJumpListCategory); if (!d->items.isEmpty()) { qDeleteAll(d->items); d->items.clear(); if (d->type == QWinJumpListCategory::Recent || d->type == QWinJumpListCategory::Frequent) d->clearRecents(); d->invalidate(); } } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const QWinJumpListCategory *category) { QDebugStateSaver saver(debug); debug.nospace(); debug.noquote(); debug << "QWinJumpListCategory("; if (category) { debug << "type=" << category->type() << ", isVisible=" << category->isVisible() << ", title=\"" << category->title() << "\", items=" << category->items(); } else { debug << '0'; } debug << ')'; return debug; return debug; } #endif // !QT_NO_DEBUG_STREAM QT_END_NAMESPACE