2012-08-02 09:17:53 -04:00
/****************************************************************
* RetroShare GUI is distributed under the following license :
*
* Copyright ( C ) 2012 by Thunder
*
* 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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <QDateTime>
2012-08-03 21:15:40 -04:00
# include <QKeyEvent>
2012-08-02 09:17:53 -04:00
# include <QMenu>
# include <QInputDialog>
# include <QPixmap>
# include <QPainter>
# include <QMessageBox>
# include <QClipboard>
# include "FeedReaderDialog.h"
# include "ui_FeedReaderDialog.h"
# include "FeedReaderNotify.h"
# include "AddFeedDialog.h"
# include "gui/common/RSTreeWidgetItem.h"
# include "util/HandleRichText.h"
# include "gui/settings/rsharesettings.h"
# include "interface/rsFeedReader.h"
# include "retroshare/rsiface.h"
# define COLUMN_FEED_COUNT 1
# define COLUMN_FEED_NAME 0
# define COLUMN_FEED_DATA 0
# define ROLE_FEED_ID Qt::UserRole
# define ROLE_FEED_SORT Qt::UserRole + 1
# define ROLE_FEED_FOLDER Qt::UserRole + 2
# define ROLE_FEED_UNREAD Qt::UserRole + 3
# define ROLE_FEED_NAME Qt::UserRole + 4
# define ROLE_FEED_WORKSTATE Qt::UserRole + 5
# define ROLE_FEED_LOADING Qt::UserRole + 6
# define ROLE_FEED_ICON Qt::UserRole + 7
# define ROLE_FEED_ERROR Qt::UserRole + 8
# define ROLE_FEED_DEACTIVATED Qt::UserRole + 9
# define COLUMN_MSG_COUNT 4
# define COLUMN_MSG_TITLE 0
# define COLUMN_MSG_READ 1
# define COLUMN_MSG_PUBDATE 2
# define COLUMN_MSG_AUTHOR 3
# define COLUMN_MSG_DATA 0
# define ROLE_MSG_ID Qt::UserRole
# define ROLE_MSG_SORT Qt::UserRole + 1
# define ROLE_MSG_NEW Qt::UserRole + 2
# define ROLE_MSG_READ Qt::UserRole + 3
# define ROLE_MSG_LINK Qt::UserRole + 4
static int filterColumnToComboBox ( int nIndex )
{
switch ( nIndex ) {
case COLUMN_MSG_TITLE :
return 0 ;
case COLUMN_MSG_PUBDATE :
return 1 ;
case COLUMN_MSG_AUTHOR :
return 2 ;
}
return filterColumnToComboBox ( COLUMN_MSG_TITLE ) ;
}
static int filterColumnFromComboBox ( int nIndex )
{
switch ( nIndex ) {
case 0 :
return COLUMN_MSG_TITLE ;
case 1 :
return COLUMN_MSG_PUBDATE ;
case 2 :
return COLUMN_MSG_AUTHOR ;
}
return COLUMN_MSG_TITLE ;
}
FeedReaderDialog : : FeedReaderDialog ( RsFeedReader * feedReader , QWidget * parent )
: MainPage ( parent ) , mFeedReader ( feedReader ) , ui ( new Ui : : FeedReaderDialog )
{
/* Invoke the Qt Designer generated object setup routine */
ui - > setupUi ( this ) ;
mNotify = new FeedReaderNotify ( ) ;
mFeedReader - > setNotify ( mNotify ) ;
connect ( mNotify , SIGNAL ( notifyFeedChanged ( QString , int ) ) , this , SLOT ( feedChanged ( QString , int ) ) ) ;
connect ( mNotify , SIGNAL ( notifyMsgChanged ( QString , QString , int ) ) , this , SLOT ( msgChanged ( QString , QString , int ) ) ) ;
mProcessSettings = false ;
/* connect signals */
connect ( ui - > feedTreeWidget , SIGNAL ( currentItemChanged ( QTreeWidgetItem * , QTreeWidgetItem * ) ) , this , SLOT ( feedItemChanged ( QTreeWidgetItem * ) ) ) ;
connect ( ui - > msgTreeWidget , SIGNAL ( itemSelectionChanged ( ) ) , this , SLOT ( msgItemChanged ( ) ) ) ;
connect ( ui - > msgTreeWidget , SIGNAL ( itemClicked ( QTreeWidgetItem * , int ) ) , this , SLOT ( msgItemClicked ( QTreeWidgetItem * , int ) ) ) ;
connect ( ui - > feedTreeWidget , SIGNAL ( customContextMenuRequested ( QPoint ) ) , this , SLOT ( feedTreeCustomPopupMenu ( QPoint ) ) ) ;
connect ( ui - > msgTreeWidget , SIGNAL ( customContextMenuRequested ( QPoint ) ) , this , SLOT ( msgTreeCustomPopupMenu ( QPoint ) ) ) ;
connect ( ui - > filterLineEdit , SIGNAL ( textChanged ( QString ) ) , this , SLOT ( filterItems ( QString ) ) ) ;
connect ( ui - > filterColumnComboBox , SIGNAL ( currentIndexChanged ( int ) ) , this , SLOT ( filterColumnChanged ( ) ) ) ;
connect ( ui - > expandButton , SIGNAL ( clicked ( ) ) , this , SLOT ( toggleMsgText ( ) ) ) ;
mFeedCompareRole = new RSTreeWidgetItemCompareRole ;
mFeedCompareRole - > setRole ( COLUMN_FEED_NAME , ROLE_FEED_SORT ) ;
mMsgCompareRole = new RSTreeWidgetItemCompareRole ;
mMsgCompareRole - > setRole ( COLUMN_MSG_TITLE , ROLE_MSG_SORT ) ;
mMsgCompareRole - > setRole ( COLUMN_MSG_READ , ROLE_MSG_SORT ) ;
mMsgCompareRole - > setRole ( COLUMN_MSG_PUBDATE , ROLE_MSG_SORT ) ;
mMsgCompareRole - > setRole ( COLUMN_MSG_AUTHOR , ROLE_MSG_SORT ) ;
/* initialize root item */
mRootItem = new QTreeWidgetItem ( ui - > feedTreeWidget ) ;
QString name = tr ( " Message Folders " ) ;
mRootItem - > setText ( COLUMN_FEED_NAME , name ) ;
mRootItem - > setIcon ( COLUMN_FEED_NAME , QIcon ( " :/images/Root.png " ) ) ;
mRootItem - > setData ( COLUMN_FEED_DATA , ROLE_FEED_NAME , name ) ;
mRootItem - > setData ( COLUMN_FEED_DATA , ROLE_FEED_FOLDER , true ) ;
mRootItem - > setData ( COLUMN_FEED_DATA , ROLE_FEED_ICON , QIcon ( " :/images/Root.png " ) ) ;
mRootItem - > setExpanded ( true ) ;
/* initialize msg list */
ui - > msgTreeWidget - > sortItems ( COLUMN_MSG_PUBDATE , Qt : : DescendingOrder ) ;
/* set initial size the splitter */
QList < int > sizes ;
sizes < < 300 < < width ( ) ; // Qt calculates the right sizes
ui - > splitter - > setSizes ( sizes ) ;
/* set header resize modes and initial section sizes */
QHeaderView * header = ui - > msgTreeWidget - > header ( ) ;
header - > setResizeMode ( COLUMN_MSG_TITLE , QHeaderView : : Interactive ) ;
header - > resizeSection ( COLUMN_MSG_TITLE , 350 ) ;
header - > resizeSection ( COLUMN_MSG_PUBDATE , 140 ) ;
header - > resizeSection ( COLUMN_MSG_AUTHOR , 150 ) ;
/* set text of column "Read" to empty - without this the column has a number as header text */
QTreeWidgetItem * headerItem = ui - > msgTreeWidget - > headerItem ( ) ;
headerItem - > setText ( COLUMN_MSG_READ , " " ) ;
/* load settings */
processSettings ( true ) ;
/* Set header sizes for the fixed columns and resize modes, must be set after processSettings */
header - > resizeSection ( COLUMN_MSG_READ , 24 ) ;
header - > setResizeMode ( COLUMN_MSG_READ , QHeaderView : : Fixed ) ;
/* initialize feed list */
ui - > feedTreeWidget - > sortItems ( COLUMN_FEED_NAME , Qt : : AscendingOrder ) ;
ui - > msgTreeWidget - > installEventFilter ( this ) ;
}
FeedReaderDialog : : ~ FeedReaderDialog ( )
{
/* save settings */
processSettings ( false ) ;
delete ( mFeedCompareRole ) ;
delete ( mMsgCompareRole ) ;
delete ( ui ) ;
mFeedReader - > setNotify ( NULL ) ;
delete ( mNotify ) ;
}
void FeedReaderDialog : : processSettings ( bool load )
{
mProcessSettings = true ;
QHeaderView * header = ui - > msgTreeWidget - > header ( ) ;
Settings - > beginGroup ( QString ( " FeedReaderDialog " ) ) ;
if ( load ) {
// load settings
// expandButton
bool value = Settings - > value ( " expandButton " , true ) . toBool ( ) ;
ui - > expandButton - > setChecked ( value ) ;
toggleMsgText_internal ( ) ;
// filterColumn
ui - > filterColumnComboBox - > setCurrentIndex ( filterColumnToComboBox ( Settings - > value ( " filterColumn " , COLUMN_MSG_TITLE ) . toInt ( ) ) ) ;
// state of thread tree
header - > restoreState ( Settings - > value ( " msgTree " ) . toByteArray ( ) ) ;
// state of splitter
ui - > splitter - > restoreState ( Settings - > value ( " Splitter " ) . toByteArray ( ) ) ;
ui - > msgSplitter - > restoreState ( Settings - > value ( " msgSplitter " ) . toByteArray ( ) ) ;
} else {
// save settings
// state of thread tree
Settings - > setValue ( " msgTree " , header - > saveState ( ) ) ;
// state of splitter
Settings - > setValue ( " Splitter " , ui - > splitter - > saveState ( ) ) ;
Settings - > setValue ( " msgSplitter " , ui - > msgSplitter - > saveState ( ) ) ;
}
Settings - > endGroup ( ) ;
mProcessSettings = false ;
}
void FeedReaderDialog : : showEvent ( QShowEvent */ * event */ )
{
updateFeeds ( " " , mRootItem ) ;
}
bool FeedReaderDialog : : eventFilter ( QObject * obj , QEvent * event )
{
if ( obj = = ui - > msgTreeWidget ) {
if ( event - > type ( ) = = QEvent : : KeyPress ) {
QKeyEvent * keyEvent = static_cast < QKeyEvent * > ( event ) ;
if ( keyEvent ) {
if ( keyEvent - > key ( ) = = Qt : : Key_Space ) {
/* Space pressed */
QTreeWidgetItem * item = ui - > msgTreeWidget - > currentItem ( ) ;
msgItemClicked ( item , COLUMN_MSG_READ ) ;
return true ; // eat event
}
if ( keyEvent - > key ( ) = = Qt : : Key_Delete ) {
/* Delete pressed */
removeMsg ( ) ;
return true ; // eat event
}
}
}
}
if ( obj = = ui - > feedTreeWidget ) {
if ( event - > type ( ) = = QEvent : : KeyPress ) {
QKeyEvent * keyEvent = static_cast < QKeyEvent * > ( event ) ;
if ( keyEvent ) {
if ( keyEvent - > key ( ) = = Qt : : Key_Delete ) {
/* Delete pressed */
removeFeed ( ) ;
return true ; // eat event
}
}
}
}
/* pass the event on to the parent class */
return MainPage : : eventFilter ( obj , event ) ;
}
std : : string FeedReaderDialog : : currentFeedId ( )
{
QTreeWidgetItem * item = ui - > feedTreeWidget - > currentItem ( ) ;
if ( ! item ) {
return " " ;
}
return item - > data ( COLUMN_FEED_DATA , ROLE_FEED_ID ) . toString ( ) . toStdString ( ) ;
}
std : : string FeedReaderDialog : : currentMsgId ( )
{
QTreeWidgetItem * item = ui - > msgTreeWidget - > currentItem ( ) ;
if ( ! item ) {
return " " ;
}
return item - > data ( COLUMN_MSG_DATA , ROLE_MSG_ID ) . toString ( ) . toStdString ( ) ;
}
void FeedReaderDialog : : feedTreeCustomPopupMenu ( QPoint /*point*/ )
{
QMenu contextMnu ( this ) ;
bool folder = false ;
QTreeWidgetItem * item = ui - > feedTreeWidget - > currentItem ( ) ;
if ( item ) {
folder = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_FOLDER ) . toBool ( ) ;
}
QMenu * menu = contextMnu . addMenu ( QIcon ( " " ) , tr ( " New " ) ) ;
QAction * action = menu - > addAction ( QIcon ( " :/images/FeedAdd.png " ) , tr ( " Feed " ) , this , SLOT ( newFeed ( ) ) ) ;
if ( ! item | | ! folder ) {
action - > setEnabled ( false ) ;
}
action = menu - > addAction ( QIcon ( " :/images/FolderAdd.png " ) , tr ( " Folder " ) , this , SLOT ( newFolder ( ) ) ) ;
if ( ! item | | ! folder ) {
action - > setEnabled ( false ) ;
}
contextMnu . addSeparator ( ) ;
action = contextMnu . addAction ( QIcon ( " :/images/edit_16.png " ) , tr ( " Edit " ) , this , SLOT ( editFeed ( ) ) ) ;
if ( ! item | | item = = mRootItem ) {
action - > setEnabled ( false ) ;
}
action = contextMnu . addAction ( QIcon ( " :/images/delete.png " ) , tr ( " Delete " ) , this , SLOT ( removeFeed ( ) ) ) ;
if ( ! item | | item = = mRootItem ) {
action - > setEnabled ( false ) ;
}
contextMnu . addSeparator ( ) ;
bool deactivated = false ;
if ( ! folder & & item ) {
deactivated = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_DEACTIVATED ) . toBool ( ) ;
}
action = contextMnu . addAction ( QIcon ( " :/images/Update.png " ) , tr ( " Update " ) , this , SLOT ( processFeed ( ) ) ) ;
action - > setEnabled ( ! deactivated ) ;
action = contextMnu . addAction ( QIcon ( " " ) , deactivated ? tr ( " Activate " ) : tr ( " Deactivate " ) , this , SLOT ( activateFeed ( ) ) ) ;
if ( ! item | | item = = mRootItem | | folder ) {
action - > setEnabled ( false ) ;
}
contextMnu . exec ( QCursor : : pos ( ) ) ;
}
void FeedReaderDialog : : msgTreeCustomPopupMenu ( QPoint /*point*/ )
{
QMenu contextMnu ( this ) ;
QList < QTreeWidgetItem * > selectedItems = ui - > msgTreeWidget - > selectedItems ( ) ;
QAction * action = contextMnu . addAction ( QIcon ( " " ) , tr ( " Mark as read " ) , this , SLOT ( markAsReadMsg ( ) ) ) ;
action - > setEnabled ( ! selectedItems . empty ( ) ) ;
action = contextMnu . addAction ( QIcon ( " " ) , tr ( " Mark as unread " ) , this , SLOT ( markAsUnreadMsg ( ) ) ) ;
action - > setEnabled ( ! selectedItems . empty ( ) ) ;
action = contextMnu . addAction ( QIcon ( " " ) , tr ( " Mark all as read " ) , this , SLOT ( markAllAsReadMsg ( ) ) ) ;
contextMnu . addSeparator ( ) ;
action = contextMnu . addAction ( QIcon ( " " ) , tr ( " Copy link " ) , this , SLOT ( copyLinkMsg ( ) ) ) ;
action - > setEnabled ( ! selectedItems . empty ( ) ) ;
action = contextMnu . addAction ( QIcon ( " " ) , tr ( " Remove " ) , this , SLOT ( removeMsg ( ) ) ) ;
action - > setEnabled ( ! selectedItems . empty ( ) ) ;
contextMnu . exec ( QCursor : : pos ( ) ) ;
}
void FeedReaderDialog : : updateFeeds ( const std : : string & parentId , QTreeWidgetItem * parentItem )
{
if ( ! parentItem ) {
return ;
}
/* get feed infos */
std : : list < FeedInfo > feedInfos ;
mFeedReader - > getFeedList ( parentId , feedInfos ) ;
int index = 0 ;
QTreeWidgetItem * item ;
std : : list < FeedInfo > : : iterator feedIt ;
/* update existing and delete not existing feeds */
while ( index < parentItem - > childCount ( ) ) {
item = parentItem - > child ( index ) ;
std : : string feedId = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_ID ) . toString ( ) . toStdString ( ) ;
/* search existing feed */
int found = - 1 ;
for ( feedIt = feedInfos . begin ( ) ; feedIt ! = feedInfos . end ( ) ; + + feedIt ) {
if ( feedIt - > feedId = = feedId ) {
/* found it, update it */
updateFeedItem ( item , * feedIt ) ;
if ( feedIt - > flag . folder ) {
/* process child feeds */
updateFeeds ( feedIt - > feedId , item ) ;
}
feedInfos . erase ( feedIt ) ;
found = index ;
break ;
}
}
if ( found > = 0 ) {
+ + index ;
} else {
delete ( parentItem - > takeChild ( index ) ) ;
}
}
/* add new feeds */
for ( feedIt = feedInfos . begin ( ) ; feedIt ! = feedInfos . end ( ) ; + + feedIt ) {
item = new RSTreeWidgetItem ( mFeedCompareRole ) ;
parentItem - > addChild ( item ) ;
updateFeedItem ( item , * feedIt ) ;
if ( feedIt - > flag . folder ) {
/* process child feeds */
updateFeeds ( feedIt - > feedId , item ) ;
}
}
calculateFeedItems ( ) ;
}
void FeedReaderDialog : : calculateFeedItem ( QTreeWidgetItem * item , uint32_t & unreadCount , bool & loading )
{
uint32_t unreadCountItem = 0 ;
bool loadingItem = false ;
if ( item - > data ( COLUMN_FEED_DATA , ROLE_FEED_FOLDER ) . toBool ( ) ) {
int childCount = item - > childCount ( ) ;
for ( int index = 0 ; index < childCount ; + + index ) {
calculateFeedItem ( item - > child ( index ) , unreadCountItem , loadingItem ) ;
}
} else {
unreadCountItem = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_UNREAD ) . toUInt ( ) ;
loadingItem = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_LOADING ) . toBool ( ) ;
}
unreadCount + = unreadCountItem ;
loading = loading | | loadingItem ;
QString name = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_NAME ) . toString ( ) ;
QString workState = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_WORKSTATE ) . toString ( ) ;
if ( unreadCountItem ) {
name + = QString ( " (%1) " ) . arg ( unreadCountItem ) ;
}
if ( ! workState . isEmpty ( ) ) {
name + = QString ( " (%1) " ) . arg ( workState ) ;
}
item - > setText ( COLUMN_FEED_NAME , name ) ;
bool deactivated = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_DEACTIVATED ) . toBool ( ) ;
QColor colorActivated ;
QColor colorDeactivated = QColor ( Qt : : gray ) ;
for ( int i = 0 ; i < COLUMN_FEED_COUNT ; i + + ) {
QFont font = item - > font ( i ) ;
font . setBold ( unreadCountItem ! = 0 ) ;
item - > setFont ( i , font ) ;
item - > setTextColor ( COLUMN_FEED_NAME , deactivated ? colorDeactivated : colorActivated ) ;
}
QIcon icon = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_ICON ) . value < QIcon > ( ) ;
if ( deactivated ) {
/* create disabled icon */
icon = icon . pixmap ( QSize ( 16 , 16 ) , QIcon : : Disabled ) ;
}
QImage overlayIcon ;
if ( loadingItem ) {
/* overlaying icon */
overlayIcon = QImage ( " :/images/FeedProcessOverlay.png " ) ;
} else if ( item - > data ( COLUMN_FEED_DATA , ROLE_FEED_ERROR ) . toBool ( ) ) {
overlayIcon = QImage ( " :/images/FeedErrorOverlay.png " ) ;
}
if ( ! overlayIcon . isNull ( ) ) {
if ( icon . isNull ( ) ) {
icon = QPixmap : : fromImage ( overlayIcon ) ;
} else {
QPixmap pixmap = icon . pixmap ( QSize ( 16 , 16 ) ) ;
QPainter painter ( & pixmap ) ;
painter . drawImage ( 0 , 0 , overlayIcon . scaled ( pixmap . size ( ) , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ) ;
painter . end ( ) ;
icon = pixmap ;
}
}
item - > setIcon ( COLUMN_FEED_NAME , icon ) ;
}
void FeedReaderDialog : : calculateFeedItems ( )
{
uint32_t unreadCount = 0 ;
bool loading = false ;
calculateFeedItem ( mRootItem , unreadCount , loading ) ;
ui - > feedTreeWidget - > sortItems ( COLUMN_FEED_NAME , Qt : : AscendingOrder ) ;
}
void FeedReaderDialog : : updateFeedItem ( QTreeWidgetItem * item , FeedInfo & info )
{
QString workState ;
QIcon icon ;
if ( info . flag . folder ) {
/* use folder icon */
icon = QIcon ( " :/images/Folder.png " ) ;
} else {
long todo ; // show icon from feed
// if (info.icon.empty()) {
/* use standard icon */
icon = QIcon ( " :/images/Feed.png " ) ;
// } else {
// /* use icon from feed */
// icon = QIcon(QPixmap::fromImage(QImage((uchar*) QByteArray::fromBase64(info.icon.c_str()).constData(), 16, 16, QImage::Format_RGB32)));
// }
}
item - > setData ( COLUMN_FEED_DATA , ROLE_FEED_ICON , icon ) ;
switch ( info . workstate ) {
case FeedInfo : : WAITING :
break ;
case FeedInfo : : WAITING_TO_DOWNLOAD :
case FeedInfo : : DOWNLOADING :
workState = tr ( " loading " ) ;
break ;
case FeedInfo : : WAITING_TO_PROCESS :
case FeedInfo : : PROCESSING :
workState = tr ( " processing " ) ;
break ;
}
QString name = QString : : fromUtf8 ( info . name . c_str ( ) ) ;
item - > setData ( COLUMN_FEED_DATA , ROLE_FEED_NAME , name . isEmpty ( ) ? tr ( " No name " ) : name ) ;
item - > setData ( COLUMN_FEED_DATA , ROLE_FEED_WORKSTATE , workState ) ;
uint32_t unreadCount ;
mFeedReader - > getMessageCount ( info . feedId , NULL , NULL , & unreadCount ) ;
item - > setData ( COLUMN_FEED_NAME , ROLE_FEED_SORT , QString ( " %1_%2 " ) . arg ( QString ( info . flag . folder ? " 0 " : " 1 " ) , name ) ) ;
item - > setData ( COLUMN_FEED_DATA , ROLE_FEED_UNREAD , unreadCount ) ;
item - > setData ( COLUMN_FEED_DATA , ROLE_FEED_LOADING , info . workstate ! = FeedInfo : : WAITING ) ;
item - > setData ( COLUMN_FEED_DATA , ROLE_FEED_ID , QString : : fromStdString ( info . feedId ) ) ;
item - > setData ( COLUMN_FEED_DATA , ROLE_FEED_FOLDER , info . flag . folder ) ;
item - > setData ( COLUMN_FEED_DATA , ROLE_FEED_DEACTIVATED , info . flag . deactivated ) ;
item - > setData ( COLUMN_FEED_DATA , ROLE_FEED_ERROR , info . error ) ;
item - > setToolTip ( COLUMN_FEED_NAME , info . error ? QString : : fromUtf8 ( info . errorString . c_str ( ) ) : " " ) ;
}
void FeedReaderDialog : : updateMsgs ( const std : : string & feedId )
{
std : : list < FeedMsgInfo > msgInfos ;
if ( ! mFeedReader - > getFeedMsgList ( feedId , msgInfos ) ) {
ui - > msgTreeWidget - > clear ( ) ;
return ;
}
int index = 0 ;
QTreeWidgetItem * item ;
std : : list < FeedMsgInfo > : : iterator msgIt ;
/* update existing and delete not existing msgs */
while ( index < ui - > msgTreeWidget - > topLevelItemCount ( ) ) {
item = ui - > msgTreeWidget - > topLevelItem ( index ) ;
std : : string msgId = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_ID ) . toString ( ) . toStdString ( ) ;
/* search existing msg */
int found = - 1 ;
for ( msgIt = msgInfos . begin ( ) ; msgIt ! = msgInfos . end ( ) ; + + msgIt ) {
if ( msgIt - > msgId = = msgId ) {
/* found it, update it */
updateMsgItem ( item , * msgIt ) ;
msgInfos . erase ( msgIt ) ;
found = index ;
break ;
}
}
if ( found > = 0 ) {
+ + index ;
} else {
delete ( ui - > msgTreeWidget - > takeTopLevelItem ( index ) ) ;
}
}
/* add new msgs */
for ( msgIt = msgInfos . begin ( ) ; msgIt ! = msgInfos . end ( ) ; + + msgIt ) {
item = new RSTreeWidgetItem ( mMsgCompareRole ) ;
updateMsgItem ( item , * msgIt ) ;
ui - > msgTreeWidget - > addTopLevelItem ( item ) ;
}
filterItems ( ui - > filterLineEdit - > text ( ) ) ;
}
void FeedReaderDialog : : calculateMsgIconsAndFonts ( QTreeWidgetItem * item )
{
if ( ! item ) {
return ;
}
bool isnew = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_NEW ) . toBool ( ) ;
bool read = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_READ ) . toBool ( ) ;
if ( read ) {
item - > setIcon ( COLUMN_MSG_READ , QIcon ( " :/images/message-state-read.png " ) ) ;
} else {
item - > setIcon ( COLUMN_MSG_READ , QIcon ( " :/images/message-state-unread.png " ) ) ;
}
if ( isnew ) {
item - > setIcon ( COLUMN_MSG_TITLE , QIcon ( " :/images/message-state-new.png " ) ) ;
} else {
item - > setIcon ( COLUMN_MSG_TITLE , QIcon ( ) ) ;
}
for ( int i = 0 ; i < COLUMN_FEED_COUNT ; i + + ) {
QFont font = item - > font ( i ) ;
font . setBold ( isnew | | ! read ) ;
item - > setFont ( i , font ) ;
}
item - > setData ( COLUMN_MSG_READ , ROLE_MSG_SORT , QString ( " %1_%2_%3 " ) . arg ( QString ( isnew ? " 1 " : " 0 " ) , QString ( read ? " 0 " : " 1 " ) , item - > data ( COLUMN_MSG_TITLE , ROLE_MSG_SORT ) . toString ( ) ) ) ;
}
void FeedReaderDialog : : updateMsgItem ( QTreeWidgetItem * item , FeedMsgInfo & info )
{
QString title = QString : : fromUtf8 ( info . title . c_str ( ) ) ;
QDateTime qdatetime ;
qdatetime . setTime_t ( info . pubDate ) ;
/* add string to all data */
QString sort = QString ( " %1_%2_%2 " ) . arg ( title , qdatetime . toString ( " yyyyMMdd_hhmmss " ) , QString : : fromStdString ( info . feedId ) ) ;
item - > setText ( COLUMN_MSG_TITLE , title ) ;
item - > setData ( COLUMN_MSG_TITLE , ROLE_MSG_SORT , sort ) ;
QString author = QString : : fromUtf8 ( info . author . c_str ( ) ) ;
item - > setText ( COLUMN_MSG_AUTHOR , author ) ;
item - > setData ( COLUMN_MSG_AUTHOR , ROLE_MSG_SORT , author + " _ " + sort ) ;
/* if the message is on same date show only time */
if ( qdatetime . daysTo ( QDateTime : : currentDateTime ( ) ) = = 0 ) {
item - > setData ( COLUMN_MSG_PUBDATE , Qt : : DisplayRole , qdatetime . time ( ) ) ;
} else {
item - > setData ( COLUMN_MSG_PUBDATE , Qt : : DisplayRole , qdatetime ) ;
}
item - > setData ( COLUMN_MSG_PUBDATE , ROLE_MSG_SORT , QString ( " %1_%2_%3 " ) . arg ( qdatetime . toString ( " yyyyMMdd_hhmmss " ) , title , QString : : fromStdString ( info . msgId ) ) ) ;
item - > setData ( COLUMN_MSG_DATA , ROLE_MSG_ID , QString : : fromStdString ( info . msgId ) ) ;
item - > setData ( COLUMN_MSG_DATA , ROLE_MSG_LINK , QString : : fromUtf8 ( info . link . c_str ( ) ) ) ;
item - > setData ( COLUMN_MSG_DATA , ROLE_MSG_READ , info . flag . read ) ;
item - > setData ( COLUMN_MSG_DATA , ROLE_MSG_NEW , info . flag . isnew ) ;
calculateMsgIconsAndFonts ( item ) ;
}
void FeedReaderDialog : : feedChanged ( const QString & feedId , int type )
{
if ( ! isVisible ( ) ) {
/* complete update in showEvent */
return ;
}
if ( feedId . isEmpty ( ) ) {
return ;
}
FeedInfo feedInfo ;
if ( type ! = NOTIFY_TYPE_DEL ) {
if ( ! mFeedReader - > getFeedInfo ( feedId . toStdString ( ) , feedInfo ) ) {
return ;
}
}
if ( type = = NOTIFY_TYPE_MOD | | type = = NOTIFY_TYPE_DEL ) {
QTreeWidgetItemIterator it ( ui - > feedTreeWidget ) ;
QTreeWidgetItem * item ;
while ( ( item = * it ) ! = NULL ) {
if ( item - > data ( COLUMN_FEED_DATA , ROLE_FEED_ID ) . toString ( ) = = feedId ) {
if ( type = = NOTIFY_TYPE_MOD ) {
updateFeedItem ( item , feedInfo ) ;
} else {
delete ( item ) ;
}
break ;
}
+ + it ;
}
}
if ( type = = NOTIFY_TYPE_ADD ) {
QString id = QString : : fromStdString ( feedInfo . parentId ) ;
QTreeWidgetItemIterator it ( ui - > feedTreeWidget ) ;
QTreeWidgetItem * itemParent ;
while ( ( itemParent = * it ) ! = NULL ) {
if ( itemParent - > data ( COLUMN_FEED_DATA , ROLE_FEED_ID ) . toString ( ) = = id ) {
QTreeWidgetItem * item = new RSTreeWidgetItem ( mFeedCompareRole ) ;
itemParent - > addChild ( item ) ;
updateFeedItem ( item , feedInfo ) ;
break ;
}
+ + it ;
}
}
calculateFeedItems ( ) ;
}
void FeedReaderDialog : : msgChanged ( const QString & feedId , const QString & msgId , int type )
{
if ( ! isVisible ( ) ) {
/* complete update in showEvent */
return ;
}
if ( feedId . isEmpty ( ) | | msgId . isEmpty ( ) ) {
return ;
}
if ( feedId . toStdString ( ) ! = currentFeedId ( ) ) {
return ;
}
FeedMsgInfo msgInfo ;
if ( type ! = NOTIFY_TYPE_DEL ) {
if ( ! mFeedReader - > getMsgInfo ( feedId . toStdString ( ) , msgId . toStdString ( ) , msgInfo ) ) {
return ;
}
}
if ( type = = NOTIFY_TYPE_MOD | | type = = NOTIFY_TYPE_DEL ) {
QTreeWidgetItemIterator it ( ui - > msgTreeWidget ) ;
QTreeWidgetItem * item ;
while ( ( item = * it ) ! = NULL ) {
if ( item - > data ( COLUMN_MSG_DATA , ROLE_MSG_ID ) . toString ( ) = = msgId ) {
if ( type = = NOTIFY_TYPE_MOD ) {
updateMsgItem ( item , msgInfo ) ;
filterItem ( item ) ;
} else {
delete ( item ) ;
}
break ;
}
+ + it ;
}
}
if ( type = = NOTIFY_TYPE_ADD ) {
QTreeWidgetItem * item = new RSTreeWidgetItem ( mMsgCompareRole ) ;
updateMsgItem ( item , msgInfo ) ;
ui - > msgTreeWidget - > addTopLevelItem ( item ) ;
filterItem ( item ) ;
}
}
void FeedReaderDialog : : feedItemChanged ( QTreeWidgetItem * item )
{
if ( ! item ) {
ui - > msgTreeWidget - > clear ( ) ;
return ;
}
std : : string feedId = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_ID ) . toString ( ) . toStdString ( ) ;
updateMsgs ( feedId ) ;
}
void FeedReaderDialog : : msgItemClicked ( QTreeWidgetItem * item , int column )
{
if ( item = = NULL ) {
return ;
}
if ( column = = COLUMN_MSG_READ ) {
QList < QTreeWidgetItem * > rows ;
rows . append ( item ) ;
bool read = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_READ ) . toBool ( ) ;
setMsgAsReadUnread ( rows , ! read ) ;
return ;
}
}
void FeedReaderDialog : : msgItemChanged ( )
{
long todo ; // show link somewhere
std : : string feedId = currentFeedId ( ) ;
std : : string msgId = currentMsgId ( ) ;
if ( feedId . empty ( ) | | msgId . empty ( ) ) {
ui - > msgTitle - > clear ( ) ;
// ui->msgLink->clear();
ui - > msgText - > clear ( ) ;
return ;
}
QTreeWidgetItem * item = ui - > msgTreeWidget - > currentItem ( ) ;
if ( ! item ) {
/* there is something wrong */
ui - > msgTitle - > clear ( ) ;
// ui->msgLink->clear();
ui - > msgText - > clear ( ) ;
return ;
}
/* get msg */
FeedMsgInfo msgInfo ;
if ( ! mFeedReader - > getMsgInfo ( feedId , msgId , msgInfo ) ) {
ui - > msgTitle - > clear ( ) ;
// ui->msgLink->clear();
ui - > msgText - > clear ( ) ;
return ;
}
bool setToReadOnActive = Settings - > valueFromGroup ( " FeedReaderDialog " , " SetMsgToReadOnActivate " , true ) . toBool ( ) ;
bool isnew = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_NEW ) . toBool ( ) ;
bool read = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_READ ) . toBool ( ) ;
QList < QTreeWidgetItem * > row ;
row . append ( item ) ;
if ( read ) {
if ( isnew ) {
/* something wrong, but set as read again to clear the new flag */
setMsgAsReadUnread ( row , true ) ;
}
} else {
/* set to read/unread */
setMsgAsReadUnread ( row , setToReadOnActive ) ;
}
QString msgTxt = RsHtml ( ) . formatText ( ui - > msgText - > document ( ) , QString : : fromUtf8 ( msgInfo . description . c_str ( ) ) , RSHTML_FORMATTEXT_EMBED_LINKS ) ;
ui - > msgText - > setHtml ( msgTxt ) ;
ui - > msgTitle - > setText ( QString : : fromUtf8 ( msgInfo . title . c_str ( ) ) ) ;
// ui->msgLink->setHtml(RsHtml().formatText(NULL, QString::fromUtf8(msgInfo.link.c_str()), RSHTML_FORMATTEXT_EMBED_LINKS));
}
void FeedReaderDialog : : setMsgAsReadUnread ( QList < QTreeWidgetItem * > & rows , bool read )
{
QList < QTreeWidgetItem * > : : iterator rowIt ;
std : : string feedId = currentFeedId ( ) ;
if ( feedId . empty ( ) ) {
return ;
}
for ( rowIt = rows . begin ( ) ; rowIt ! = rows . end ( ) ; rowIt + + ) {
QTreeWidgetItem * item = * rowIt ;
bool rowRead = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_READ ) . toBool ( ) ;
bool rowNew = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_NEW ) . toBool ( ) ;
if ( rowNew | | read ! = rowRead ) {
std : : string msgId = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_ID ) . toString ( ) . toStdString ( ) ;
mFeedReader - > setMessageRead ( feedId , msgId , read ) ;
}
}
}
void FeedReaderDialog : : filterColumnChanged ( )
{
if ( mProcessSettings ) {
return ;
}
filterItems ( ui - > filterLineEdit - > text ( ) ) ;
// save index
int filterColumn = filterColumnFromComboBox ( ui - > filterColumnComboBox - > currentIndex ( ) ) ;
Settings - > setValueToGroup ( " FeedReaderDialog " , " filterColumn " , filterColumn ) ;
}
void FeedReaderDialog : : filterItems ( const QString & text )
{
int filterColumn = filterColumnFromComboBox ( ui - > filterColumnComboBox - > currentIndex ( ) ) ;
int count = ui - > msgTreeWidget - > topLevelItemCount ( ) ;
for ( int index = 0 ; index < count ; + + index ) {
filterItem ( ui - > msgTreeWidget - > topLevelItem ( index ) , text , filterColumn ) ;
}
}
void FeedReaderDialog : : filterItem ( QTreeWidgetItem * item , const QString & text , int filterColumn )
{
if ( text . isEmpty ( ) = = false ) {
if ( item - > text ( filterColumn ) . contains ( text , Qt : : CaseInsensitive ) ) {
item - > setHidden ( false ) ;
} else {
item - > setHidden ( true ) ;
}
} else {
item - > setHidden ( false ) ;
}
}
void FeedReaderDialog : : filterItem ( QTreeWidgetItem * item )
{
filterItem ( item , ui - > filterLineEdit - > text ( ) , filterColumnFromComboBox ( ui - > filterColumnComboBox - > currentIndex ( ) ) ) ;
}
void FeedReaderDialog : : toggleMsgText ( )
{
// save state of button
Settings - > setValueToGroup ( " FeedReaderDialog " , " expandButton " , ui - > expandButton - > isChecked ( ) ) ;
toggleMsgText_internal ( ) ;
}
void FeedReaderDialog : : toggleMsgText_internal ( )
{
if ( ui - > expandButton - > isChecked ( ) ) {
ui - > msgText - > setVisible ( true ) ;
ui - > expandButton - > setIcon ( QIcon ( QString ( " :/images/edit_remove24.png " ) ) ) ;
ui - > expandButton - > setToolTip ( tr ( " Hide " ) ) ;
} else {
ui - > msgText - > setVisible ( false ) ;
ui - > expandButton - > setIcon ( QIcon ( QString ( " :/images/edit_add24.png " ) ) ) ;
ui - > expandButton - > setToolTip ( tr ( " Expand " ) ) ;
}
}
void FeedReaderDialog : : newFolder ( )
{
QInputDialog dialog ;
dialog . setWindowTitle ( tr ( " Add new folder " ) ) ;
dialog . setLabelText ( tr ( " Please enter a name for the folder " ) ) ;
dialog . setWindowIcon ( QIcon ( " :/images/FeedReader.png " ) ) ;
if ( dialog . exec ( ) = = QDialog : : Accepted & & ! dialog . textValue ( ) . isEmpty ( ) ) {
std : : string feedId ;
RsFeedAddResult result = mFeedReader - > addFolder ( currentFeedId ( ) , dialog . textValue ( ) . toUtf8 ( ) . constData ( ) , feedId ) ;
AddFeedDialog : : showError ( this , result , tr ( " Create folder " ) , tr ( " Cannot create folder. " ) ) ;
}
}
void FeedReaderDialog : : newFeed ( )
{
AddFeedDialog dialog ( mFeedReader , this ) ;
dialog . setParent ( currentFeedId ( ) ) ;
dialog . exec ( ) ;
}
void FeedReaderDialog : : removeFeed ( )
{
std : : string feedId = currentFeedId ( ) ;
if ( feedId . empty ( ) ) {
return ;
}
QTreeWidgetItem * item = ui - > feedTreeWidget - > currentItem ( ) ;
if ( ! item ) {
return ;
}
bool folder = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_FOLDER ) . toBool ( ) ;
QString name = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_NAME ) . toString ( ) ;
if ( QMessageBox : : question ( this , folder ? tr ( " Remove folder " ) : tr ( " Remove feed " ) , folder ? tr ( " Do you want to remove the folder %1? " ) . arg ( name ) : tr ( " Do you want to remove the feed %1? " ) . arg ( name ) , QMessageBox : : Yes | QMessageBox : : No , QMessageBox : : No ) = = QMessageBox : : Yes ) {
mFeedReader - > removeFeed ( feedId ) ;
}
}
void FeedReaderDialog : : editFeed ( )
{
std : : string feedId = currentFeedId ( ) ;
if ( feedId . empty ( ) ) {
return ;
}
QTreeWidgetItem * item = ui - > feedTreeWidget - > currentItem ( ) ;
if ( ! item ) {
return ;
}
bool folder = item - > data ( COLUMN_FEED_DATA , ROLE_FEED_FOLDER ) . toBool ( ) ;
if ( folder ) {
QInputDialog dialog ;
dialog . setWindowTitle ( tr ( " Edit folder " ) ) ;
dialog . setLabelText ( tr ( " Please enter a new name for the folder " ) ) ;
dialog . setWindowIcon ( QIcon ( " :/images/FeedReader.png " ) ) ;
dialog . setTextValue ( item - > data ( COLUMN_FEED_DATA , ROLE_FEED_NAME ) . toString ( ) ) ;
if ( dialog . exec ( ) = = QDialog : : Accepted & & ! dialog . textValue ( ) . isEmpty ( ) ) {
RsFeedAddResult result = mFeedReader - > setFolder ( feedId , dialog . textValue ( ) . toUtf8 ( ) . constData ( ) ) ;
AddFeedDialog : : showError ( this , result , tr ( " Create folder " ) , tr ( " Cannot create folder. " ) ) ;
}
} else {
AddFeedDialog dialog ( mFeedReader , this ) ;
if ( ! dialog . fillFeed ( feedId ) ) {
return ;
}
dialog . exec ( ) ;
}
}
void FeedReaderDialog : : activateFeed ( )
{
std : : string feedId = currentFeedId ( ) ;
if ( feedId . empty ( ) ) {
return ;
}
FeedInfo feedInfo ;
if ( ! mFeedReader - > getFeedInfo ( feedId , feedInfo ) ) {
return ;
}
if ( feedInfo . flag . folder ) {
return ;
}
feedInfo . flag . deactivated = ! feedInfo . flag . deactivated ;
mFeedReader - > setFeed ( feedId , feedInfo ) ;
}
void FeedReaderDialog : : processFeed ( )
{
std : : string feedId = currentFeedId ( ) ;
/* empty feed id process all feeds */
mFeedReader - > processFeed ( feedId ) ;
}
void FeedReaderDialog : : markAsReadMsg ( )
{
QList < QTreeWidgetItem * > selectedItems = ui - > msgTreeWidget - > selectedItems ( ) ;
setMsgAsReadUnread ( selectedItems , true ) ;
}
void FeedReaderDialog : : markAsUnreadMsg ( )
{
QList < QTreeWidgetItem * > selectedItems = ui - > msgTreeWidget - > selectedItems ( ) ;
setMsgAsReadUnread ( selectedItems , false ) ;
}
void FeedReaderDialog : : markAllAsReadMsg ( )
{
QList < QTreeWidgetItem * > items ;
QTreeWidgetItemIterator it ( ui - > msgTreeWidget ) ;
QTreeWidgetItem * item ;
while ( ( item = * it ) ! = NULL ) {
if ( ! item - > isHidden ( ) ) {
items . push_back ( item ) ;
}
+ + it ;
}
setMsgAsReadUnread ( items , true ) ;
}
void FeedReaderDialog : : copyLinkMsg ( )
{
QString links ;
QTreeWidgetItemIterator it ( ui - > msgTreeWidget , QTreeWidgetItemIterator : : Selected ) ;
QTreeWidgetItem * item ;
while ( ( item = * it ) ! = NULL ) {
QString link = item - > data ( COLUMN_MSG_DATA , ROLE_MSG_LINK ) . toString ( ) ;
if ( ! link . isEmpty ( ) ) {
links + = link + " \n " ;
}
+ + it ;
}
if ( links . isEmpty ( ) ) {
return ;
}
QApplication : : clipboard ( ) - > setText ( links ) ;
}
void FeedReaderDialog : : removeMsg ( )
{
std : : string feedId = currentFeedId ( ) ;
if ( feedId . empty ( ) ) {
return ;
}
QList < QTreeWidgetItem * > selectedItems = ui - > msgTreeWidget - > selectedItems ( ) ;
QList < QTreeWidgetItem * > : : iterator it ;
std : : list < std : : string > msgIds ;
for ( it = selectedItems . begin ( ) ; it ! = selectedItems . end ( ) ; + + it ) {
msgIds . push_back ( ( * it ) - > data ( COLUMN_MSG_DATA , ROLE_MSG_ID ) . toString ( ) . toStdString ( ) ) ;
}
mFeedReader - > removeMsgs ( feedId , msgIds ) ;
}