| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 Ivan Vizir <define-true-false@yandex.com> |
| ** Copyright (C) 2016 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:LGPL$ |
| ** 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. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include <QtCore/qglobal.h> |
| |
| #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 <QtCore/qdebug.h> |
| |
| #include <shlobj.h> |
| |
| 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<void **>(&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<void **>(&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<void **>(&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<QWinJumpListItem *> 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 |