Index: trunk/playground/network/choqok/src/searchwindow.h =================================================================== --- trunk/playground/network/choqok/src/searchwindow.h (revision 933512) +++ trunk/playground/network/choqok/src/searchwindow.h (revision 933513) @@ -1,76 +1,92 @@ /* This file is part of choqoK, the KDE micro-blogging client Copyright (C) 2008-2009 Mehrdad Momeny 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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, see http://www.gnu.org/licenses/ */ #ifndef SEARCHWINDOW_H #define SEARCHWINDOW_H #include +#include #include "ui_searchwidget_base.h" #include "account.h" class QLabel; class StatusTextEdit; class StatusWidget; /** The Search Widget + For any microblogging service compatible with the Twitter Search API @author Stephen Henderson */ class SearchWindow : public QWidget { Q_OBJECT public: explicit SearchWindow( Account account, QWidget* parent = 0 ); ~SearchWindow(); void clearSearchResults(); + void updateStatusList(); void setAccount(Account account); +protected: + virtual void keyPressEvent( QKeyEvent *e ); + +public slots: + void updateSearchResults(); + void autoUpdateSearchResults(); + protected slots: void search(); void searchResultsReceived( QList &stautsList ); void error( QString message ); private slots: void initObjects(); signals: void forwardReply( const QString &username, uint statusId, bool dMsg ); void forwardFavorited( uint statusId, bool isFavorite ); +// void updateTimeLines(); private: void addNewStatusesToUi( QList &statusList ); + void resetSearchArea(); + void markStatusesAsRead(); protected: QList listResults; private: Account mAccount; Ui::searchwidget_base ui; + + QString lastSearchQuery; + int lastSearchType; }; #endif Index: trunk/playground/network/choqok/src/search.cpp =================================================================== --- trunk/playground/network/choqok/src/search.cpp (revision 933512) +++ trunk/playground/network/choqok/src/search.cpp (revision 933513) @@ -1,56 +1,58 @@ /* This file is part of choqoK, the KDE micro-blogging client Copyright (C) 2008-2009 Mehrdad Momeny 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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, see http://www.gnu.org/licenses/ */ #include "search.h" Search::Search() { } Search::~Search() { } QMap Search::getSearchTypes() { return mSearchTypes; } -KUrl Search::buildUrl( QString query, int option ) +KUrl Search::buildUrl( QString query, int option, uint sinceStatusId ) { Q_UNUSED(query); Q_UNUSED(option); + Q_UNUSED(sinceStatusId); return KUrl(); } -void Search::requestSearchResults( QString query, int option ) +void Search::requestSearchResults( QString query, int option, uint sinceStatusId ) { Q_UNUSED(query); Q_UNUSED(option); + Q_UNUSED(sinceStatusId) } void Search::searchResultsReturned( KJob* job ) { Q_UNUSED(job); } Index: trunk/playground/network/choqok/src/mainwindow.h =================================================================== --- trunk/playground/network/choqok/src/mainwindow.h (revision 933512) +++ trunk/playground/network/choqok/src/mainwindow.h (revision 933513) @@ -1,117 +1,118 @@ /* This file is part of choqoK, the KDE micro-blogging client Copyright (C) 2008-2009 Mehrdad Momeny 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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, see http://www.gnu.org/licenses/ */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include "datacontainers.h" #include "account.h" #include "ui_prefs_base.h" // #include "ui_accounts_base.h" #include "ui_appears_base.h" #include "searchwindow.h" #define TIMEOUT 5000 class QTimer; class QuickTwit; class SysTrayIcon; class KTabWidget; /** * This class serves as the main window for choqoK. It handles the * menus, toolbars, and status bars. * * @short Main window class * @author Mehrdad Momeny */ class MainWindow : public KXmlGuiWindow { Q_OBJECT public: /** * Default Constructor */ MainWindow(); /** * Default Destructor */ virtual ~MainWindow(); signals: void updateTimeLines(); + void updateSearchResults(); // void sigSetUnread( int unread ); void abortPostNewStatus(); void setUnreadStatusesToReadState(); public slots: void systemNotify( const QString &title, const QString &message, const QString &iconUrl ); protected slots: void optionsPreferences(); void search(); void settingsChanged(); void notify( const QString &message, bool isPermanent = false ); void quitApp(); void setNumOfUnreadOnMainWin( int unread ); void showTimeLine(); protected: void hideEvent( QHideEvent * event ); void checkUnreadStatuses( int numOfNewStatusesReciened ); bool queryClose(); private: void setupActions(); void setupQuickTweet(); void setDefaultDirection(); void disableApp(); void enableApp(); void loadConfigurations(); private slots: void loadAccounts(); void addAccountTimeLine( const Account &account, bool isStartup = false ); void removeAccountTimeLine( const QString &alias ); void setTimeLineUpdatesEnabled( bool isEnabled ); void setNotificationsEnabled( bool isEnabled ); void postQuickTwit(); private: KTabWidget *mainWidget; QTimer *timelineTimer; Ui::prefs_base ui_prefs_base; Ui::appears_base ui_appears_base; QString currentUsername;// used for undresanding of username changes! int mPrevNotifyType; int mPrevUpdateInterval; SysTrayIcon *sysIcon; QuickTwit *quickWidget; //QWidget* searchRoot; SearchWindow* searchWin; }; #endif Index: trunk/playground/network/choqok/src/twittersearch.cpp =================================================================== --- trunk/playground/network/choqok/src/twittersearch.cpp (revision 933512) +++ trunk/playground/network/choqok/src/twittersearch.cpp (revision 933513) @@ -1,207 +1,210 @@ /* This file is part of choqoK, the KDE micro-blogging client Copyright (C) 2008-2009 Mehrdad Momeny 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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, see http://www.gnu.org/licenses/ */ #include "twittersearch.h" #include #include #include #include #include #include #include TwitterSearch::TwitterSearch() : Search() { kDebug(); mSearchTypes[CustomSearch] = i18n( "Custom Search" ); mSearchTypes[ToUser] = i18n( "Tweets To This User" ); mSearchTypes[FromUser] = i18n( "Tweets From This User" ); mSearchTypes[ReferenceUser] = i18n( "Tweets Including This Users Name" ); mSearchTypes[ReferenceHashtag] = i18n( "Tweets Including This Hashtag" ); } TwitterSearch::~TwitterSearch() { kDebug(); } -KUrl TwitterSearch::buildUrl( QString query, int option ) +KUrl TwitterSearch::buildUrl( QString query, int option, uint sinceStatusId ) { kDebug(); - QString baseUrl = "http://search.twitter.com/search.atom?q="; + QString baseUrl = "http://search.twitter.com/search.atom?"; + if( sinceStatusId ) + baseUrl += "since_id=" + QString::number( sinceStatusId ) + "&"; + baseUrl += "q="; + + kDebug() << "Search URL: " << baseUrl; QString formattedQuery; switch ( option ) { case CustomSearch: formattedQuery = query; break; case ToUser: formattedQuery = "to:" + query; break; case FromUser: formattedQuery = "from:" + query; break; case ReferenceUser: formattedQuery = "@" + query; break; case ReferenceHashtag: formattedQuery = "%23" + query; break; default: formattedQuery = query; break; }; KUrl url( baseUrl + formattedQuery ); return url; } -void TwitterSearch::requestSearchResults( QString query, int option ) +void TwitterSearch::requestSearchResults( QString query, int option, uint sinceStatusId ) { kDebug(); - KUrl url = buildUrl( query, option ); + KUrl url = buildUrl( query, option, sinceStatusId ); KIO::StoredTransferJob *job = KIO::storedGet( url, KIO::Reload, KIO::HideProgressInfo ); if( !job ) { kDebug() << "Cannot create a http GET request!"; emit error( i18n( "Unable to fetch search results." ) ); return; } connect( job, SIGNAL( result( KJob* ) ), this, SLOT( searchResultsReturned( KJob* ) ) ); job->start(); } void TwitterSearch::searchResultsReturned( KJob* job ) { kDebug(); if( job == 0 ) { kDebug() << "job is a null pointer"; emit error( i18n( "Unable to fetch search results." ) ); return; } if( job->error() ) { kError() << "Error: " << job->errorString(); emit error( i18n( "Unable to fetch search results. ERROR: %1", job->errorString() ) ); return; } KIO::StoredTransferJob *jj = qobject_cast( job ); QList* statusList = parseAtom( jj->data() ); emit searchResultsReceived( *statusList ); } QList* TwitterSearch::parseAtom( const QByteArray &buffer ) { kDebug(); QDomDocument document; QList *statusList = new QList; document.setContent( buffer ); QDomElement root = document.documentElement(); if ( root.tagName() != "feed" ) { kDebug() << "There is no feed element in Atom feed " << buffer.data(); return 0; } QDomNode node = root.firstChild(); QString timeStr; while ( !node.isNull() ) { if ( node.toElement().tagName() != "entry" ) { node = node.nextSibling(); continue; } QDomNode entryNode = node.firstChild(); Status status; status.isDMessage = false; while ( !entryNode.isNull() ) { if ( entryNode.toElement().tagName() == "id" ) { // Fomatting example: "tag:search.twitter.com,2005:1235016836" int id = 0; sscanf( qPrintable( entryNode.toElement().text() ), "tag:search.twitter.com,%*d:%d", &id); status.statusId = id; } else if ( entryNode.toElement().tagName() == "published" ) { // Formatting example: "2009-02-21T19:42:39Z" // Need to extract date in similar fashion to dateFromString int year, month, day, hour, minute, second; sscanf( qPrintable( entryNode.toElement().text() ), "%d-%d-%dT%d:%d:%d%*s", &year, &month, &day, &hour, &minute, &second); QDateTime recognized( QDate( year, month, day), QTime( hour, minute, second ) ); recognized.setTimeSpec( Qt::UTC ); status.creationDateTime = recognized; } else if ( entryNode.toElement().tagName() == "title" ) { status.content = entryNode.toElement().text(); } else if ( entryNode.toElement().tagName() == "twitter:source" ) { status.source = entryNode.toElement().text(); } else if ( entryNode.toElement().tagName() == "link" && entryNode.toElement().attributeNode( "rel" ).value() == "image") { QDomAttr imageAttr = entryNode.toElement().attributeNode( "href" ); status.user.profileImageUrl = imageAttr.value(); } else if ( entryNode.toElement().tagName() == "author") { QDomNode userNode = entryNode.firstChild(); while ( !userNode.isNull() ) { if ( userNode.toElement().tagName() == "name" ) { QString fullName = userNode.toElement().text(); int bracketPos = fullName.indexOf( " ", 0 ); QString screenName = fullName.left( bracketPos ); QString name = fullName.right ( fullName.size() - bracketPos - 2 ); name.chop( 1 ); status.user.name = name; status.user.screenName = screenName; } userNode = userNode.nextSibling(); } - } else { - kDebug() << "No instructions on how to deal with element " << entryNode.toElement().tagName(); } entryNode = entryNode.nextSibling(); } status.isFavorited = false; status.isTruncated = false; status.replyToStatusId = 0; statusList->insert( 0, status ); node = node.nextSibling(); } return statusList; } Index: trunk/playground/network/choqok/src/searchwindow.cpp =================================================================== --- trunk/playground/network/choqok/src/searchwindow.cpp (revision 933512) +++ trunk/playground/network/choqok/src/searchwindow.cpp (revision 933513) @@ -1,146 +1,237 @@ /* This file is part of choqoK, the KDE micro-blogging client Copyright (C) 2008-2009 Mehrdad Momeny 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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, see http://www.gnu.org/licenses/ */ #include "searchwindow.h" #include "statuswidget.h" #include "settings.h" #include #include #include #include #include #include SearchWindow::SearchWindow( Account account, QWidget* parent ) : QWidget( parent ) { kDebug(); mAccount = account; ui.setupUi( this ); resize( Settings::searchWindowSize() ); move( Settings::searchWindowPosition() ); QTimer::singleShot( 0, this, SLOT( initObjects() ) ); } void SearchWindow::initObjects() { kDebug(); connect( mAccount.searchPtr(), SIGNAL( searchResultsReceived( QList< Status>& ) ), this, SLOT( searchResultsReceived ( QList< Status >& ) ) ); connect( mAccount.searchPtr(), SIGNAL( error( QString ) ), this, SLOT( error( QString ) ) ); connect( ui.txtSearch, SIGNAL( returnPressed() ), this, SLOT( search() ) ); - QMap searchTypes = mAccount.searchPtr()->getSearchTypes(); - for( int i = 0; i < searchTypes.count(); ++i ) - ui.comboSearchType->insertItem( i, searchTypes[i] ); + resetSearchArea(); } SearchWindow::~SearchWindow() { kDebug(); Settings::setSearchWindowPosition(pos()); Settings::setSearchWindowSize(size()); } void SearchWindow::error( QString message ) { ui.lblStatus->setText( i18n( "Failed, %1", message ) ); + lastSearchQuery.clear(); } void SearchWindow::searchResultsReceived(QList &statusList ) { kDebug(); - ui.txtSearch->setEnabled( true ); - clearSearchResults(); - int count = statusList.count(); if ( count == 0 ) { kDebug() << "Status list is empty"; ui.lblStatus->setText( i18n( "No search results." ) ); - return; } else { ui.lblStatus->setText( i18n( "Search Results Received!" ) ); addNewStatusesToUi( statusList ); ui.searchScroll->verticalScrollBar()->setSliderPosition( 0 ); } + ui.txtSearch->setEnabled( true ); } void SearchWindow::search() { kDebug(); if ( ui.txtSearch->text().size() > 140 ) { ui.lblStatus->setText( i18n( "Search text size is more than 140 characters." ) ); return; } ui.txtSearch->setEnabled( false ); + clearSearchResults(); ui.lblStatus->setText( i18n( "Searching..." ) ); mAccount.searchPtr()->requestSearchResults( ui.txtSearch->text(), - ui.comboSearchType->currentIndex() ); + ui.comboSearchType->currentIndex(), 0 ); + + lastSearchQuery = ui.txtSearch->text(); + lastSearchType = ui.comboSearchType->currentIndex(); +} + +void SearchWindow::updateSearchResults() +{ + kDebug(); + if( isVisible() && !lastSearchQuery.isNull() ) + { + uint sinceStatusId = 0; + if( listResults.count() ) + sinceStatusId = listResults.last()->currentStatus().statusId; + + ui.lblStatus->setText( i18n( "Searching..." ) ); + mAccount.searchPtr()->requestSearchResults( lastSearchQuery, + lastSearchType, + sinceStatusId ); + } +} + +void SearchWindow::autoUpdateSearchResults() +{ + kDebug(); + if( ui.chkAutoUpdate->isChecked() ) + updateSearchResults(); } void SearchWindow::addNewStatusesToUi( QList &statusList ) { kDebug(); + // This will make all statuses prior to the update marked as read + // and deleted if there are more than Settings::countOfStatusesOnMain. + // The reasoning for this is that there's a distinct possibility of + // a searching racking up thousands of unread messages depending on + // the query which would go undeleted as unread messages. The other + // option to avoid this would be to enforce a strict message limit + // regardless of whether or not they were marked as read. + markStatusesAsRead(); + QList::const_iterator it = statusList.constBegin(); QList::const_iterator endIt = statusList.constEnd(); for( ; it != endIt; ++it ) { StatusWidget *wt = new StatusWidget( &mAccount, this ); connect( wt, SIGNAL( sigReply( const QString&, uint, bool ) ), this, SIGNAL( forwardReply( const QString&, uint, bool ) ) ); connect( wt, SIGNAL( sigFavorite( uint, bool ) ), this, SIGNAL( forwardFavorited( uint, bool ) ) ); wt->setAttribute( Qt::WA_DeleteOnClose ); wt->setCurrentStatus( *it ); + wt->setUnread( StatusWidget::WithoutNotify ); listResults.append( wt ); ui.searchLayout->insertWidget( 0, wt ); } + updateStatusList(); +} + +void SearchWindow::updateStatusList() +{ + kDebug(); + int toBeDelete = listResults.count() - Settings::countOfStatusesOnMain(); + + if ( toBeDelete > 0 ) { + for ( int i = 0; i < toBeDelete; ++i ) { + StatusWidget* wt = listResults.at( i ); + + if ( !wt->isRead() ) + break; + + listResults.removeAt( i ); + + --i; + + --toBeDelete; + + wt->close(); + } + } } void SearchWindow::clearSearchResults() { kDebug(); int count = listResults.count(); for ( int i = 0; i < count; ++i ) { StatusWidget* wt = listResults.first(); listResults.removeFirst(); wt->close(); } } +void SearchWindow::markStatusesAsRead() +{ + kDebug(); + int count = listResults.count(); + for ( int i = 0;i < count; ++i ) { + listResults[i]->setRead(); + } +} + void SearchWindow::setAccount( Account account ) { mAccount = account; + resetSearchArea(); +} + +void SearchWindow::resetSearchArea() +{ + ui.txtSearch->setText( QString() ); + ui.comboSearchType->clear(); + ui.chkAutoUpdate->setChecked( false ); + + QMap searchTypes = mAccount.searchPtr()->getSearchTypes(); + for( int i = 0; i < searchTypes.count(); ++i ) + ui.comboSearchType->insertItem( i, searchTypes[i] ); +} + +void SearchWindow::keyPressEvent( QKeyEvent* e ) +{ + if ( e->key() == Qt::Key_F5 ) { +// emit updateTimeLines(); + updateSearchResults(); + e->accept(); + } else if ( e->modifiers() == Qt::CTRL && e->key() == Qt::Key_R ) { + markStatusesAsRead(); + } else { + QWidget::keyPressEvent( e ); + } } Index: trunk/playground/network/choqok/src/searchwidget_base.ui =================================================================== --- trunk/playground/network/choqok/src/searchwidget_base.ui (revision 933512) +++ trunk/playground/network/choqok/src/searchwidget_base.ui (revision 933513) @@ -1,117 +1,124 @@ searchwidget_base Qt::NonModal 0 - 129 + 120 320 400 0 0 choqoK true 1 0 0 QFrame::NoFrame QFrame::Plain true 0 0 318 313 0 0 1 Qt::Vertical 20 0 75 true No Search Results Qt::AlignCenter + + + + Auto-Update Results + + + qPixmapFromMimeSource Index: trunk/playground/network/choqok/src/search.h =================================================================== --- trunk/playground/network/choqok/src/search.h (revision 933512) +++ trunk/playground/network/choqok/src/search.h (revision 933513) @@ -1,67 +1,67 @@ /* This file is part of choqoK, the KDE micro-blogging client Copyright (C) 2008-2009 Mehrdad Momeny 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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, see http://www.gnu.org/licenses/ */ #ifndef SEARCH_H #define SEARCH_H #include #include #include #include #include "datacontainers.h" class KJob; /** Base class for search feature. @author Stephen Henderson */ class Search : public QObject { Q_OBJECT public: Search(); virtual ~Search(); QMap getSearchTypes(); private: - virtual KUrl buildUrl( QString query, int option ); + virtual KUrl buildUrl( QString query, int option, uint sinceStatusId = 0 ); public slots: - virtual void requestSearchResults( QString query, int option ); + virtual void requestSearchResults( QString query, int option, uint sinceStatusId = 0 ); protected slots: virtual void searchResultsReturned( KJob *job ); signals: void searchResultsReceived( QList &statusList ); void error( QString message ); protected: QMap mSearchTypes; }; #endif Index: trunk/playground/network/choqok/src/mainwindow.cpp =================================================================== --- trunk/playground/network/choqok/src/mainwindow.cpp (revision 933512) +++ trunk/playground/network/choqok/src/mainwindow.cpp (revision 933513) @@ -1,484 +1,491 @@ /* This file is part of choqoK, the KDE micro-blogging client Copyright (C) 2008-2009 Mehrdad Momeny 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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, see http://www.gnu.org/licenses/ */ #include "mainwindow.h" #include "settings.h" #include "timelinewidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "constants.h" #include "accounts.h" #include "accountmanager.h" #include "accountswizard.h" #include "searchwindow.h" #include "systrayicon.h" #include "quicktwit.h" #include "statuswidget.h" MainWindow::MainWindow() : KXmlGuiWindow() { kDebug(); quickWidget = 0; timelineTimer = new QTimer( this ); this->setAttribute( Qt::WA_DeleteOnClose, false ); mainWidget = new KTabWidget( this ); searchWin = 0; setCentralWidget( mainWidget ); sysIcon = new SysTrayIcon(this); // setupQuickTweet(); setupActions(); statusBar()->show(); notify( i18n( "Initializing choqoK, please be patient..." ) ); setupGUI(); // timelineTimer->setInterval ( Settings::updateInterval() *60000 ); // timelineTimer->start(); if ( Settings::notifyType() == SettingsBase::NoNotify ) mPrevNotifyType = 1; else mPrevNotifyType = Settings::notifyType(); if ( Settings::updateInterval() > 2 ) mPrevUpdateInterval = Settings::updateInterval(); else mPrevUpdateInterval = 10; connect( timelineTimer, SIGNAL( timeout() ), this, SIGNAL( updateTimeLines() ) ); connect( AccountManager::self(), SIGNAL( accountAdded( const Account& ) ), this, SLOT( addAccountTimeLine( const Account& ) ) ); connect( AccountManager::self(), SIGNAL( accountRemoved( const QString& ) ), this, SLOT( removeAccountTimeLine( const QString& ) ) ); settingsChanged(); QTimer::singleShot( 0, this, SLOT( loadAccounts() ) ); } MainWindow::~MainWindow() { kDebug(); } void MainWindow::setupActions() { KStandardAction::quit( qApp, SLOT( quit() ), actionCollection() ); connect( qApp, SIGNAL( aboutToQuit() ), this, SLOT( quitApp() ) ); KAction *prefs = KStandardAction::preferences( this, SLOT( optionsPreferences() ), actionCollection() ); KAction *actUpdate = new KAction( KIcon( "view-refresh" ), i18n( "Update timelines" ), this ); actionCollection()->addAction( QLatin1String( "update_timeline" ), actUpdate ); actUpdate->setShortcut( Qt::Key_F5 ); actUpdate->setGlobalShortcutAllowed( true ); KShortcut updateGlobalShortcut( Qt::CTRL | Qt::META | Qt::Key_F5 ); // updateGlobalShortcut.setAlternate ( Qt::MetaModifier | Qt::Key_F5 ); actUpdate->setGlobalShortcut( updateGlobalShortcut ); connect( actUpdate, SIGNAL( triggered( bool ) ), this, SIGNAL( updateTimeLines() ) ); + connect( actUpdate, SIGNAL( triggered( bool ) ), this, SIGNAL( updateSearchResults() ) ); KAction *newTwit = new KAction( KIcon( "document-new" ), i18n( "Quick Tweet" ), this ); actionCollection()->addAction( QLatin1String( "choqok_new_twit" ), newTwit ); newTwit->setShortcut( KShortcut( Qt::CTRL | Qt::Key_T ) ); newTwit->setGlobalShortcutAllowed( true ); KShortcut quickTwitGlobalShortcut( Qt::CTRL | Qt::META | Qt::Key_T ); newTwit->setGlobalShortcut( quickTwitGlobalShortcut ); connect( newTwit, SIGNAL( triggered(bool) ), this, SLOT( postQuickTwit() ) ); KAction *newSearch = new KAction( KIcon( "edit-find" ), i18n( "Search" ), this ); actionCollection()->addAction( QLatin1String( "choqok_search" ), newSearch ); newSearch->setShortcut( KShortcut( Qt::CTRL | Qt::Key_F ) ); newSearch->setGlobalShortcutAllowed( false ); connect( newSearch, SIGNAL( triggered( bool ) ), this, SLOT( search() ) ); KAction *markRead = new KAction( KIcon( "mail-mark-read" ), i18n( "Mark All As Read" ), this ); actionCollection()->addAction( QLatin1String( "choqok_mark_read" ), markRead ); markRead->setShortcut( KShortcut( Qt::CTRL | Qt::Key_R ) ); actUpdate->setGlobalShortcutAllowed( false ); connect( markRead, SIGNAL( triggered( bool ) ), this, SIGNAL( setUnreadStatusesToReadState() ) ); KAction *showMain = new KAction( this ); actionCollection()->addAction( QLatin1String( "toggle_mainwin" ), showMain ); KShortcut toggleMainGlobalShortcut( Qt::CTRL | Qt::META | Qt::Key_C ); showMain->setGlobalShortcutAllowed( true ); showMain->setGlobalShortcut( toggleMainGlobalShortcut/*, KAction::DefaultShortcut, KAction::NoAutoloading*/ ); showMain->setText( i18n( "Minimize" ) ); connect( showMain, SIGNAL( triggered( bool ) ), this, SLOT( hide() ) ); KAction *enableUpdates = new KAction( i18n( "Enable update timer" ), this ); enableUpdates->setCheckable( true ); actionCollection()->addAction( QLatin1String( "choqok_enable_updates" ), enableUpdates ); enableUpdates->setShortcut( KShortcut( Qt::CTRL | Qt::Key_U ) ); enableUpdates->setGlobalShortcutAllowed( true ); connect( enableUpdates, SIGNAL( toggled( bool ) ), this, SLOT( setTimeLineUpdatesEnabled( bool ) ) ); KAction *enableNotify = new KAction( i18n( "Enable notifications" ), this ); enableNotify->setCheckable( true ); actionCollection()->addAction( QLatin1String( "choqok_enable_notify" ), enableNotify ); enableNotify->setShortcut( KShortcut( Qt::CTRL | Qt::Key_N ) ); enableNotify->setGlobalShortcutAllowed( true ); connect( enableNotify, SIGNAL( toggled( bool ) ), this, SLOT( setNotificationsEnabled( bool ) ) ); ///SysTray Actions: sysIcon->contextMenu()->addAction( newTwit ); // sysIcon->contextMenu()->addAction( newSearch ); sysIcon->contextMenu()->addAction( actUpdate ); sysIcon->contextMenu()->addSeparator(); connect( enableUpdates, SIGNAL( toggled( bool ) ), sysIcon, SLOT( setTimeLineUpdatesEnabled( bool ) ) ); sysIcon->contextMenu()->addAction( enableUpdates ); sysIcon->setTimeLineUpdatesEnabled( enableUpdates->isChecked() ); sysIcon->show(); sysIcon->contextMenu()->addAction( enableNotify ); sysIcon->contextMenu()->addAction( prefs ); } void MainWindow::setupQuickTweet() { quickWidget = new QuickTwit( this ); connect( quickWidget, SIGNAL( sigNotify( const QString&, const QString&, const QString& ) ), this, SLOT( systemNotify( const QString&, const QString&, const QString& ) ) ); connect( quickWidget, SIGNAL( sigStatusUpdated( bool ) ), sysIcon, SLOT( slotStatusUpdated( bool ) ) ); } void MainWindow::postQuickTwit() { if(!quickWidget) setupQuickTweet(); if ( quickWidget->isVisible() ) { quickWidget->hide(); } else { quickWidget->showFocusedOnNewStatusField(); } } void MainWindow::systemNotify( const QString &title, const QString &message, const QString &iconUrl ) { if ( Settings::notifyType() == SettingsBase::KNotify ) {//KNotify KNotification *notif = new KNotification( "notify", this ); notif->setText( message ); // notify->setPixmap(mainWin-); notif->setFlags( KNotification::RaiseWidgetOnActivation | KNotification::Persistent ); notif->sendEvent(); QTimer::singleShot( Settings::notifyInterval()*1000, notif, SLOT( close() ) ); } else if ( Settings::notifyType() == SettingsBase::LibNotify ) {//Libnotify! QString msg = message; msg = msg.replace( "
", "\n" ); QString libnotifyCmd = QString( "notify-send -t " ) + QString::number( Settings::notifyInterval() * 1000 ) + QString( " -u low -i " + iconUrl + " \"" ) + title + QString( "\" \"" ) + msg + QString( "\"" ); QProcess::execute( libnotifyCmd ); } } void MainWindow::hideEvent( QHideEvent * event ) { Q_UNUSED(event); emit setUnreadStatusesToReadState(); } void MainWindow::optionsPreferences() { kDebug(); if ( KConfigDialog::showDialog( "settings" ) ) { return; } KConfigDialog *dialog = new KConfigDialog( this, "settings", Settings::self() ); QWidget *generalSettingsDlg = new QWidget; ui_prefs_base.setupUi( generalSettingsDlg ); dialog->addPage( generalSettingsDlg, i18n( "General" ), "configure" ); Accounts *accountsSettingsDlg = new Accounts( this ); dialog->addPage( accountsSettingsDlg, i18n( "Accounts" ), "user-properties" ); QWidget *appearsSettingsDlg = new QWidget; ui_appears_base.setupUi( appearsSettingsDlg ); dialog->addPage( appearsSettingsDlg, i18n( "Appearances" ), "format-stroke-color" ); connect( dialog, SIGNAL( settingsChanged( QString ) ), this, SLOT( settingsChanged() ) ); dialog->setAttribute( Qt::WA_DeleteOnClose ); dialog->show(); } void MainWindow::search() { kDebug(); TimeLineWidget * tmp = qobject_cast( mainWidget->widget( mainWidget->currentIndex() ) ); if( tmp->currentAccount().searchPtr() == 0 ) { kDebug() << "Service has no search implementation"; KMessageBox::error( this, i18n( "This service has no search feature." ) ); return; } if( !searchWin ) { searchWin = new SearchWindow( tmp->currentAccount(), 0 ); searchWin->setWindowTitle( i18nc( "Search in service", "%1 Search", tmp->currentAccount().serviceName() ) ); searchWin->show(); connect( searchWin, SIGNAL( forwardReply( const QString&, uint, bool ) ), tmp, SLOT( prepareReply( const QString&, uint, bool ) ) ); connect( searchWin, SIGNAL( forwardFavorited( uint, bool ) ), tmp->getBackend(), SLOT( requestFavorited( uint, bool ) ) ); + connect( this, SIGNAL( updateSearchResults() ), + searchWin, SLOT( updateSearchResults() ) ); + connect( timelineTimer, SIGNAL( timeout() ), + searchWin, SLOT( autoUpdateSearchResults() ) ); +// connect( searchWin, SIGNAL( updateTimeLines() ), this, SIGNAL( updateTimeLines() ) ); + ///I think this^ connection made code a bit confusing! -Mehrdad } else if ( searchWin->isVisible() ) { searchWin->hide(); } else { searchWin->clearSearchResults(); searchWin->setAccount( tmp->currentAccount() ); searchWin->setWindowTitle( i18nc( "Search in service", "%1 Search", tmp->currentAccount().serviceName() ) ); searchWin->show(); } } void MainWindow::settingsChanged() { kDebug(); if ( AccountManager::self()->accounts().count() < 1 ) { if ( KMessageBox::questionYesNo( this, i18n( "In order to use this app you need at \ least one account on Identi.ca or \ Twitter.com services.
Would you like to add your account now?
" ) ) == KMessageBox::Yes ) { AccountsWizard *dia = new AccountsWizard( QString(), this ); dia->setAttribute( Qt::WA_DeleteOnClose ); dia->show(); } } timelineTimer->setInterval( Settings::updateInterval() *60000 ); if ( Settings::isCustomUi() ) { StatusWidget::setStyle(Settings::newStatusForeColor(),Settings::newStatusBackColor(),Settings::defaultForeColor(),Settings::defaultBackColor()); } else { QPalette p = window()->palette(); StatusWidget::setStyle(p.color(QPalette::WindowText),p.color(QPalette::Window).lighter(),p.color(QPalette::WindowText),p.color(QPalette::Window)); } int count = mainWidget->count(); for ( int i = 0; i < count; ++i ) { qobject_cast( mainWidget->widget( i ) )->settingsChanged(); } if ( Settings::notifyType() == SettingsBase::NoNotify ) { actionCollection()->action( "choqok_enable_notify" )->setChecked( false ); } else { actionCollection()->action( "choqok_enable_notify" )->setChecked( true ); } if ( Settings::updateInterval() > 2 ) { timelineTimer->start(); // kDebug()<<"timelineTimer started"; actionCollection()->action( "choqok_enable_updates" )->setChecked( true ); } else { timelineTimer->stop(); // kDebug()<<"timelineTimer stoped"; actionCollection()->action( "choqok_enable_updates" )->setChecked( false ); } } void MainWindow::notify( const QString &message, bool isPermanent ) { if ( isPermanent ) { statusBar()->showMessage( message ); } else { statusBar()->showMessage( message, TIMEOUT ); } } void MainWindow::quitApp() { kDebug(); Settings::setPosition( pos() ); timelineTimer->stop(); Settings::self()->writeConfig(); deleteLater(); } void MainWindow::loadConfigurations() { kDebug(); } bool MainWindow::queryClose() { hide(); return false; } void MainWindow::disableApp() { kDebug(); timelineTimer->stop(); // kDebug()<<"timelineTimer stoped"; actionCollection()->action( "update_timeline" )->setEnabled( false ); actionCollection()->action( "choqok_new_twit" )->setEnabled( false ); actionCollection()->action( "choqok_search" )->setEnabled( false ); actionCollection()->action( "choqok_mark_read" )->setEnabled( false ); } void MainWindow::enableApp() { kDebug(); if ( Settings::updateInterval() > 2 ) { timelineTimer->start(); // kDebug()<<"timelineTimer started"; } actionCollection()->action( "update_timeline" )->setEnabled( true ); actionCollection()->action( "choqok_new_twit" )->setEnabled( true ); actionCollection()->action( "choqok_search" )->setEnabled( true ); actionCollection()->action( "choqok_mark_read" )->setEnabled( true ); } void MainWindow::addAccountTimeLine( const Account & account, bool isStartup ) { kDebug() << "Alias: " << account.alias() << "Service :" << account.serviceName(); TimeLineWidget *widget = new TimeLineWidget( account, this ); widget->layout()->setContentsMargins( 0, 0, 0, 0 ); connect( widget, SIGNAL( sigSetUnread( int ) ), sysIcon, SLOT( slotSetUnread( int ) ) ); connect( widget, SIGNAL( systemNotify( const QString&, const QString&, const QString& ) ), this, SLOT( systemNotify( const QString&, const QString&, const QString& ) ) ); connect( widget, SIGNAL( notify( const QString&, bool ) ), this, SLOT( notify( const QString&, bool ) ) ); connect( widget, SIGNAL( showMe() ), this, SLOT( showTimeLine() ) ); // connect(widget, SIGNAL(sigStatusUpdated(bool)), this, SIGNAL(sigStatusUpdated(bool))); connect( this, SIGNAL( updateTimeLines() ), widget, SLOT( updateTimeLines() ) ); connect( this, SIGNAL( abortPostNewStatus() ), widget, SLOT( abortPostNewStatus() ) ); connect( this, SIGNAL( setUnreadStatusesToReadState() ), widget, SLOT( setUnreadStatusesToReadState() ) ); connect( widget, SIGNAL( sigSetUnreadOnMainWin( int ) ), this, SLOT( setNumOfUnreadOnMainWin( int ) ) ); mainWidget->addTab( widget, account.alias() ); if ( !isStartup ) { QTimer::singleShot( 500, widget, SLOT( updateTimeLines() ) ); QTimer::singleShot( 1000, widget, SLOT(reloadFriendsList()) ); } enableApp(); } void MainWindow::loadAccounts() { kDebug(); QList ac = AccountManager::self()->accounts(); QListIterator it( ac ); while ( it.hasNext() ) { Account current = it.next(); addAccountTimeLine( current, true ); } if ( ac.count() > 0 ) { enableApp(); } else { disableApp(); } } void MainWindow::removeAccountTimeLine( const QString & alias ) { kDebug(); int count = mainWidget->count(); for ( int i = 0; i < count; ++i ) { TimeLineWidget * tmp = qobject_cast( mainWidget->widget( i ) ); if ( tmp->currentAccount().alias() == alias ) { mainWidget->removeTab( i ); if ( mainWidget->count() < 1 ) disableApp(); // tmp->setRemoved( true ); tmp->deleteLater(); return; } } } void MainWindow::setNumOfUnreadOnMainWin( int unread ) { // kDebug()<( sender() ); QString text; if ( unread <= 0 ) { text = subWidget->currentAccount().alias(); } else { text = i18nc( "account, unread","%1(%2)", subWidget->currentAccount().alias(), unread ); } mainWidget->setTabText( mainWidget->indexOf( subWidget ), text ); } void MainWindow::showTimeLine() { mainWidget->setCurrentWidget( qobject_cast( sender() ) ); if ( !this->isVisible() ) this->show(); this->raise(); } void MainWindow::setTimeLineUpdatesEnabled( bool isEnabled ) { kDebug(); if ( isEnabled ) { Settings::setUpdateInterval( mPrevUpdateInterval ); timelineTimer->start( Settings::updateInterval() *60000 ); // kDebug()<<"timelineTimer started"; } else { mPrevUpdateInterval = Settings::updateInterval(); timelineTimer->stop(); // kDebug()<<"timelineTimer stoped"; Settings::setUpdateInterval( 2 ); } } void MainWindow::setNotificationsEnabled( bool isEnabled ) { kDebug(); if ( isEnabled ) { Settings::setNotifyType( (SettingsBase::NotifyType) mPrevNotifyType ); } else { mPrevNotifyType = Settings::notifyType(); Settings::setNotifyType( SettingsBase::NoNotify ); } } #include "mainwindow.moc" Index: trunk/playground/network/choqok/src/twittersearch.h =================================================================== --- trunk/playground/network/choqok/src/twittersearch.h (revision 933512) +++ trunk/playground/network/choqok/src/twittersearch.h (revision 933513) @@ -1,59 +1,59 @@ /* This file is part of choqoK, the KDE micro-blogging client Copyright (C) 2008-2009 Mehrdad Momeny 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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, see http://www.gnu.org/licenses/ */ #ifndef TWITTERSEARCH_H #define TWITTERSEARCH_H #include #include "search.h" #include "datacontainers.h" /** Twitter.com search API implementation. @author Stephen Henderson */ class TwitterSearch : public Search { Q_OBJECT public: enum SearchType { CustomSearch = 0, ToUser, FromUser, ReferenceUser, ReferenceHashtag }; TwitterSearch(); virtual ~TwitterSearch(); private: - virtual KUrl buildUrl( QString query, int option ); + virtual KUrl buildUrl( QString query, int option, uint sinceStatusId = 0 ); QList* parseAtom( const QByteArray &buffer ); public slots: - virtual void requestSearchResults( QString query, int option ); + virtual void requestSearchResults( QString query, int option, uint sinceStatusId = 0 ); protected slots: virtual void searchResultsReturned( KJob *job ); }; #endif