diff --git a/src/ConfigDialog.cpp b/src/ConfigDialog.cpp index 26f64945b..46f806ead 100644 --- a/src/ConfigDialog.cpp +++ b/src/ConfigDialog.cpp @@ -44,14 +44,14 @@ ConfigDialog::ConfigDialog(QDir _home, Zones *_zones, MainWindow *mainWindow) : configPage = new ConfigurationPage(mainWindow); devicePage = new DevicePage(this); - - twitterPage = new TwitterPage(this); - pagesWidget = new QStackedWidget; pagesWidget->addWidget(configPage); pagesWidget->addWidget(cyclistPage); pagesWidget->addWidget(devicePage); + #ifdef GC_HAVE_LIBOAUTH + twitterPage = new TwitterPage(this); pagesWidget->addWidget(twitterPage); + #endif closeButton = new QPushButton(tr("Close")); saveButton = new QPushButton(tr("Save")); @@ -117,11 +117,13 @@ void ConfigDialog::createIcons() realtimeButton->setTextAlignment(Qt::AlignHCenter); realtimeButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); +#ifdef GC_HAVE_LIBOAUTH QListWidgetItem *twitterButton = new QListWidgetItem(contentsWidget); twitterButton->setIcon(QIcon(":images/twitter.png")); twitterButton->setText(tr("Twitter")); twitterButton->setTextAlignment(Qt::AlignHCenter); twitterButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); +#endif connect(contentsWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), @@ -169,11 +171,6 @@ void ConfigDialog::save_Clicked() settings->setValue(GC_LTS_DAYS, cyclistPage->perfManLTSavg->text()); settings->setValue(GC_SB_TODAY, (int) cyclistPage->showSBToday->isChecked()); - //Save Twitter - Info PASSWORD IS IN CLEAR - settings->setValue(GC_TWITTER_USERNAME, twitterPage->accountName->text()); - settings->setValue(GC_TWITTER_PASSWORD, twitterPage->passwordEdit->text()); - - // set default stress names if not set: settings->setValue(GC_STS_NAME, settings->value(GC_STS_NAME,tr("Short Term Stress"))); settings->setValue(GC_STS_ACRONYM, settings->value(GC_STS_ACRONYM,tr("STS"))); @@ -188,6 +185,10 @@ void ConfigDialog::save_Clicked() // save interval metrics and ride data pages configPage->saveClicked(); +#ifdef GC_HAVE_LIBOAUTH + //Call Twitter Save Dialog to get Access Token + twitterPage->saveClicked(); +#endif // Save the device configuration... DeviceConfigurations all; all.writeConfig(devicePage->deviceListModel->Configuration); diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 62412f9aa..2f43b5faf 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -950,10 +950,6 @@ MainWindow::showTreeContextMenuPopup(const QPoint &pos) QAction *actSplitRide = new QAction(tr("Split Ride"), treeWidget); connect(actSplitRide, SIGNAL(triggered(void)), this, SLOT(splitRide())); - QAction *actTweetRide = new QAction(tr("Tweet Ride"), treeWidget); - connect(actTweetRide, SIGNAL(triggered(void)), this, SLOT(tweetRide())); - - if (rideItem->isDirty() == true) { menu.addAction(actSaveRide); menu.addAction(revertRide); @@ -963,7 +959,12 @@ MainWindow::showTreeContextMenuPopup(const QPoint &pos) menu.addAction(actBestInt); menu.addAction(actPowerPeaks); menu.addAction(actSplitRide); - menu.addAction(actTweetRide); + +#ifdef GC_HAVE_LIBOAUTH + QAction *actTweetRide = new QAction(tr("Tweet Ride"), treeWidget); + connect(actTweetRide, SIGNAL(triggered(void)), this, SLOT(tweetRide())); + menu.addAction(actTweetRide); +#endif menu.exec(treeWidget->mapToGlobal( pos )); } @@ -1482,6 +1483,7 @@ MainWindow::manualProcess(QString name) } } +#ifdef GC_HAVE_LIBOAUTH void MainWindow::tweetRide() { @@ -1496,4 +1498,5 @@ MainWindow::tweetRide() twitterDialog->setWindowModality(Qt::ApplicationModal); twitterDialog->exec(); } +#endif diff --git a/src/MainWindow.h b/src/MainWindow.h index 299b01551..8bd6d7c47 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -163,7 +163,9 @@ class MainWindow : public QMainWindow void frontInterval(); void backInterval(); void intervalEdited(QTreeWidgetItem *, int); +#ifdef GC_HAVE_LIBOAUTH void tweetRide(); +#endif protected: diff --git a/src/Pages.cpp b/src/Pages.cpp index d908ede1a..157e5fa19 100644 --- a/src/Pages.cpp +++ b/src/Pages.cpp @@ -10,6 +10,8 @@ #include "ColorButton.h" #include "SpecialFields.h" +#include + ConfigurationPage::ConfigurationPage(MainWindow *main) : main(main) { QTabWidget *tabs = new QTabWidget(this); @@ -1819,29 +1821,94 @@ CPPage::zonesChanged() } } } + +#ifdef GC_HAVE_LIBOAUTH // // Twitter Config page // TwitterPage::TwitterPage(QWidget *parent) : QWidget(parent) { - boost::shared_ptr settings = GetApplicationSettings(); + settings = GetApplicationSettings(); QTabWidget *tabs = new QTabWidget(this); QWidget *twitter = new QWidget(this); tabs->addTab(twitter, tr("Twitter Config")); QHBoxLayout *twitterlayout = new QHBoxLayout(twitter); + authorizeButton = new QPushButton(tr("Authorize")); - accountLabel = new QLabel(tr("Twitter User Name"),this); - accountName = new QLineEdit(tr(""), this); + QTextEdit *twitterInstructionsEdit = new QTextEdit(this); + twitterInstructionsEdit->setReadOnly(true); + twitterInstructionsEdit->setEnabled(false); + twitterInstructionsEdit->setPlainText(tr("Click the Authorize button. Your default browser will open to Twitter. " + "Once you have authorized Golden Cheetah access your Twitter account, " + "Copy/Paste PIN number from Twitter into PIN field. Click Save")); + twitterPinLabel = new QLabel(tr("Enter PIN: "),this); + twitterPIN = new QLineEdit(tr(""), this); - passwordLabel = new QLabel(tr("Password"),this); - passwordEdit = new QLineEdit(tr(""), this); - passwordEdit->setEchoMode(QLineEdit::Password); - - twitterlayout->addWidget(accountLabel); - twitterlayout->addWidget(accountName); - twitterlayout->addWidget(passwordLabel); - twitterlayout->addWidget(passwordEdit); - - accountName->setText(settings->value(GC_TWITTER_USERNAME).toString()); - passwordEdit->setText(settings->value(GC_TWITTER_PASSWORD).toString()); + twitterlayout->addWidget(twitterInstructionsEdit); + twitterlayout->addWidget(authorizeButton); + twitterlayout->addWidget(twitterPinLabel); + twitterlayout->addWidget(twitterPIN); + connect(authorizeButton, SIGNAL(clicked()), this, SLOT(authorizeClicked())); } + +void TwitterPage::authorizeClicked() +{ + int rc; + char **rv = NULL; + QString token; + QString url = QString(); + t_key = NULL; + t_secret = NULL; + + const char *request_token_uri = "http://api.twitter.com/oauth/request_token"; + + char *req_url = NULL; + char *postarg = NULL; + char *reply = NULL; + req_url = oauth_sign_url2(request_token_uri, NULL, OA_HMAC, NULL, GC_TWITTER_CONSUMER_KEY, GC_TWITTER_CONSUMER_SECRET, NULL, NULL); + reply = oauth_http_get(req_url,postarg); + + rc = oauth_split_url_parameters(reply, &rv); + qsort(rv, rc, sizeof(char *), oauth_cmpstringp); + token = QString(rv[1]); + t_key =strdup(&(rv[1][12])); + t_secret =strdup(&(rv[2][19])); + url = QString("http://api.twitter.com/oauth/authorize?"); + url.append(token); + QDesktopServices::openUrl(QUrl(url)); + if(rv) free(rv); +} + +void TwitterPage::saveClicked() +{ + char *reply; + char *req_url; + char **rv = NULL; + char *postarg = NULL; + QString url = QString("http://api.twitter.com/oauth/access_token?a=b&oauth_verifier="); + + QString strPin = twitterPIN->text(); + if(strPin.size() == 0) + return; + + url.append(strPin); + + req_url = oauth_sign_url2(url.toLatin1(), NULL, OA_HMAC, NULL, GC_TWITTER_CONSUMER_KEY, GC_TWITTER_CONSUMER_SECRET, t_key, t_secret); + reply = oauth_http_get(req_url,postarg); + + int rc = oauth_split_url_parameters(reply, &rv); + + if(rc ==4) + { + qsort(rv, rc, sizeof(char *), oauth_cmpstringp); + + const char *oauth_token = strdup(&(rv[0][12])); + const char *oauth_secret = strdup(&(rv[1][19])); + + //Save Twitter oauth_token and oauth_secret; + settings->setValue(GC_TWITTER_TOKEN, oauth_token); + settings->setValue(GC_TWITTER_SECRET, oauth_secret); + } +} +#endif + diff --git a/src/Pages.h b/src/Pages.h index ce9e546fe..c5add58a4 100644 --- a/src/Pages.h +++ b/src/Pages.h @@ -23,6 +23,10 @@ #include "RideMetadata.h" #include "DataProcessor.h" +extern "C" { +#include +} + class QGroupBox; class QHBoxLayout; class QVBoxLayout; @@ -402,16 +406,17 @@ class TwitterPage : public QWidget public: TwitterPage(QWidget *parent = 0); - void saveClicked(); // Children talk to each other SchemePage *schemePage; CPPage *cpPage; - QLineEdit *accountName; - QLineEdit *passwordEdit; - + QLineEdit *twitterPIN; + void saveClicked(); public slots: +#ifdef GC_HAVE_LIBOAUTH + void authorizeClicked(); +#endif protected: @@ -422,8 +427,12 @@ class TwitterPage : public QWidget // local versions for modification private: - QLabel *accountLabel; - QLabel *passwordLabel; + QLabel *twitterPinLabel; + QPushButton *authorizeButton; + char *t_key; + char *t_secret; + boost::shared_ptr settings; + }; #endif diff --git a/src/Settings.h b/src/Settings.h index 8595c7201..ab7cea66a 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -61,8 +61,6 @@ #define GC_WORKOUTDIR "workoutDir" #define GC_TRAIN_SPLITTER_SIZES "trainwindow/splitterSizes" #define GC_LTM_SPLITTER_SIZES "ltmwindow/splitterSizes" -#define GC_TWITTER_USERNAME "TwitterUser" -#define GC_TWITTER_PASSWORD "TwitterPass" // device Configurations NAME/SPEC/TYPE/DEFI/DEFR all get a number appended // to them to specify which configured device i.e. devices1 ... devicesn where @@ -82,6 +80,12 @@ #define GC_DPFS_VARIANCE "dataprocess/fixspikes/variance" #define GC_DPTA "dataprocess/torqueadjust/adjustment" +//Twitter oauth keys +#define GC_TWITTER_CONSUMER_KEY "qbbmhDt8bG8ZBcT3r9nYw" //< consumer key +#define GC_TWITTER_CONSUMER_SECRET "IWXu2G6mQC5xvhM8V0ohA0mPTUOqAFutiuKIva3LQg" +#define GC_TWITTER_TOKEN "twitter_token" +#define GC_TWITTER_SECRET "twitter_secret" + #include #include diff --git a/src/TwitterDialog.cpp b/src/TwitterDialog.cpp index 72459b6ee..22b4989b7 100644 --- a/src/TwitterDialog.cpp +++ b/src/TwitterDialog.cpp @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2009 Justin F. Knotzke (jknotzke@shampoo.ca) + * + * 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 "TwitterDialog.h" #include "Settings.h" #include @@ -19,7 +37,7 @@ TwitterDialog::TwitterDialog(MainWindow *mainWindow, RideItem *item) : timeRidingChk = new QCheckBox(tr("Time Riding")); totalDistanceChk = new QCheckBox(tr("Total Distance")); elevationGainChk = new QCheckBox(tr("Elevation Gain")); - totalWorkChk = new QCheckBox(tr("Total Work (kj)")); + totalWorkChk = new QCheckBox(tr("Total Work (kJ)")); averageSpeedChk = new QCheckBox(tr("Average Speed")); averagePowerChk = new QCheckBox(tr("Average Power")); averageHRMChk = new QCheckBox(tr("Average Heart Rate")); @@ -78,26 +96,26 @@ TwitterDialog::TwitterDialog(MainWindow *mainWindow, RideItem *item) : void TwitterDialog::tweetCurrentRide() { - setEnabled(false); - QString twitterMsg = getTwitterMessage(); - QString post = "/statuses/update.xml?status="; - QString strUrl = QUrl::toPercentEncoding(twitterMsg + " #goldencheetah"); - qDebug() << post << strUrl; - QHttp *twitter_http_updater = new QHttp(); - twitter_http_updater->setHost("www.twitter.com"); - twitter_http_updater->setUser(settings->value(GC_TWITTER_USERNAME).toString(), settings->value(GC_TWITTER_PASSWORD).toString()); - twitter_http_updater->post(post+strUrl, QByteArray()); - connect(twitter_http_updater, SIGNAL(done(bool)), this, SLOT(updateTwitterStatusFinish(bool))); -} -void TwitterDialog::updateTwitterStatusFinish(bool error) -{ - if(error == true) - QMessageBox::warning(this, tr("Tweeted Ride"), tr("Tweet Not Sent")); - else - QMessageBox::information(this, tr("Tweeted Ride"), tr("Tweet Sent")); + QString strToken = settings->value(GC_TWITTER_TOKEN).toString(); + QString strSecret = settings->value(GC_TWITTER_SECRET).toString(); + + QString s_token = QString(strToken); + QString s_secret = QString(strSecret); + + char *postarg = NULL; + QString qurl = "http://api.twitter.com/1/statuses/update.json?status="; + + QString twitterMsg = getTwitterMessage(); + const QString strUrl = QUrl::toPercentEncoding(twitterMsg + " #goldencheetah"); + qurl.append(strUrl); + const char *req_url = oauth_sign_url2(qurl.toLatin1(), &postarg, OA_HMAC, NULL, GC_TWITTER_CONSUMER_KEY, GC_TWITTER_CONSUMER_SECRET, s_token.toLatin1(), s_secret.toLatin1()); + oauth_http_post(req_url,postarg); + + if(postarg) free(postarg); accept(); + } QString TwitterDialog::getTwitterMessage() @@ -127,9 +145,7 @@ QString TwitterDialog::getTwitterMessage() if(totalDistanceChk->isChecked()) { m = ride->metrics.value("total_distance"); - tmp = round(m->value(useMetricUnits)); - QString msg = QString("Total Distance: %1 " + (useMetricUnits ? tr("KM") : tr("Miles"))).arg(tmp); - qDebug() << msg; + QString msg = QString("Total Distance: %1" + (useMetricUnits ? tr("km") : tr("mi"))).arg(m->value(useMetricUnits),1,'f',1); twitterMsg.append(msg + " "); } @@ -137,7 +153,7 @@ QString TwitterDialog::getTwitterMessage() { m = ride->metrics.value("elevation_gain"); tmp = round(m->value(useMetricUnits)); - QString msg = QString("Elevation Gained: %1"+ (useMetricUnits ? tr("Meters") : tr("Feet"))).arg(tmp); + QString msg = QString("Elevation Gained: %1"+ (useMetricUnits ? tr("m") : tr("ft"))).arg(tmp); twitterMsg.append(msg + " "); } @@ -145,15 +161,14 @@ QString TwitterDialog::getTwitterMessage() { m = ride->metrics.value("total_work"); tmp = round(m->value(true)); - QString msg = QString("Total Work (kj): %1").arg(tmp); + QString msg = QString("Total Work: %1"+ tr("kJ")).arg(tmp); twitterMsg.append(msg + " "); } if(averageSpeedChk->isChecked()) { m = ride->metrics.value("average_speed"); - tmp = round(m->value(useMetricUnits)); - QString msg = QString("Average Speed: %1"+ (useMetricUnits ? tr("KM/H") : tr("MPH"))).arg(tmp); + QString msg = QString("Average Speed: %1"+ (useMetricUnits ? tr("km/h") : tr("mph"))).arg(m->value(useMetricUnits),1,'f',1); twitterMsg.append(msg + " "); } @@ -161,7 +176,7 @@ QString TwitterDialog::getTwitterMessage() { m = ride->metrics.value("average_power"); tmp = round(m->value(true)); - QString msg = QString("Average Power: %1 watts").arg(tmp); + QString msg = QString("Average Power: %1 "+ tr("watts")).arg(tmp); twitterMsg.append(msg + " "); } @@ -169,7 +184,7 @@ QString TwitterDialog::getTwitterMessage() { m = ride->metrics.value("average_hr"); tmp = round(m->value(true)); - QString msg = QString("Average Heart Rate: %1").arg(tmp); + QString msg = QString("Average Heart Rate: %1"+ tr("bpm")).arg(tmp); twitterMsg.append(msg + " "); } @@ -177,7 +192,7 @@ QString TwitterDialog::getTwitterMessage() { m = ride->metrics.value("average_cad"); tmp = round(m->value(true)); - QString msg = QString("Average Cadence: %1").arg(tmp); + QString msg = QString("Average Cadence: %1"+ tr("rpm")).arg(tmp); twitterMsg.append(msg + " "); } @@ -185,7 +200,7 @@ QString TwitterDialog::getTwitterMessage() { m = ride->metrics.value("max_power"); tmp = round(m->value(true)); - QString msg = QString("Max Power: %1 watts").arg(tmp); + QString msg = QString("Max Power: %1 "+ tr("watts")).arg(tmp); twitterMsg.append(msg + " "); } @@ -193,7 +208,7 @@ QString TwitterDialog::getTwitterMessage() { m = ride->metrics.value("max_heartrate"); tmp = round(m->value(true)); - QString msg = QString("Max Heart Rate: %1").arg(tmp); + QString msg = QString("Max Heart Rate: %1"+ tr("bpm")).arg(tmp); twitterMsg.append(msg + " "); } diff --git a/src/TwitterDialog.h b/src/TwitterDialog.h index b7f94bc9e..5473c8702 100644 --- a/src/TwitterDialog.h +++ b/src/TwitterDialog.h @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2009 Justin F. Knotzke (jknotzke@shampoo.ca) + * + * 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 + */ + #ifndef TWITTERDIALOG_H #define TWITTERDIALOG_H @@ -5,6 +23,9 @@ #include #include "MainWindow.h" #include "RideItem.h" +extern "C" { +#include +} class TwitterDialog : public QDialog { @@ -15,7 +36,6 @@ public: signals: private slots: - void updateTwitterStatusFinish(bool error); void onCheck(int state); void tweetMsgChange(QString); void tweetCurrentRide(); diff --git a/src/gcconfig.pri.in b/src/gcconfig.pri.in index 934be863e..7e1df635d 100644 --- a/src/gcconfig.pri.in +++ b/src/gcconfig.pri.in @@ -6,6 +6,16 @@ BOOST_INSTALL = /usr/local/boost SRMIO_INSTALL = /usr/local/srmio D2XX_INCLUDE = /usr/local/include/D2XX +# If you want Twitter support you must install liboauth +# http://liboauth.sourceforge.net/ +# Set the path to where liboauth.a was installed +# By default it will have been installed like this: +# +#LIBOAUTH_INSTALL = /usr/local +#LIBCRYPTO_INSTALL = -lcrypto +#LIBCURL_INSTALL=-lcurl +#LIBZ_INSTALL=-lz + # If you want 3D plotting, you need to install qwtplot3d # # http://qwtplot3d.sourceforge.net/ diff --git a/src/src.pro b/src/src.pro index 15b85502d..4278b4e69 100644 --- a/src/src.pro +++ b/src/src.pro @@ -11,6 +11,17 @@ QT += xml sql network webkit LIBS += ../qwt/lib/libqwt.a LIBS += -lm +!isEmpty( LIBOAUTH_INSTALL ) { +INCLUDEPATH += $${LIBOAUTH_INSTALL}/include +LIBS += $${LIBCRYPTO_INSTALL} +LIBS += $${LIBOAUTH_INSTALL}/lib/liboauth.a +LIBS += $${LIBZ_INSTALL} +LIBS += $${LIBCURL_INSTALL} +DEFINES += GC_HAVE_LIBOAUTH +SOURCES += TwitterDialog.cpp +HEADERS += TwitterDialog.h +} + !isEmpty( D2XX_INCLUDE ) { INCLUDEPATH += $${D2XX_INCLUDE} HEADERS += D2XX.h @@ -171,7 +182,6 @@ HEADERS += \ TrainTabs.h \ TrainTool.h \ TrainWindow.h \ - TwitterDialog.h \ Units.h \ ViewSelection.h \ WeeklySummaryWindow.h \ @@ -281,7 +291,6 @@ SOURCES += \ TrainTabs.cpp \ TrainTool.cpp \ TrainWindow.cpp \ - TwitterDialog.cpp \ ViewSelection.cpp \ WeeklySummaryWindow.cpp \ WkoRideFile.cpp \