/*
* Bittorrent Client using Qt4 and libtorrent .
* Copyright ( C ) 2006 Christophe Dumez , Arnaud Demaiziere
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program 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 General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
* Contact : chris @ qbittorrent . org arnaud @ qbittorrent . org
*/
# include "rss_imp.h"
# include "rss.h"
# include <QDesktopServices>
# include <QInputDialog>
# include <QMenu>
# include <QStandardItemModel>
# include <QMessageBox>
# include <QTimer>
// display a right-click menu
void RSSImp : : displayRSSListMenu ( const QPoint & pos ) {
QMenu myFinishedListMenu ( this ) ;
QTreeWidgetItem * item = listStreams - > itemAt ( pos ) ;
QList < QTreeWidgetItem * > selectedItems = listStreams - > selectedItems ( ) ;
if ( item ! = 0 ) {
myFinishedListMenu . addAction ( actionDelete ) ;
if ( selectedItems . size ( ) = = 1 )
myFinishedListMenu . addAction ( actionRename ) ;
myFinishedListMenu . addAction ( actionRefresh ) ;
} else {
myFinishedListMenu . addAction ( actionCreate ) ;
myFinishedListMenu . addAction ( actionRefreshAll ) ;
}
myFinishedListMenu . exec ( mapToGlobal ( pos ) + QPoint ( 10 , 33 ) ) ;
}
// add a stream by a button
void RSSImp : : on_addStream_button_clicked ( ) {
createStream ( ) ;
}
// delete a stream by a button
void RSSImp : : on_delStream_button_clicked ( ) {
QList < QTreeWidgetItem * > selectedItems = listStreams - > selectedItems ( ) ;
QTreeWidgetItem * item ;
if ( ! selectedItems . size ( ) ) return ;
int ret = QMessageBox : : question ( this , tr ( " Are you sure? -- qBittorrent " ) , tr ( " Are you sure you want to delete this stream from the list? " ) ,
tr ( " &Yes " ) , tr ( " &No " ) ,
QString ( ) , 0 , 1 ) ;
if ( ! ret ) {
QStringList urlsToDelete ;
foreach ( item , selectedItems ) {
QString url = item - > data ( 1 , Qt : : DisplayRole ) . toString ( ) ;
urlsToDelete < < url ;
}
QString url ;
foreach ( url , urlsToDelete ) {
if ( selectedFeedUrl = = url ) {
textBrowser - > clear ( ) ;
listNews - > clear ( ) ;
}
rssmanager - > removeStream ( url ) ;
delete getTreeItemFromUrl ( url ) ;
}
if ( urlsToDelete . size ( ) )
rssmanager - > saveStreamList ( ) ;
}
}
// refresh all streams by a button
void RSSImp : : on_refreshAll_button_clicked ( ) {
refreshAllStreams ( ) ;
}
// open the url of the news in a browser
void RSSImp : : openInBrowser ( QListWidgetItem * item ) {
RssItem * news = rssmanager - > getFeed ( selectedFeedUrl ) - > getItem ( listNews - > row ( item ) ) ;
QString link = news - > getLink ( ) ;
if ( ! link . isEmpty ( ) )
QDesktopServices : : openUrl ( QUrl ( link ) ) ;
}
//right-click on stream : give him an alias
void RSSImp : : renameStream ( ) {
QList < QTreeWidgetItem * > selectedItems = listStreams - > selectedItems ( ) ;
Q_ASSERT ( selectedItems . size ( ) = = 1 ) ;
QTreeWidgetItem * item = selectedItems . at ( 0 ) ;
QString url = item - > data ( 1 , Qt : : DisplayRole ) . toString ( ) ;
bool ok ;
QString newAlias = QInputDialog : : getText ( this , tr ( " Please choose a new name for this stream " ) , tr ( " New stream name: " ) , QLineEdit : : Normal , rssmanager - > getFeed ( url ) - > getAlias ( ) , & ok ) ;
if ( ok ) {
rssmanager - > setAlias ( url , newAlias ) ;
}
}
//right-click on stream : refresh it
void RSSImp : : refreshSelectedStreams ( ) {
QList < QTreeWidgetItem * > selectedItems = listStreams - > selectedItems ( ) ;
QTreeWidgetItem * item ;
foreach ( item , selectedItems ) {
QString url = item - > text ( 1 ) ;
textBrowser - > clear ( ) ;
listNews - > clear ( ) ;
rssmanager - > refresh ( url ) ;
item - > setData ( 0 , Qt : : DecorationRole , QVariant ( QIcon ( " :/Icons/loading.png " ) ) ) ;
}
}
//right-click somewhere, refresh all the streams
void RSSImp : : refreshAllStreams ( ) {
textBrowser - > clear ( ) ;
listNews - > clear ( ) ;
unsigned int nbFeeds = listStreams - > topLevelItemCount ( ) ;
for ( unsigned int i = 0 ; i < nbFeeds ; + + i )
listStreams - > topLevelItem ( i ) - > setData ( 0 , Qt : : DecorationRole , QVariant ( QIcon ( " :/Icons/loading.png " ) ) ) ;
rssmanager - > refreshAll ( ) ;
updateLastRefreshedTimeForStreams ( ) ;
}
void RSSImp : : fillFeedsList ( ) {
QList < RssStream * > feeds = rssmanager - > getRssFeeds ( ) ;
RssStream * stream ;
foreach ( stream , feeds ) {
QTreeWidgetItem * item = new QTreeWidgetItem ( listStreams ) ;
item - > setData ( 0 , Qt : : DisplayRole , stream - > getAliasOrUrl ( ) + QString ( " (0) " ) ) ;
item - > setData ( 0 , Qt : : DecorationRole , QVariant ( QIcon ( " :/Icons/loading.png " ) ) ) ;
item - > setData ( 1 , Qt : : DisplayRole , stream - > getUrl ( ) ) ;
item - > setToolTip ( 0 , QString ( " <b> " ) + tr ( " Description: " ) + QString ( " </b> " ) + stream - > getDescription ( ) + QString ( " <br/><b> " ) + tr ( " url: " ) + QString ( " </b> " ) + stream - > getUrl ( ) + QString ( " <br/><b> " ) + tr ( " Last refresh: " ) + QString ( " </b> " ) + stream - > getLastRefreshElapsedString ( ) ) ;
}
}
//right-click, register a new stream
void RSSImp : : createStream ( ) {
bool ok ;
QString newUrl = QInputDialog : : getText ( this , tr ( " Please type a rss stream url " ) , tr ( " Stream URL: " ) , QLineEdit : : Normal , " http:// " , & ok ) ;
if ( ok ) {
newUrl = newUrl . trimmed ( ) ;
if ( ! newUrl . isEmpty ( ) ) {
RssStream * stream = rssmanager - > addStream ( newUrl ) ;
if ( stream = = 0 ) {
// Already existing
QMessageBox : : warning ( this , tr ( " qBittorrent " ) ,
tr ( " This rss feed is already in the list. " ) ,
QMessageBox : : Ok ) ;
return ;
}
QTreeWidgetItem * item = new QTreeWidgetItem ( listStreams ) ;
item - > setText ( 0 , stream - > getAliasOrUrl ( ) + QString ( " (0) " ) ) ;
item - > setText ( 1 , stream - > getUrl ( ) ) ;
item - > setData ( 0 , Qt : : DecorationRole , QVariant ( QIcon ( " :/Icons/loading.png " ) ) ) ;
item - > setToolTip ( 0 , QString ( " <b> " ) + tr ( " Description: " ) + QString ( " </b> " ) + stream - > getDescription ( ) + QString ( " <br/><b> " ) + tr ( " url: " ) + QString ( " </b> " ) + stream - > getUrl ( ) + QString ( " <br/><b> " ) + tr ( " Last refresh: " ) + QString ( " </b> " ) + stream - > getLastRefreshElapsedString ( ) ) ;
if ( listStreams - > topLevelItemCount ( ) = = 1 )
selectFirstFeed ( ) ;
rssmanager - > refresh ( newUrl ) ;
rssmanager - > saveStreamList ( ) ;
}
}
}
void RSSImp : : updateLastRefreshedTimeForStreams ( ) {
unsigned int nbFeeds = listStreams - > topLevelItemCount ( ) ;
for ( unsigned int i = 0 ; i < nbFeeds ; + + i ) {
QTreeWidgetItem * item = listStreams - > topLevelItem ( i ) ;
RssStream * stream = rssmanager - > getFeed ( item - > data ( 1 , Qt : : DisplayRole ) . toString ( ) ) ;
item - > setToolTip ( 0 , QString ( " <b> " ) + tr ( " Description: " ) + QString ( " </b> " ) + stream - > getDescription ( ) + QString ( " <br/><b> " ) + tr ( " url: " ) + QString ( " </b> " ) + stream - > getUrl ( ) + QString ( " <br/><b> " ) + tr ( " Last refresh: " ) + QString ( " </b> " ) + stream - > getLastRefreshElapsedString ( ) ) ;
}
}
// fills the newsList
void RSSImp : : refreshNewsList ( QTreeWidgetItem * item , int ) {
selectedFeedUrl = item - > text ( 1 ) ;
RssStream * stream = rssmanager - > getFeed ( selectedFeedUrl ) ;
listNews - > clear ( ) ;
qDebug ( " Getting the list of news " ) ;
QList < RssItem * > news = stream - > getNewsList ( ) ;
qDebug ( " Got the list of news " ) ;
RssItem * article ;
foreach ( article , news ) {
QListWidgetItem * it = new QListWidgetItem ( article - > getTitle ( ) , listNews ) ;
if ( article - > isRead ( ) ) {
it - > setData ( Qt : : ForegroundRole , QVariant ( QColor ( " grey " ) ) ) ;
it - > setData ( Qt : : DecorationRole , QVariant ( QIcon ( " :/Icons/sphere.png " ) ) ) ;
} else {
it - > setData ( Qt : : ForegroundRole , QVariant ( QColor ( " blue " ) ) ) ;
it - > setData ( Qt : : DecorationRole , QVariant ( QIcon ( " :/Icons/sphere2.png " ) ) ) ;
}
}
qDebug ( " Added all news to the GUI " ) ;
selectFirstNews ( ) ;
qDebug ( " First news selected " ) ;
}
// display a news
void RSSImp : : refreshTextBrowser ( QListWidgetItem * item ) {
RssItem * article = rssmanager - > getFeed ( selectedFeedUrl ) - > getItem ( listNews - > row ( item ) ) ;
textBrowser - > setHtml ( article - > getTitle ( ) + " :<br/> " + article - > getDescription ( ) ) ;
article - > setRead ( ) ;
item - > setData ( Qt : : ForegroundRole , QVariant ( QColor ( " grey " ) ) ) ;
item - > setData ( Qt : : DecorationRole , QVariant ( QIcon ( " :/Icons/sphere.png " ) ) ) ;
updateFeedNbNews ( selectedFeedUrl ) ;
}
QTreeWidgetItem * RSSImp : : getTreeItemFromUrl ( QString url ) const {
unsigned int nbItems = listStreams - > topLevelItemCount ( ) ;
for ( unsigned int i = 0 ; i < nbItems ; + + i ) {
QTreeWidgetItem * item = listStreams - > topLevelItem ( i ) ;
if ( item - > text ( 1 ) = = url )
return item ;
}
qDebug ( " Cannot find url %s in feeds list " , ( const char * ) url . toUtf8 ( ) ) ;
Q_ASSERT ( false ) ; // Should never go through here
return ( QTreeWidgetItem * ) 0 ;
}
void RSSImp : : updateFeedIcon ( QString url , QString icon_path ) {
QTreeWidgetItem * item = getTreeItemFromUrl ( url ) ;
item - > setData ( 0 , Qt : : DecorationRole , QVariant ( QIcon ( icon_path ) ) ) ;
}
void RSSImp : : updateFeedNbNews ( QString url ) {
QTreeWidgetItem * item = getTreeItemFromUrl ( url ) ;
RssStream * stream = rssmanager - > getFeed ( url ) ;
item - > setText ( 0 , stream - > getAliasOrUrl ( ) + QString ( " ( " ) + QString : : number ( stream - > getNbUnRead ( ) , 10 ) + String ( " ) " ) ) ;
}
void RSSImp : : updateFeedInfos ( QString url , QString aliasOrUrl , unsigned int nbUnread ) {
QTreeWidgetItem * item = getTreeItemFromUrl ( url ) ;
RssStream * stream = rssmanager - > getFeed ( url ) ;
item - > setText ( 0 , aliasOrUrl + QString ( " ( " ) + QString : : number ( nbUnread , 10 ) + String ( " ) " ) ) ;
item - > setData ( 0 , Qt : : DecorationRole , QVariant ( QIcon ( stream - > getIconPath ( ) ) ) ) ;
item - > setToolTip ( 0 , QString ( " <b> " ) + tr ( " Description: " ) + QString ( " </b> " ) + stream - > getDescription ( ) + QString ( " <br/><b> " ) + tr ( " url: " ) + QString ( " </b> " ) + stream - > getUrl ( ) + QString ( " <br/><b> " ) + tr ( " Last refresh: " ) + QString ( " </b> " ) + stream - > getLastRefreshElapsedString ( ) ) ;
// If the feed is selected, update the displayed news
if ( selectedFeedUrl = = url ) {
refreshNewsList ( getTreeItemFromUrl ( url ) , 0 ) ;
}
}
RSSImp : : RSSImp ( ) : QWidget ( ) {
setupUi ( this ) ;
// icons of bottom buttons
addStream_button - > setIcon ( QIcon ( QString : : fromUtf8 ( " :/Icons/skin/add.png " ) ) ) ;
delStream_button - > setIcon ( QIcon ( QString : : fromUtf8 ( " :/Icons/skin/remove.png " ) ) ) ;
refreshAll_button - > setIcon ( QIcon ( QString : : fromUtf8 ( " :/Icons/refresh.png " ) ) ) ;
// icons of right-click menu
actionDelete - > setIcon ( QIcon ( QString : : fromUtf8 ( " :/Icons/skin/remove.png " ) ) ) ;
actionRename - > setIcon ( QIcon ( QString : : fromUtf8 ( " :/Icons/log.png " ) ) ) ;
actionRefresh - > setIcon ( QIcon ( QString : : fromUtf8 ( " :/Icons/refresh.png " ) ) ) ;
actionCreate - > setIcon ( QIcon ( QString : : fromUtf8 ( " :/Icons/skin/add.png " ) ) ) ;
actionRefreshAll - > setIcon ( QIcon ( QString : : fromUtf8 ( " :/Icons/refresh.png " ) ) ) ;
// Hide second column (url)
listStreams - > hideColumn ( 1 ) ;
rssmanager = new RssManager ( ) ;
fillFeedsList ( ) ;
connect ( rssmanager , SIGNAL ( feedInfosChanged ( QString , QString , unsigned int ) ) , this , SLOT ( updateFeedInfos ( QString , QString , unsigned int ) ) ) ;
connect ( rssmanager , SIGNAL ( feedIconChanged ( QString , QString ) ) , this , SLOT ( updateFeedIcon ( QString , QString ) ) ) ;
connect ( listStreams , SIGNAL ( customContextMenuRequested ( const QPoint & ) ) , this , SLOT ( displayRSSListMenu ( const QPoint & ) ) ) ;
connect ( actionDelete , SIGNAL ( triggered ( ) ) , this , SLOT ( on_delStream_button_clicked ( ) ) ) ;
connect ( actionRename , SIGNAL ( triggered ( ) ) , this , SLOT ( renameStream ( ) ) ) ;
connect ( actionRefresh , SIGNAL ( triggered ( ) ) , this , SLOT ( refreshSelectedStreams ( ) ) ) ;
connect ( actionCreate , SIGNAL ( triggered ( ) ) , this , SLOT ( createStream ( ) ) ) ;
connect ( actionRefreshAll , SIGNAL ( triggered ( ) ) , this , SLOT ( refreshAllStreams ( ) ) ) ;
connect ( listStreams , SIGNAL ( itemClicked ( QTreeWidgetItem * , int ) ) , this , SLOT ( refreshNewsList ( QTreeWidgetItem * , int ) ) ) ;
connect ( listNews , SIGNAL ( itemClicked ( QListWidgetItem * ) ) , this , SLOT ( refreshTextBrowser ( QListWidgetItem * ) ) ) ;
connect ( listNews , SIGNAL ( itemDoubleClicked ( QListWidgetItem * ) ) , this , SLOT ( openInBrowser ( QListWidgetItem * ) ) ) ;
refreshTimeTimer = new QTimer ( this ) ;
connect ( refreshTimeTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( updateLastRefreshedTimeForStreams ( ) ) ) ;
refreshTimeTimer - > start ( 60000 ) ; // 1min
// Select first news of first feed
selectFirstFeed ( ) ;
// Refresh all feeds
rssmanager - > refreshAll ( ) ;
qDebug ( " RSSImp constructed " ) ;
}
void RSSImp : : selectFirstFeed ( ) {
if ( listStreams - > topLevelItemCount ( ) ) {
QTreeWidgetItem * first = listStreams - > topLevelItem ( 0 ) ;
listStreams - > setCurrentItem ( first ) ;
selectedFeedUrl = first - > text ( 1 ) ;
}
}
void RSSImp : : selectFirstNews ( ) {
if ( listNews - > count ( ) ) {
listNews - > setCurrentRow ( 0 ) ;
refreshTextBrowser ( listNews - > currentItem ( ) ) ;
}
}
RSSImp : : ~ RSSImp ( ) {
delete refreshTimeTimer ;
delete rssmanager ;
}