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 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 #include "itemsviewdelegate.h" 00020 #include "itemsmodel.h" 00021 00022 #include <QtGui/QPainter> 00023 #include <QtGui/QSortFilterProxyModel> 00024 00025 #include <kdebug.h> 00026 #include <kstandarddirs.h> 00027 #include <kicon.h> 00028 #include <klocale.h> 00029 #include <kmenu.h> 00030 #include <krun.h> 00031 00032 static const int kLabel = 0; 00033 static const int kInstall = 1; 00034 static const int kRating = 2; 00035 00036 namespace KNS 00037 { 00038 ItemsViewDelegate::ItemsViewDelegate(QAbstractItemView *itemView, QObject * parent) 00039 : KWidgetItemDelegate(itemView, parent) 00040 { 00041 QString framefile = KStandardDirs::locate("data", "knewstuff/pics/thumb_frame.png"); 00042 00043 m_frameImage = QPixmap(framefile).toImage(); 00044 00045 // Invalid 00046 m_statusicons << KIcon("dialog-error"); 00047 // Downloadable 00048 m_statusicons << KIcon(); 00049 //Installed 00050 m_statusicons << KIcon("dialog-ok"); 00051 //Updateable 00052 m_statusicons << KIcon("system-software-update"); 00053 //Deleted 00054 m_statusicons << KIcon("edit-delete"); 00055 } 00056 00057 ItemsViewDelegate::~ItemsViewDelegate() 00058 { 00059 } 00060 00061 KMenu * ItemsViewDelegate::InstallMenu(const QToolButton* button, Entry::Status status) const 00062 { 00063 Q_UNUSED(button) 00064 KMenu * installMenu = new KMenu(NULL); 00065 QAction * action_install = installMenu->addAction(m_statusicons[Entry::Installed], i18n("Install")); 00066 QAction * action_uninstall = installMenu->addAction(m_statusicons[Entry::Deleted], i18n("Uninstall")); 00067 action_install->setData(DownloadDialog::kInstall); 00068 action_uninstall->setData(DownloadDialog::kUninstall); 00069 00070 action_install->setVisible(status != Entry::Installed); 00071 action_uninstall->setVisible(status == Entry::Installed); 00072 return installMenu; 00073 } 00074 00075 QList<QWidget*> ItemsViewDelegate::createItemWidgets() const 00076 { 00077 QList<QWidget*> list; 00078 00079 QLabel * infoLabel = new QLabel(); 00080 infoLabel->setOpenExternalLinks(true); 00081 list << infoLabel; 00082 00083 QToolButton * installButton = new QToolButton(); 00084 list << installButton; 00085 setBlockedEventTypes(installButton, QList<QEvent::Type>() << QEvent::MouseButtonPress 00086 << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick); 00087 connect(installButton, SIGNAL(triggered(QAction *)), this, SLOT(slotActionTriggered(QAction *))); 00088 connect(installButton, SIGNAL(clicked()), this, SLOT(slotInstallClicked())); 00089 00090 QLabel * ratingLabel = new QLabel(); 00091 list << ratingLabel; 00092 00093 return list; 00094 } 00095 00096 void ItemsViewDelegate::updateItemWidgets(const QList<QWidget*> widgets, 00097 const QStyleOptionViewItem &option, 00098 const QPersistentModelIndex &index) const 00099 { 00100 const QSortFilterProxyModel * model = qobject_cast<const QSortFilterProxyModel*>(index.model()); 00101 if (model == NULL) { 00102 return; 00103 } 00104 00105 const ItemsModel * realmodel = qobject_cast<const ItemsModel*>(model->sourceModel()); 00106 if (realmodel == NULL || !index.isValid()) { 00107 return; 00108 } 00109 00110 // setup the install button 00111 int margin = option.fontMetrics.height() / 2; 00112 00113 int right = option.rect.width(); 00114 //int bottom = option.rect.height(); 00115 00116 QSize size(option.fontMetrics.height() * 7, widgets.at(kInstall)->sizeHint().height()); 00117 00118 QLabel * infoLabel = qobject_cast<QLabel*>(widgets.at(kLabel)); 00119 infoLabel->setWordWrap(true); 00120 if (infoLabel != NULL) { 00121 if (realmodel->hasPreviewImages()) { 00122 // move the text right by kPreviewWidth + margin pixels to fit the preview 00123 infoLabel->move(kPreviewWidth + margin * 2, 0); 00124 infoLabel->resize(QSize(option.rect.width() - kPreviewWidth - (margin * 6) - size.width(), option.fontMetrics.height() * 7)); 00125 } else { 00126 infoLabel->move(margin, 0); 00127 infoLabel->resize(QSize(option.rect.width() - (margin * 4) - size.width(), option.fontMetrics.height() * 7)); 00128 } 00129 00130 QString text = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" 00131 "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">p, li { white-space: pre-wrap; margin:0 0 0 0;}\n" 00132 "</style></head><body><p><b>" + 00133 index.data(ItemsModel::kNameRole).toString() + "</b></p>\n"; 00134 00135 QString summary = "<p>" + option.fontMetrics.elidedText(index.data(ItemsModel::kSummary).toString(), 00136 Qt::ElideRight, infoLabel->width() * 3) + "</p>\n"; 00137 text += summary; 00138 00139 QString authorName = index.data(ItemsModel::kAuthorName).toString(); 00140 QString email = index.data(ItemsModel::kAuthorEmail).toString(); 00141 if (!authorName.isEmpty()) { 00142 if (email.isEmpty()) { 00143 text += "<p><i>" + authorName + "</i></p>\n"; 00144 } else { 00145 text += "<p><i>" + authorName + "</i> <a href=\"mailto:" + email + "\">" + email + "</a></p>\n"; 00146 } 00147 } 00148 00149 unsigned int downloads = index.data(ItemsModel::kDownloads).toUInt(); 00150 text += downloads == 0 ? i18n("<p>No Downloads</p>") : i18n("<p>Downloads: %1</p>\n", downloads); 00151 00152 text += "</body></html>"; 00153 text.replace("[b]", "<b>"); 00154 text.replace("[/b]", "</b>"); 00155 text.replace("[i]", "<i>"); 00156 text.replace("[/i]", "</i>"); 00157 text.replace("[u]", "<i>"); 00158 text.replace("[/u]", "</i>"); 00159 text.remove("[url]"); 00160 text.remove("[/url]"); 00161 text.replace("\\\'", "\'"); 00162 infoLabel->setText(text.simplified()); 00163 } 00164 00165 QToolButton * button = qobject_cast<QToolButton*>(widgets.at(kInstall)); 00166 if (button != NULL) { 00167 Entry::Status status = Entry::Status(model->data(index, ItemsModel::kStatus).toUInt()); 00168 //if (!button->menu()) { 00169 // button->setMenu(InstallMenu(button, status)); 00170 // button->setIconSize(QSize(16, 16)); 00171 button->resize(size); 00172 //} 00173 button->move(right - button->width() - margin, option.rect.height() / 2 - button->height()); 00174 button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 00175 //button->setPopupMode(QToolButton::MenuButtonPopup); 00176 00177 // validate our assumptions 00178 //Q_ASSERT(button->menu()); 00179 //Q_ASSERT(button->menu()->actions().count() == 2); 00180 00181 // get the two actions 00182 //QAction * action_install = button->menu()->actions()[0]; 00183 //QAction * action_uninstall = button->menu()->actions()[1]; 00184 switch (status) { 00185 case Entry::Installed: 00186 button->setText(i18n("Uninstall")); 00187 //action_install->setVisible(false); 00188 //action_uninstall->setVisible(true); 00189 button->setIcon(QIcon(m_statusicons[Entry::Deleted])); 00190 break; 00191 case Entry::Updateable: 00192 button->setText(i18n("Update")); 00193 //action_uninstall->setVisible(false); 00194 //action_install->setText(i18n("Update")); 00195 //action_install->setVisible(true); 00196 //action_install->setIcon(QIcon(m_statusicons[Entry::Updateable])); 00197 button->setIcon(QIcon(m_statusicons[Entry::Updateable])); 00198 break; 00199 case Entry::Deleted: 00201 button->setText(i18n("Install")); 00202 //action_uninstall->setVisible(false); 00203 //action_install->setText(i18n("Install")); 00204 //action_install->setVisible(true); 00205 //action_install->setIcon(QIcon(m_statusicons[Entry::Installed])); 00206 button->setIcon(QIcon(m_statusicons[Entry::Installed])); 00207 break; 00208 default: 00209 button->setText(i18n("Install")); 00210 //action_uninstall->setVisible(false); 00211 //action_install->setVisible(true); 00212 //action_install->setIcon(QIcon(m_statusicons[Entry::Installed])); 00213 button->setIcon(QIcon(m_statusicons[Entry::Installed])); 00214 } 00215 } 00216 00217 QLabel * ratingLabel = qobject_cast<QLabel*>(widgets.at(kRating)); 00218 if (ratingLabel != NULL) { 00219 ratingLabel->setText(i18n("Rating: %1", model->data(index, ItemsModel::kRating).toString())); 00220 00221 // put the rating label below the install button 00222 ratingLabel->move(right - button->width() - margin, option.rect.height() / 2 + button->height()/2); 00223 ratingLabel->resize(size); 00224 } 00225 } 00226 00227 // draw the entry based on what 00228 // paint the item at index with all it's attributes shown 00229 void ItemsViewDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const 00230 { 00231 int margin = option.fontMetrics.height() / 2; 00232 00233 QStyle *style = QApplication::style(); 00234 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0); 00235 00236 painter->save(); 00237 00238 if (option.state & QStyle::State_Selected) { 00239 painter->setPen(QPen(option.palette.highlightedText().color())); 00240 } else { 00241 painter->setPen(QPen(option.palette.text().color())); 00242 } 00243 00244 const QSortFilterProxyModel * model = qobject_cast<const QSortFilterProxyModel*>(index.model()); 00245 const ItemsModel * realmodel = qobject_cast<const ItemsModel*>(model->sourceModel()); 00246 00247 if (realmodel->hasPreviewImages()) { 00248 00249 int height = option.rect.height(); 00250 QPoint point(option.rect.left() + margin, option.rect.top() + ((height - kPreviewHeight) / 2)); 00251 00252 if (index.data(ItemsModel::kPreview).toString().isEmpty()) { 00253 QRect rect(point, QSize(kPreviewWidth, kPreviewHeight)); 00254 painter->drawText(rect, Qt::AlignCenter | Qt::TextWordWrap, i18n("No Preview")); 00255 } else { 00256 QImage image = index.data(ItemsModel::kPreviewPixmap).value<QImage>(); 00257 if (!image.isNull()) { 00258 point.setY(option.rect.top() + ((height - image.height()) / 2)); 00259 painter->drawImage(point, image); 00260 QPoint framePoint(point.x() - 5, point.y() - 5); 00261 painter->drawImage(framePoint, m_frameImage.scaled(image.width() + 10, image.height() + 10)); 00262 } else { 00263 QRect rect(point, QSize(kPreviewWidth, kPreviewHeight)); 00264 painter->drawText(rect, Qt::AlignCenter | Qt::TextWordWrap, i18n("Loading Preview")); 00265 } 00266 } 00267 } 00268 00269 painter->restore(); 00270 } 00271 00272 //bool ItemsViewDelegate::eventFilter(QObject *watched, QEvent *event) 00273 //{ 00274 // if (event->type() == QEvent::ToolTip) { 00275 // 00276 // } 00277 00278 // return KWidgetItemDelegate::eventFilter(watched, event); 00279 //} 00280 00281 QSize ItemsViewDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const 00282 { 00283 Q_UNUSED(option); 00284 Q_UNUSED(index); 00285 00286 QSize size; 00287 00288 size.setWidth(option.fontMetrics.height() * 4); 00289 size.setHeight(qMax(option.fontMetrics.height() * 7, kPreviewHeight)); // up to 6 lines of text, and two margins 00290 00291 return size; 00292 } 00293 00294 void ItemsViewDelegate::slotLinkClicked(const QString & url) 00295 { 00296 Q_UNUSED(url) 00297 QModelIndex index = focusedIndex(); 00298 Q_ASSERT(index.isValid()); 00299 00300 const QSortFilterProxyModel * model = qobject_cast<const QSortFilterProxyModel*>(index.model()); 00301 const ItemsModel * realmodel = qobject_cast<const ItemsModel*>(model->sourceModel()); 00302 KNS::Entry * entry = realmodel->entryForIndex(model->mapToSource(index)); 00303 emit performAction(DownloadDialog::kContactEmail, entry); 00304 } 00305 00306 void ItemsViewDelegate::slotActionTriggered(QAction *action) 00307 { 00308 QModelIndex index = focusedIndex(); 00309 Q_ASSERT(index.isValid()); 00310 00311 const QSortFilterProxyModel * model = qobject_cast<const QSortFilterProxyModel*>(index.model()); 00312 const ItemsModel * realmodel = qobject_cast<const ItemsModel*>(model->sourceModel()); 00313 KNS::Entry * entry = realmodel->entryForIndex(model->mapToSource(index)); 00314 emit performAction(DownloadDialog::EntryAction(action->data().toInt()), entry); 00315 } 00316 00317 void ItemsViewDelegate::slotInstallClicked() 00318 { 00319 QModelIndex index = focusedIndex(); 00320 00321 if (index.isValid()) { 00322 const QSortFilterProxyModel * model = qobject_cast<const QSortFilterProxyModel*>(index.model()); 00323 const ItemsModel * realmodel = qobject_cast<const ItemsModel*>(model->sourceModel()); 00324 KNS::Entry * entry = realmodel->entryForIndex(model->mapToSource(index)); 00325 if ( !entry ) 00326 return; 00327 00328 if (entry->status() == Entry::Installed) { 00329 emit performAction(DownloadDialog::kUninstall, entry); 00330 } else { 00331 emit performAction(DownloadDialog::kInstall, entry); 00332 } 00333 } 00334 } 00335 }
KDE 4.6 API Reference