diff --git a/src/ui/itemsgridviewdelegate.cpp b/src/ui/itemsgridviewdelegate.cpp index 1a5a3ff0..34c7863f 100644 --- a/src/ui/itemsgridviewdelegate.cpp +++ b/src/ui/itemsgridviewdelegate.cpp @@ -1,378 +1,386 @@ /* Copyright (C) 2008 Jeremy Whiting Copyright (C) 2010 Reza Fatahilah Shah Copyright (C) 2010 Frederik Gladhorn This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "itemsgridviewdelegate_p.h" #include #include #include #include #include #include #include #include +#include #include #include #include #include #include "core/itemsmodel.h" namespace KNS3 { enum { DelegateTitleLabel, DelegateAuthorLabel, DelegateDownloadCounterLabel, DelegateGridRatingWidget }; ItemsGridViewDelegate::ItemsGridViewDelegate(QAbstractItemView *itemView, KNSCore::Engine *engine, QObject *parent) : ItemsViewBaseDelegate(itemView, engine, parent) , m_elementYPos(0) { createOperationBar(); } ItemsGridViewDelegate::~ItemsGridViewDelegate() { } QList ItemsGridViewDelegate::createItemWidgets(const QModelIndex &index) const { Q_UNUSED(index) QList m_widgetList; KSqueezedTextLabel *titleLabel = new KSqueezedTextLabel(); titleLabel->setOpenExternalLinks(true); titleLabel->setTextElideMode(Qt::ElideRight); // not so nice - work around constness to install the event filter ItemsGridViewDelegate *delegate = const_cast(this); titleLabel->installEventFilter(delegate); m_widgetList << titleLabel; KSqueezedTextLabel *authorLabel = new KSqueezedTextLabel(); authorLabel->setTextElideMode(Qt::ElideRight); m_widgetList << authorLabel; KSqueezedTextLabel *downloadCounterLabel = new KSqueezedTextLabel(); downloadCounterLabel->setTextElideMode(Qt::ElideRight); m_widgetList << downloadCounterLabel; KRatingWidget *rating = new KRatingWidget(); rating->setMaxRating(10); rating->setHalfStepsEnabled(true); m_widgetList << rating; return m_widgetList; } void ItemsGridViewDelegate::updateItemWidgets(const QList widgets, const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const { const KNSCore::ItemsModel *model = qobject_cast(index.model()); if (!model) { qCDebug(KNEWSTUFF) << "WARNING - INVALID MODEL!"; return; } KNSCore::EntryInternal entry = index.data(Qt::UserRole).value(); int elementYPos = KNSCore::PreviewHeight + ItemMargin + FrameThickness * 2; //setup rating widget KRatingWidget *rating = qobject_cast(widgets.at(DelegateGridRatingWidget)); if (rating) { if (entry.rating() > 0) { rating->setToolTip(i18n("Rating: %1%", entry.rating())); // assume all entries come with rating 0..100 but most are in the range 20 - 80, so 20 is 0 stars, 80 is 5 stars rating->setRating((entry.rating() - 20) * 10 / 60); //make the rating widget smaller than the one at list view int newWidth = 68; QSize size(newWidth, 15); rating->resize(size); //put rating widget under image rectangle rating->move((ItemGridWidth - newWidth) / 2, elementYPos); elementYPos += rating->height(); } else { //is it better to stay visible? rating->setVisible(false); } } elementYPos += ItemMargin; //setup title label QLabel *titleLabel = qobject_cast(widgets.at(DelegateTitleLabel)); if (titleLabel != nullptr) { titleLabel->setWordWrap(true); titleLabel->setAlignment(Qt::AlignHCenter); //titleLabel->setFrameStyle(QFrame::Panel); titleLabel->resize(QSize(option.rect.width() - (ItemMargin * 2), option.fontMetrics.height() * 2)); titleLabel->move((ItemGridWidth - titleLabel->width()) / 2, elementYPos); QString title; QUrl link = qvariant_cast(entry.homepage()); if (!link.isEmpty()) { title += "" + entry.name() + "\n"; } else { title += "" + entry.name() + ""; } + + const auto downloadInfo = entry.downloadLinkInformationList(); + if (!downloadInfo.isEmpty() && downloadInfo.at(0).size > 0) { + QString sizeString = KFormat().formatByteSize(downloadInfo.at(0).size * 1000); + title += i18nc("Show the size of the file in a list", "
Size: ") + sizeString; + } + titleLabel->setText(title); elementYPos += titleLabel->height(); } //setup author label QLabel *authorLabel = qobject_cast(widgets.at(DelegateAuthorLabel)); if (authorLabel != nullptr) { authorLabel->setWordWrap(true); authorLabel->setAlignment(Qt::AlignHCenter); authorLabel->resize(QSize(option.rect.width() - (ItemMargin * 2), option.fontMetrics.height())); authorLabel->move((ItemGridWidth - authorLabel->width()) / 2, elementYPos); QString text; QString authorName = entry.author().name(); QString email = entry.author().email(); QString authorPage = entry.author().homepage(); if (!authorName.isEmpty()) { if (!authorPage.isEmpty()) { text += "

" + i18nc("Show the author of this item in a list", "By %1", " " + authorName + "") + "

\n"; } else if (!email.isEmpty()) { text += "

" + i18nc("Show the author of this item in a list", "By %1", authorName) + " " + email + "

\n"; } else { text += "

" + i18nc("Show the author of this item in a list", "By %1", authorName) + "

\n"; } } authorLabel->setText(text); elementYPos += authorLabel->height(); } elementYPos += ItemMargin; //setup download label QLabel *downloadLabel = qobject_cast(widgets.at(DelegateDownloadCounterLabel)); if (downloadLabel != nullptr) { downloadLabel->setWordWrap(true); downloadLabel->setAlignment(Qt::AlignHCenter); downloadLabel->resize(QSize(option.rect.width() - (ItemMargin * 2), option.fontMetrics.height())); downloadLabel->move((ItemGridWidth - downloadLabel->width()) / 2, elementYPos); unsigned int fans = entry.numberFans(); unsigned int downloads = entry.downloadCount(); QString text; QString fanString; QString downloadString; if (fans > 0) { fanString = i18ncp("fan as in supporter", "1 fan", "%1 fans", fans); } if (downloads > 0) { downloadString = i18np("1 download", "%1 downloads", downloads); } if (downloads > 0 || fans > 0) { text += "

" + downloadString; if (downloads > 0 && fans > 0) { text += QLatin1String(", "); } text += fanString + QLatin1String("

"); } downloadLabel->setText(text); elementYPos += downloadLabel->height(); } elementYPos += ItemMargin; m_elementYPos = elementYPos; } void ItemsGridViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (option.state & QStyle::State_MouseOver) { QModelIndex focIndex = focusedIndex(); if (m_oldIndex != focIndex || !m_operationBar->isVisible()) { ItemsGridViewDelegate *delegate = const_cast(this); delegate->displayOperationBar(option.rect, index); delegate->m_oldIndex = focIndex; } } else { QModelIndex focindex = focusedIndex(); if (!focindex.isValid()) { qCDebug(KNEWSTUFF) << "INVALID hide selection"; m_operationBar->hide(); } } QStyle *style = QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, nullptr); painter->save(); if (option.state & QStyle::State_Selected) { painter->setPen(QPen(option.palette.highlightedText().color())); } else { painter->setPen(QPen(option.palette.text().color())); } const KNSCore::ItemsModel *realmodel = qobject_cast(index.model()); if (realmodel->hasPreviewImages()) { int width = option.rect.width(); KNSCore::EntryInternal entry = index.data(Qt::UserRole).value(); if (entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1).isEmpty()) { ; } else { QPoint centralPoint(option.rect.left() + width / 2, option.rect.top() + ItemMargin + FrameThickness + KNSCore::PreviewHeight / 2); QImage image = entry.previewImage(KNSCore::EntryInternal::PreviewSmall1); if (!image.isNull()) { QPoint previewPoint(centralPoint.x() - image.width() / 2, centralPoint.y() - image.height() / 2); painter->drawImage(previewPoint, image); QPixmap frameImageScaled = m_frameImage.scaled(image.width() + FrameThickness * 2, image.height() + FrameThickness * 2); QPoint framePoint(centralPoint.x() - frameImageScaled.width() / 2, centralPoint.y() - frameImageScaled.height() / 2); painter->drawPixmap(framePoint, frameImageScaled); } else { QPoint thumbnailPoint(option.rect.left() + ((width - KNSCore::PreviewWidth - FrameThickness * 2) / 2), option.rect.top() + ItemMargin); QRect rect(thumbnailPoint, QSize(KNSCore::PreviewWidth + FrameThickness * 2, KNSCore::PreviewHeight + FrameThickness * 2)); painter->drawText(rect, Qt::AlignCenter | Qt::TextWordWrap, i18n("Loading Preview")); } } } painter->restore(); } QSize ItemsGridViewDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option); Q_UNUSED(index); QSize size; size.setWidth(ItemGridWidth); size.setHeight(qMax(option.fontMetrics.height() * 13, ItemGridHeight)); // up to 6 lines of text, and two margins return size; } void ItemsGridViewDelegate::createOperationBar() { m_operationBar = new QWidget(this->itemView()->viewport()); m_detailsButton = new QToolButton(); m_detailsButton->setToolButtonStyle(Qt::ToolButtonFollowStyle); m_detailsButton->setPopupMode(QToolButton::InstantPopup); m_detailsButton->setToolTip(i18n("Details")); m_detailsButton->setIcon(QIcon::fromTheme(QStringLiteral("documentinfo"))); setBlockedEventTypes(m_detailsButton, QList() << QEvent::MouseButtonPress << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick); connect(m_detailsButton, &QToolButton::clicked, this, static_cast(&ItemsGridViewDelegate::slotDetailsClicked)); m_installButton = new QToolButton(); m_installButton->setToolButtonStyle(Qt::ToolButtonFollowStyle); m_installButton->setPopupMode(QToolButton::InstantPopup); setBlockedEventTypes(m_installButton, QList() << QEvent::MouseButtonPress << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick); connect(m_installButton, &QAbstractButton::clicked, this, &ItemsGridViewDelegate::slotInstallClicked); connect(m_installButton, &QToolButton::triggered, this, &ItemsGridViewDelegate::slotInstallActionTriggered); if (m_installButton->menu()) { QMenu *buttonMenu = m_installButton->menu(); buttonMenu->clear(); m_installButton->setMenu(nullptr); buttonMenu->deleteLater(); } QHBoxLayout *layout = new QHBoxLayout(m_operationBar); layout->setSpacing(1); layout->addWidget(m_installButton); layout->addWidget(m_detailsButton); m_operationBar->adjustSize(); m_operationBar->hide(); } void ItemsGridViewDelegate::displayOperationBar(const QRect &rect, const QModelIndex &index) { KNSCore::EntryInternal entry = index.data(Qt::UserRole).value(); if (m_installButton != nullptr) { if (m_installButton->menu() != nullptr) { QMenu *buttonMenu = m_installButton->menu(); buttonMenu->clear(); m_installButton->setMenu(nullptr); buttonMenu->deleteLater(); } bool installable = false; bool enabled = true; QString text; QIcon icon; switch (entry.status()) { case Entry::Installed: text = i18n("Uninstall"); icon = m_iconDelete; break; case Entry::Updateable: text = i18n("Update"); icon = m_iconUpdate; installable = true; break; case Entry::Installing: text = i18n("Installing"); enabled = false; icon = m_iconUpdate; break; case Entry::Updating: text = i18n("Updating"); enabled = false; icon = m_iconUpdate; break; case Entry::Downloadable: text = i18n("Install"); icon = m_iconInstall; installable = true; break; case Entry::Deleted: text = i18n("Install Again"); icon = m_iconInstall; installable = true; break; default: text = i18n("Install"); } m_installButton->setToolTip(text); m_installButton->setIcon(icon); m_installButton->setEnabled(enabled); if (installable && entry.downloadLinkCount() > 1) { QMenu *installMenu = new QMenu(m_installButton); foreach (const KNSCore::EntryInternal::DownloadLinkInformation &info, entry.downloadLinkInformationList()) { QString text = info.name; if (!info.distributionType.trimmed().isEmpty()) { text + " (" + info.distributionType.trimmed() + ')'; } QAction *installAction = installMenu->addAction(m_iconInstall, text); installAction->setData(QPoint(index.row(), info.id)); } m_installButton->setMenu(installMenu); } m_operationBar->move(rect.left() + (ItemGridWidth - m_operationBar->width()) / 2, rect.top() + m_elementYPos); m_operationBar->show(); } } }