KNewStuff
itemsview.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of KNewStuff2. 00003 Copyright (C) 2005 by Enrico Ros <eros.kde@email.it> 00004 Copyright (C) 2005 - 2007 Josef Spillner <spillner@kde.org> 00005 Copyright (C) 2007 Dirk Mueller <mueller@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 // own include 00022 #include "itemsview.h" 00023 00024 // qt/kde includes 00025 #include <QtCore/QFile> 00026 #include <QtGui/QWidget> 00027 #include <QtCore/QTimer> 00028 #include <QtGui/QLayout> 00029 #include <QtGui/QImage> 00030 #include <QtGui/QFont> 00031 #include <QtGui/QComboBox> 00032 #include <QtGui/QPushButton> 00033 #include <QtCore/QMutableVectorIterator> 00034 #include <QtCore/QRect> 00035 #include <QtGui/QPainter> 00036 #include <QtGui/QScrollArea> 00037 #include <QtGui/QApplication> 00038 #include <QtGui/QTextDocument> 00039 #include <kaboutdata.h> 00040 #include <kapplication.h> 00041 #include <kcomponentdata.h> 00042 #include <kglobalsettings.h> 00043 #include <klocale.h> 00044 #include <klineedit.h> 00045 #include <kconfig.h> 00046 #include <kstandarddirs.h> 00047 #include <kmessagebox.h> 00048 #include <kdebug.h> 00049 #include <kiconloader.h> 00050 #include <kio/job.h> 00051 #include <kio/netaccess.h> 00052 #include <ktitlewidget.h> 00053 #include <ktoolinvocation.h> 00054 00055 #include "knewstuff2/core/provider.h" 00056 #include "knewstuff2/core/providerhandler.h" 00057 #include "knewstuff2/core/entry.h" 00058 #include "knewstuff2/core/entryhandler.h" 00059 #include "knewstuff2/core/category.h" 00060 00061 #include "knewstuff2/dxs/dxs.h" 00062 00063 #include "knewstuff2/ui/qprogressindicator.h" 00064 00065 // local includes 00066 #include "ui_DownloadDialog.h" 00067 #include "kdxsbutton.h" 00068 #include "qasyncimage_p.h" 00069 00070 using namespace KNS; 00071 00072 static bool NameSorter(const Entry* e1, const Entry* e2) 00073 { 00074 return e1->name().representation() < e2->name().representation(); 00075 } 00076 00077 static bool RatingSorter(const Entry* e1, const Entry* e2) 00078 { 00079 return e1->rating() < e2->rating(); 00080 } 00081 00082 static bool RecentSorter(const Entry* e1, const Entry* e2) 00083 { 00084 // return > instead of < to sort in reverse order 00085 return e1->releaseDate() > e2->releaseDate(); 00086 } 00087 00088 static bool DownloadsSorter(const Entry* e1, const Entry* e2) 00089 { 00090 // return > instead of < to sort most downloads at the top 00091 return e1->downloads() > e2->downloads(); 00092 } 00093 00094 ItemsView::ItemsView(QWidget* _parent) 00095 : QListView(_parent), 00096 m_currentProvider(0), m_currentFeed(0), m_root(0), m_sorting(0), m_engine(0) 00097 { 00098 m_root = new QWidget(this); 00099 setFrameStyle(QFrame::Plain | QFrame::StyledPanel); 00100 setVerticalScrollMode(ScrollPerPixel); 00101 //setWidgetResizable(true); 00102 } 00103 00104 ItemsView::~ItemsView() 00105 { 00106 } 00107 00108 void ItemsView::setEngine(DxsEngine *engine) 00109 { 00110 m_engine = engine; 00111 } 00112 00113 void ItemsView::setProvider(const Provider * provider, const Feed * feed) 00114 { 00115 m_currentProvider = provider; 00116 m_currentFeed = feed; 00117 buildContents(); 00118 } 00119 00120 void ItemsView::setSorting(int sortType) 00121 { 00122 m_sorting = sortType; 00123 buildContents(); 00124 } 00125 00126 void ItemsView::setFeed(const Feed * feed) 00127 { 00128 m_currentFeed = feed; 00129 buildContents(); 00130 } 00131 00132 void ItemsView::setSearchText(const QString & text) 00133 { 00134 m_searchText = text; 00135 buildContents(); 00136 } 00137 00138 void ItemsView::updateItem(Entry *entry) 00139 { 00140 // FIXME: change this to call updateEntry once it is complete 00141 // if (m_views.contains(entry)) { 00142 // m_views[entry]->setEntry(entry); 00143 // } 00144 } 00145 00146 void ItemsView::buildContents() 00147 { 00148 m_views.clear(); 00149 00150 m_root->setBackgroundRole(QPalette::Base); 00151 QVBoxLayout* _layout = new QVBoxLayout(m_root); 00152 00153 if (m_currentFeed != NULL) { 00154 Entry::List entries = m_currentFeed->entries(); 00155 //switch (m_sorting) 00156 //{ 00157 // case 0: 00158 // qSort(entries.begin(), entries.end(), NameSorter); 00159 // break; 00160 // case 1: 00161 // qSort(entries.begin(), entries.end(), RatingSorter); 00162 // break; 00163 // case 2: 00164 // qSort(entries.begin(), entries.end(), RecentSorter); 00165 // break; 00166 // case 3: 00167 // qSort(entries.begin(), entries.end(), DownloadsSorter); 00168 // break; 00169 //} 00170 00171 Entry::List::iterator it = entries.begin(), iEnd = entries.end(); 00172 for (unsigned row = 0; it != iEnd; ++it) { 00173 Entry* entry = (*it); 00174 00175 if (entry->name().representation().toLower().contains(m_searchText.toLower())) { 00176 QHBoxLayout * itemLayout = new QHBoxLayout; 00177 _layout->addLayout(itemLayout); 00178 00179 EntryView *part = new EntryView(m_root); 00180 part->setBackgroundRole(row & 1 ? QPalette::AlternateBase : QPalette::Base); 00181 itemLayout->addWidget(part); 00182 00183 QVBoxLayout * previewLayout = new QVBoxLayout; 00184 itemLayout->insertLayout(0, previewLayout); 00185 00186 KDXSButton *dxsbutton = new KDXSButton(m_root); 00187 dxsbutton->setEntry(entry); 00188 dxsbutton->setProvider(m_currentProvider); 00189 dxsbutton->setEngine(m_engine); 00190 00191 QString imageurl = entry->preview().representation(); 00192 if (!imageurl.isEmpty()) { 00193 QLabel *f = new QLabel(m_root); 00194 f->setFrameStyle(QFrame::Panel | QFrame::Sunken); 00195 QAsyncImage *pix = new QAsyncImage(imageurl, m_root); 00196 f->setFixedSize(64, 64); 00197 //connect(pix, SIGNAL(signalLoaded(const QImage&)), 00198 // f, SLOT(setImage(const QImage&))); 00199 previewLayout->addWidget(f); 00200 } 00201 //previewLayout->addWidget(dxsbutton); 00202 00203 part->setEntry(entry); 00204 m_views.insert(entry, part); 00205 ++row; 00206 } 00207 } 00208 } 00209 00210 //setWidget(m_root); 00211 } 00212 00213 EntryView::EntryView(QWidget * _parent) 00214 : QLabel(_parent) 00215 { 00216 connect(this, SIGNAL(linkActivated(const QString&)), SLOT(urlSelected(const QString&))); 00217 } 00218 00219 void EntryView::setEntry(Entry *entry) 00220 { 00221 m_entry = entry; 00222 buildContents(); 00223 } 00224 00225 void EntryView::updateEntry(Entry *entry) 00226 { 00227 // get item id string and iformations 00228 QString idString = QString::number((unsigned long)entry); 00229 // AvailableItem::State state = item->state(); 00230 // bool showProgress = state != AvailableItem::Normal; 00231 // int pixelProgress = showProgress ? (int)(item->progress() * 80.0) : 0; 00232 00233 // perform internal scripting operations over the element 00234 // executeScript( "document.getElementById('" + idString + "').style.color='red'" ); 00235 // executeScript( "document.getElementById('bar" + idString + "').style.width='" + 00236 // QString::number( pixelProgress ) + "px'" ); 00237 // executeScript( "document.getElementById('bc" + idString + "').style.backgroundColor='" + 00238 // (showProgress ? "gray" : "transparent") + "'" ); 00239 // executeScript( "document.getElementById('btn" + idString + "').value='" + 00240 // (item->installed() ? i18n( "Uninstall" ) : i18n( "Install" )) + "'" ); 00241 } 00242 00243 void EntryView::buildContents() 00244 { 00245 // write the html header and contents manipulation scripts 00246 QString t; 00247 00248 t += "<html><body>"; 00249 00250 //t += setTheAaronnesqueStyle(); 00251 // precalc the status icon 00252 Entry::Status status = m_entry->status(); 00253 QString statusIcon; 00254 KIconLoader *loader = KIconLoader::global(); 00255 00256 switch (status) { 00257 case Entry::Invalid: 00258 statusIcon = "<img src='" + loader->iconPath("dialog-error", -KIconLoader::SizeSmall) + "' />"; 00259 break; 00260 case Entry::Downloadable: 00261 // find a good icon to represent downloadable data 00262 //statusIcon = "<img src='" + loader->iconPath("network-server", -KIconLoader::SizeSmall) + "' />"; 00263 break; 00264 case Entry::Installed: 00265 statusIcon = "<img src='" + loader->iconPath("dialog-ok", -KIconLoader::SizeSmall) + "' />"; 00266 break; 00267 case Entry::Updateable: 00268 statusIcon = "<img src='" + loader->iconPath("software-update-available", -KIconLoader::SizeSmall) + "' />"; 00269 break; 00270 case Entry::Deleted: 00271 statusIcon = "<img src='" + loader->iconPath("user-trash", -KIconLoader::SizeSmall) + "' />"; 00272 break; 00273 } 00274 00275 // precalc the title string 00276 QString titleString = m_entry->name().representation(); 00277 if (!m_entry->version().isEmpty()) titleString += " v." + Qt::escape(m_entry->version()); 00278 00279 // precalc the string for displaying stars (normal+grayed) 00280 QString starIconPath = KStandardDirs::locate("data", "knewstuff/pics/ghns_star.png"); 00281 QString starBgIconPath = KStandardDirs::locate("data", "knewstuff/pics/ghns_star_gray.png"); 00282 00283 int starPixels = 11 + 11 * (m_entry->rating() / 10); 00284 QString starsString = "<div style='width: " + QString::number(starPixels) + "px; background-image: url(" + starIconPath + "); background-repeat: repeat-x;'> </div>"; 00285 int grayPixels = 22 + 22 * (m_entry->rating() / 20); 00286 starsString = "<div style='width: " + QString::number(grayPixels) + "px;background-image: url(" + starBgIconPath + "); background-repeat: repeat-x;'>" + starsString + " </div>"; 00287 00288 // precalc the string for displaying author (parsing email) 00289 KNS::Author author = m_entry->author(); 00290 QString authorString = author.name(); 00291 00292 QString emailString = author.email(); 00293 if (!emailString.isEmpty()) { 00294 authorString = "<a href='mailto:" + Qt::escape(emailString) + "'>" 00295 + Qt::escape(authorString) + "</a>"; 00296 } 00297 00298 // write the HTML code for the current item 00299 t += //QLatin1String("<table class='contentsHeader' cellspacing='2' cellpadding='0'>") 00300 statusIcon + Qt::escape(titleString) + "<br />" 00301 //+ "<span align='right'>" + starsString + "</span><br />" 00302 + Qt::escape(m_entry->summary().representation()) 00303 + "<br />"; 00304 00305 if (m_entry->rating() > 0) { 00306 t += i18n("Rating: ") + QString::number(m_entry->rating()) 00307 + "<br />"; 00308 } 00309 00310 if (m_entry->downloads() > 0) { 00311 t += i18n("Downloads: ") + QString::number(m_entry->downloads()) 00312 + "<br />"; 00313 } 00314 00315 if (!authorString.isEmpty()) { 00316 t += "<em>" + authorString + "</em>, "; 00317 } 00318 t += KGlobal::locale()->formatDate(m_entry->releaseDate(), KLocale::ShortDate) 00319 + "<br />" + "</body></html>"; 00320 00321 setText(t); 00322 } 00323 00324 void EntryView::setTheAaronnesqueStyle() 00325 { 00326 QString hoverColor = "#000000"; //QApplication::palette().active().highlightedText().name(); 00327 QString hoverBackground = "#f8f8f8"; //QApplication::palette().active().highlight().name(); 00328 QString starIconPath = KStandardDirs::locate("data", "knewstuff/pics/ghns_star.png"); 00329 QString starBgIconPath = KStandardDirs::locate("data", "knewstuff/pics/ghns_star_gray.png"); 00330 00331 // default elements style 00332 QString s; 00333 s += "body { background-color: white; color: black; padding: 0; margin: 0; }"; 00334 s += "table, td, th { padding: 0; margin: 0; text-align: left; }"; 00335 s += "input { color: #000080; font-size:120%; }"; 00336 00337 // the main item container (custom element) 00338 s += ".itemBox { background-color: white; color: black; width: 100%; border-bottom: 1px solid gray; margin: 0px 0px; }"; 00339 s += ".itemBox:hover { background-color: " + hoverBackground + "; color: " + hoverColor + "; }"; 00340 00341 // s of the item elements (4 cells with multiple containers) 00342 s += ".leftColumn { width: 100px; height:100%; text-align: center; }"; 00343 s += ".leftImage {}"; 00344 s += ".leftButton {}"; 00345 s += ".leftProgressContainer { width: 82px; height: 10px; background-color: transparent; }"; 00346 s += ".leftProgressBar { left: 1px; width: 0px; top: 1px; height: 8px; background-color: red; }"; 00347 s += ".contentsColumn { vertical-align: top; }"; 00348 s += ".contentsHeader { width: 100%; font-size: 120%; font-weight: bold; border-bottom: 1px solid #c8c8c8; }"; 00349 s += ".contentsBody {}"; 00350 s += ".contentsFooter {}"; 00351 s += ".star { width: 0px; height: 24px; background-image: url(" + starIconPath + "); background-repeat: repeat-x; }"; 00352 s += ".starbg { width: 110px; height: 24px; background-image: url(" + starBgIconPath + "); background-repeat: repeat-x; }"; 00353 setStyleSheet(s); 00354 } 00355 00356 void EntryView::urlSelected(const QString &link) 00357 { 00358 //kDebug() << "Clicked on URL " << link; 00359 00360 KUrl url(link); 00361 QString urlProtocol = url.protocol(); 00362 QString urlPath = url.path(); 00363 00364 if (urlProtocol == "mailto") { 00365 // clicked over a mail address 00366 // FIXME: if clicked with MRB, show context menu with IM etc. 00367 // FIXME: but RMB never reaches this method?! 00368 KToolInvocation::invokeMailer(url); 00369 } else if (urlProtocol == "item") { 00370 // clicked over an item 00371 bool ok; 00372 unsigned long itemPointer = urlPath.toULong(&ok); 00373 if (!ok) { 00374 kWarning() << "ItemsView: error converting item pointer."; 00375 return; 00376 } 00377 00378 // I love to cast pointers 00379 Entry *entry = (Entry*)itemPointer; 00380 if (entry != m_entry) { 00381 kWarning() << "ItemsView: error retrieving item pointer."; 00382 return; 00383 } 00384 00385 // XXX ??? 00386 // install/uninstall the item 00387 // if ( item->installed() ) 00388 // m_newStuffDialog->removeItem( item ); // synchronous 00389 // else 00390 // m_newStuffDialog->installItem( item ); // asynchronous 00391 } 00392 } 00393 00394 #include "itemsview.moc" 00395
KDE 4.6 API Reference