KNewStuff
itemsviewdelegate.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of KNewStuff2. 00003 Copyright (C) 2008 Jeremy Whiting <jpwhiting@kde.org> 00004 Copyright (C) 2010 Reza Fatahilah Shah <rshah0385@kireihana.com> 00005 Copyright (C) 2010 Frederik Gladhorn <gladhorn@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public 00009 License as published by the Free Software Foundation; either 00010 version 2.1 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License along with this library. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 #include "itemsviewdelegate.h" 00022 00023 #include <QtGui/QPainter> 00024 #include <QtGui/QSortFilterProxyModel> 00025 #include <QtGui/QApplication> 00026 #include <QtGui/QToolButton> 00027 #include <QMenu> 00028 #include <kdebug.h> 00029 #include <kstandarddirs.h> 00030 #include <kicon.h> 00031 #include <klocale.h> 00032 #include <kmenu.h> 00033 #include <kratingwidget.h> 00034 00035 #include "itemsmodel.h" 00036 #include "entrydetailsdialog.h" 00037 00038 namespace KNS3 00039 { 00040 enum { DelegateLabel, DelegateInstallButton, DelegateDetailsButton, DelegateRatingWidget }; 00041 00042 ItemsViewDelegate::ItemsViewDelegate(QAbstractItemView *itemView, Engine* engine, QObject * parent) 00043 : ItemsViewBaseDelegate(itemView, engine, parent) 00044 { 00045 } 00046 00047 ItemsViewDelegate::~ItemsViewDelegate() 00048 { 00049 } 00050 00051 QList<QWidget*> ItemsViewDelegate::createItemWidgets() const 00052 { 00053 QList<QWidget*> list; 00054 00055 QLabel * infoLabel = new QLabel(); 00056 infoLabel->setOpenExternalLinks(true); 00057 // not so nice - work around constness to install the event filter 00058 ItemsViewDelegate* delegate = const_cast<ItemsViewDelegate*>(this); 00059 infoLabel->installEventFilter(delegate); 00060 list << infoLabel; 00061 00062 QToolButton * installButton = new QToolButton(); 00063 installButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 00064 installButton->setPopupMode(QToolButton::InstantPopup); 00065 list << installButton; 00066 setBlockedEventTypes(installButton, QList<QEvent::Type>() << QEvent::MouseButtonPress 00067 << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick); 00068 connect(installButton, SIGNAL(clicked()), this, SLOT(slotInstallClicked())); 00069 connect(installButton, SIGNAL(triggered(QAction *)), this, SLOT(slotInstallActionTriggered(QAction *))); 00070 00071 QToolButton* detailsButton = new QToolButton(); 00072 detailsButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 00073 list << detailsButton; 00074 setBlockedEventTypes(detailsButton, QList<QEvent::Type>() << QEvent::MouseButtonPress 00075 << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick); 00076 connect(detailsButton, SIGNAL(clicked()), this, SLOT(slotDetailsClicked())); 00077 00078 KRatingWidget* rating = new KRatingWidget(); 00079 rating->setMaxRating(10); 00080 rating->setHalfStepsEnabled(true); 00081 list << rating; 00082 //connect(rating, SIGNAL(ratingChanged(uint)), this, SLOT()); 00083 00084 return list; 00085 } 00086 00087 void ItemsViewDelegate::updateItemWidgets(const QList<QWidget*> widgets, 00088 const QStyleOptionViewItem &option, 00089 const QPersistentModelIndex &index) const 00090 { 00091 const ItemsModel * model = qobject_cast<const ItemsModel*>(index.model()); 00092 if (!model) { 00093 kDebug() << "WARNING - INVALID MODEL!"; 00094 return; 00095 } 00096 00097 EntryInternal entry = index.data(Qt::UserRole).value<KNS3::EntryInternal>(); 00098 00099 // setup the install button 00100 int margin = option.fontMetrics.height() / 2; 00101 int right = option.rect.width(); 00102 00103 QToolButton * installButton = qobject_cast<QToolButton*>(widgets.at(DelegateInstallButton)); 00104 if (installButton != 0) { 00105 00106 if (installButton->menu()) { 00107 QMenu* buttonMenu = installButton->menu(); 00108 buttonMenu->clear(); 00109 installButton->setMenu(0); 00110 buttonMenu->deleteLater(); 00111 } 00112 00113 bool installable = false; 00114 bool enabled = true; 00115 QString text; 00116 KIcon icon; 00117 00118 switch (entry.status()) { 00119 case Entry::Installed: 00120 text = i18n("Uninstall"); 00121 icon = m_iconDelete; 00122 break; 00123 case Entry::Updateable: 00124 text = i18n("Update"); 00125 icon = m_iconUpdate; 00126 installable = true; 00127 break; 00128 case Entry::Installing: 00129 text = i18n("Installing"); 00130 enabled = false; 00131 icon = m_iconUpdate; 00132 break; 00133 case Entry::Updating: 00134 text = i18n("Updating"); 00135 enabled = false; 00136 icon = m_iconUpdate; 00137 break; 00138 case Entry::Downloadable: 00139 text = i18n("Install"); 00140 icon = m_iconInstall; 00141 installable = true; 00142 break; 00143 case Entry::Deleted: 00144 text = i18n("Install Again"); 00145 icon = m_iconInstall; 00146 installable = true; 00147 break; 00148 default: 00149 text = i18n("Install"); 00150 } 00151 installButton->setText(text); 00152 installButton->setEnabled(enabled); 00153 installButton->setIcon(icon); 00154 if (installable && entry.downloadLinkCount() > 1) { 00155 KMenu * installMenu = new KMenu(installButton); 00156 foreach (EntryInternal::DownloadLinkInformation info, entry.downloadLinkInformationList()) { 00157 QString text = info.name; 00158 if (!info.distributionType.trimmed().isEmpty()) { 00159 text + " (" + info.distributionType.trimmed() + ")"; 00160 } 00161 QAction* installAction = installMenu->addAction(m_iconInstall, text); 00162 installAction->setData(QPoint(index.row(), info.id)); 00163 } 00164 installButton->setMenu(installMenu); 00165 } 00166 } 00167 00168 QToolButton* detailsButton = qobject_cast<QToolButton*>(widgets.at(DelegateDetailsButton)); 00169 if (detailsButton) { 00170 detailsButton->setText(i18n("Details")); 00171 detailsButton->setIcon(KIcon("documentinfo")); 00172 } 00173 00174 if (installButton && detailsButton) { 00175 if (m_buttonSize.width() < installButton->sizeHint().width()) { 00176 const_cast<QSize&>(m_buttonSize) = QSize( 00177 qMax(option.fontMetrics.height() * 7, 00178 qMax(installButton->sizeHint().width(), detailsButton->sizeHint().width())), 00179 installButton->sizeHint().height()); 00180 } 00181 installButton->resize(m_buttonSize); 00182 installButton->move(right - installButton->width() - margin, option.rect.height()/2 - installButton->height()*1.5); 00183 detailsButton->resize(m_buttonSize); 00184 detailsButton->move(right - installButton->width() - margin, option.rect.height()/2 - installButton->height()/2); 00185 } 00186 00187 QLabel * infoLabel = qobject_cast<QLabel*>(widgets.at(DelegateLabel)); 00188 infoLabel->setWordWrap(true); 00189 if (infoLabel != NULL) { 00190 if (model->hasPreviewImages()) { 00191 // move the text right by kPreviewWidth + margin pixels to fit the preview 00192 infoLabel->move(PreviewWidth + margin * 2, 0); 00193 infoLabel->resize(QSize(option.rect.width() - PreviewWidth - (margin * 6) - m_buttonSize.width(), option.fontMetrics.height() * 7)); 00194 00195 } else { 00196 infoLabel->move(margin, 0); 00197 infoLabel->resize(QSize(option.rect.width() - (margin * 4) - m_buttonSize.width(), option.fontMetrics.height() * 7)); 00198 } 00199 00200 QString text = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" 00201 "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">p, li { white-space: pre-wrap; margin:0 0 0 0;}\n" 00202 "</style></head><body><p><b>"; 00203 00204 KUrl link = qvariant_cast<KUrl>(entry.homepage()); 00205 if (!link.isEmpty()) { 00206 text += "<p><a href=\"" + link.url() + "\">" + entry.name() + "</a></p>\n"; 00207 } else { 00208 text += entry.name(); 00209 } 00210 00211 text += "</b></p>\n"; 00212 00213 QString authorName = entry.author().name(); 00214 QString email = entry.author().email(); 00215 QString authorPage = entry.author().homepage(); 00216 00217 if (!authorName.isEmpty()) { 00218 if (!authorPage.isEmpty()) { 00219 text += "<p>" + i18nc("Show the author of this item in a list", "By <i>%1</i>", " <a href=\"" + authorPage + "\">" + authorName + "</a>") + "</p>\n"; 00220 } else if (!email.isEmpty()) { 00221 text += "<p>" + i18nc("Show the author of this item in a list", "By <i>%1</i>", authorName) + " <a href=\"mailto:" + email + "\">" + email + "</a></p>\n"; 00222 } else { 00223 text += "<p>" + i18nc("Show the author of this item in a list", "By <i>%1</i>", authorName) + "</p>\n"; 00224 } 00225 } 00226 00227 QString summary = "<p>" + option.fontMetrics.elidedText(entry.summary(), 00228 Qt::ElideRight, infoLabel->width() * 3) + "</p>\n"; 00229 text += summary; 00230 00231 unsigned int fans = entry.numberFans(); 00232 unsigned int downloads = entry.downloadCount(); 00233 00234 QString fanString; 00235 QString downloadString; 00236 if (fans > 0) { 00237 fanString = i18ncp("fan as in supporter", "1 fan", "%1 fans", fans); 00238 } 00239 if (downloads > 0) { 00240 downloadString = i18np("1 download", "%1 downloads", downloads); 00241 } 00242 if (downloads > 0 || fans > 0) { 00243 text += "<p>" + downloadString; 00244 if (downloads > 0 && fans > 0) { 00245 text += ", "; 00246 } 00247 text += fanString + QLatin1String("</p>\n"); 00248 } 00249 00250 text += "</body></html>"; 00251 // use simplified to get rid of newlines etc 00252 text = replaceBBCode(text).simplified(); 00253 infoLabel->setText(text); 00254 } 00255 00256 KRatingWidget * rating = qobject_cast<KRatingWidget*>(widgets.at(DelegateRatingWidget)); 00257 if (rating) { 00258 if (entry.rating() > 0) { 00259 rating->setToolTip(i18n("Rating: %1%", entry.rating())); 00260 // 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 00261 rating->setRating((entry.rating()-20)*10/60); 00262 // put the rating label below the install button 00263 rating->move(right - installButton->width() - margin, option.rect.height()/2 + installButton->height()/2); 00264 rating->resize(m_buttonSize); 00265 } else { 00266 rating->setVisible(false); 00267 } 00268 } 00269 } 00270 00271 // draws the preview 00272 void ItemsViewDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const 00273 { 00274 int margin = option.fontMetrics.height() / 2; 00275 00276 QStyle *style = QApplication::style(); 00277 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0); 00278 00279 painter->save(); 00280 00281 if (option.state & QStyle::State_Selected) { 00282 painter->setPen(QPen(option.palette.highlightedText().color())); 00283 } else { 00284 painter->setPen(QPen(option.palette.text().color())); 00285 } 00286 00287 const ItemsModel * realmodel = qobject_cast<const ItemsModel*>(index.model()); 00288 00289 if (realmodel->hasPreviewImages()) { 00290 int height = option.rect.height(); 00291 QPoint point(option.rect.left() + margin, option.rect.top() + ((height - PreviewHeight) / 2)); 00292 00293 KNS3::EntryInternal entry = index.data(Qt::UserRole).value<KNS3::EntryInternal>(); 00294 if (entry.previewUrl(EntryInternal::PreviewSmall1).isEmpty()) { 00295 // paint the no preview icon 00296 //point.setX((PreviewWidth - m_noImage.width())/2 + 5); 00297 //point.setY(option.rect.top() + ((height - m_noImage.height()) / 2)); 00298 //painter->drawPixmap(point, m_noImage); 00299 } else { 00300 QImage image = entry.previewImage(EntryInternal::PreviewSmall1); 00301 if (!image.isNull()) { 00302 point.setX((PreviewWidth - image.width())/2 + 5); 00303 point.setY(option.rect.top() + ((height - image.height()) / 2)); 00304 painter->drawImage(point, image); 00305 00306 QPoint framePoint(point.x() - 5, point.y() - 5); 00307 painter->drawPixmap(framePoint, m_frameImage.scaled(image.width() + 10, image.height() + 10)); 00308 } else { 00309 QRect rect(point, QSize(PreviewWidth, PreviewHeight)); 00310 painter->drawText(rect, Qt::AlignCenter | Qt::TextWordWrap, i18n("Loading Preview")); 00311 } 00312 } 00313 00314 } 00315 painter->restore(); 00316 } 00317 00318 QSize ItemsViewDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const 00319 { 00320 Q_UNUSED(option); 00321 Q_UNUSED(index); 00322 00323 QSize size; 00324 00325 size.setWidth(option.fontMetrics.height() * 4); 00326 size.setHeight(qMax(option.fontMetrics.height() * 7, PreviewHeight)); // up to 6 lines of text, and two margins 00327 return size; 00328 } 00329 00330 } // namespace 00331 00332 #include "itemsviewdelegate.moc"
KDE 4.6 API Reference