OSDN Git Service

Merge remote-tracking branch 'origin/master'
[memma/Source.git] / widget.cpp
1 /**
2  * CommandoJikkyouSennyou - Commando Jikkyou Sennyou Client for twitter for Qt.
3  *
4  * Author: amayav (vamayav@yahoo.co.jp)
5  *
6  *
7  *  CommandoJikkyouSennyou is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  CommandoJikkyouSennyou is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with CommandoJikkyouSennyou.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 #include "widget.h"
21 #include "ui_widget.h"
22 #include <QTextCodec>
23 #include <QDebug>
24 #include <QKeyEvent>
25 #include "extrapushbutton.h"
26 #include <cmath>
27 #include <QLayoutItem>
28 #include <QDateTime>
29 #include "picojson.h"
30 #include <QSslConfiguration>
31 #include <QSslCertificate>
32 #include <QDirIterator>
33
34 using namespace std;
35 using namespace picojson;
36
37 #define LATEST_NUMBER_FOR_TIME 128
38
39 //QString _consumerKey("nXrjGagSLIQxCC4AmJ1J3g");
40 //QString _consumerSecretKey("QkTRr36zT6wAMERWqKUefyshxXIeaGzPKxB5pwMN0tg");
41 /*
42   publidc functions
43   */
44 Widget::Widget(QWidget *parent)
45     : QWidget(parent),
46       ui(new Ui::Widget),
47       _oauthManager(new KQOAuthManager(parent)),
48       _oauthRequest(new KQOAuthRequest),
49       _oauthSettings(new QSettings(qApp->applicationDirPath() + "/verification.ini",
50                                    QSettings::IniFormat)),
51       _shortCutKeysSettings(new QSettings(qApp->applicationDirPath() + "/key.txt",
52                                           QSettings::IniFormat)),
53       _sizeSettings(new QSettings(qApp->applicationDirPath() + "/size.ini",
54                                   QSettings::IniFormat)),
55       _proxy(new QNetworkProxy()),
56       _consumerKey(),
57       _consumerSecretKey(),
58       _clockCountTimer(new QTimer),
59       _latestTweetsForTime(),
60       _subject(new WidgetDomain)
61 {
62     QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf-8"));
63     QTextCodec::setCodecForTr(QTextCodec::codecForName("utf-8"));
64     QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));
65
66     ui->setupUi(this);
67     this->setPostShortcutKeys();
68     this->setJikkyouShortcutKeys();
69     this->setWindowSize();
70     this->setProxyLineEdits();
71     this->setConsumerKeyAndConsumerSecretLineEdits();
72     this->setConsumerKeyAndConsumerSecret();
73
74     // OAuth Settings
75     _oauthSettings->setIniCodec("utf-8");
76     if (_oauthSettings->childKeys().size() == 3) { //number, consumer_key, consumer_secret_key
77         ui->lineEdit->setText(_oauthSettings->value("number").toString());
78     }
79
80     this->initializeKQOAuth();
81     this->initializeOwnPostsWidgets();
82     this->updateData();
83
84     _clockCountTimer->setInterval(1000);
85     _clockCountTimer->start();
86     connect(_clockCountTimer, SIGNAL(timeout()), this, SLOT(countDownClock()), Qt::UniqueConnection);
87 }
88
89 Widget::~Widget() {
90     delete _oauthManager;
91     delete _oauthRequest;
92     delete _oauthSettings;
93     delete _shortCutKeysSettings;
94     delete _sizeSettings;
95     delete _proxy;
96     delete _clockCountTimer;
97     delete _subject;
98     delete ui;
99 }
100
101 bool Widget::initializeKQOAuth(){
102     _oauthManager->setNetworkManager(new QNetworkAccessManager);
103     connect(_oauthManager->networkManager(), SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
104             this, SLOT(receiveSSLError(QNetworkReply*,QList<QSslError>)), Qt::UniqueConnection);
105     _oauthRequest->setEnableDebugOutput(false);
106     return true;
107 }
108
109 bool Widget::setPostShortcutKeys(){
110     // Short Cut Key for Post.
111     QList<QShortcut*> postShortCutList;
112     postShortCutList << new QShortcut(ui->lineEdit_2)
113                      << new QShortcut(ui->lineEdit_3)
114                      << new QShortcut(ui->lineEdit_4)
115                      << new QShortcut(ui->lineEdit_5)
116                      << new QShortcut(ui->lineEdit_6);
117     for(QList<QShortcut*>::const_iterator it = postShortCutList.begin();it != postShortCutList.end();++it){
118         this->setShortCutKeyAndContext(*it,
119                                        QKeySequence(Qt::CTRL + Qt::Key_Return),
120                                        Qt::WidgetShortcut);
121         connect(*it, SIGNAL(activated()), ui->postButton, SLOT(click()));
122     }
123     return true;
124 }
125
126 bool Widget::setJikkyouShortcutKeys(){
127     _shortCutKeysSettings->setIniCodec("utf-8");
128     ExtraPushButton *button;
129     for(int i=0;i<_shortCutKeysSettings->childKeys().size();++i){
130         _subject->getKeysHash()->insert(_shortCutKeysSettings->childKeys().at(i),
131                                         _shortCutKeysSettings->value(_shortCutKeysSettings->childKeys().at(i)).toString());
132         button = new ExtraPushButton(_shortCutKeysSettings->childKeys().at(i),
133                                      _shortCutKeysSettings->value(_shortCutKeysSettings->childKeys().at(i)).toString(),
134                                      this);
135         button->setToolTip(_shortCutKeysSettings->value(_shortCutKeysSettings->childKeys().at(i)).toString());
136         ui->buttonsGridLayout->addWidget(button,0,i);
137         // Succession of slots can not go well.
138         connect(button, SIGNAL(clicked()), button, SLOT(click()));
139         connect(button, SIGNAL(clicked(QString)), this, SLOT(sendTweet(QString)));
140         connect(button, SIGNAL(showingToolTip(QString)), ui->plainTextEdit, SLOT(setPlainText(QString)));
141     }
142     return true;
143 }
144
145 bool Widget::setWindowSize(){
146     _sizeSettings->beginGroup("size");
147     if(_sizeSettings->value("width").isNull())
148         resize(200,200);
149     else
150         resize(_sizeSettings->value("width").toInt(), _sizeSettings->value("height").toInt());
151     _sizeSettings->endGroup();
152     return true;
153 }
154
155 bool Widget::setProxyLineEdits(){
156     _sizeSettings->beginGroup("proxy");
157     if(_sizeSettings->value("hostName").isNull()){
158         _sizeSettings->endGroup();
159         return false;
160     }
161     _proxy->setHostName(_sizeSettings->value("hostName").toString());
162     _proxy->setPort(_sizeSettings->value("port").toInt());
163     _proxy->setUser(_sizeSettings->value("user").toString());
164     _proxy->setPassword(_sizeSettings->value("password").toString());
165     ui->proxyHostNameLineEdit->setText(_sizeSettings->value("hostName").toString());
166     ui->proxyPortLineEdit->setText(_sizeSettings->value("port").toString());
167     ui->proxyUserLineEdit->setText(_sizeSettings->value("user").toString());
168     ui->proxyPasswordLineEdit->setText(_sizeSettings->value("password").toString());
169     _sizeSettings->endGroup();
170     return true;
171 }
172
173 bool Widget::setConsumerKeyAndConsumerSecretLineEdits(){
174     _sizeSettings->beginGroup("consumerKey");
175     if(_sizeSettings->value("consumerKey").isNull()){
176         _sizeSettings->endGroup();
177         return false;
178     }
179     ui->consumerKeyLineEdit->setText(_sizeSettings->value("consumerKey").toString());
180     ui->consumerSecretKeyLineEdit->setText(_sizeSettings->value("consumerSecretKey").toString());
181     _sizeSettings->endGroup();
182     return true;
183 }
184
185 bool Widget::setConsumerKeyAndConsumerSecret(){
186     _consumerKey = ui->consumerKeyLineEdit->text();
187     _consumerSecretKey = ui->consumerSecretKeyLineEdit->text();
188     return true;
189 }
190
191 bool Widget::SSLconnect(KQOAuthRequest *request)
192 {
193     try{
194         _oauthRequest = request;
195         QNetworkRequest networkRequest;
196         networkRequest.setUrl( _oauthRequest->requestEndpoint() );
197         QSslConfiguration sslcon;
198         sslcon.setCaCertificates(QSslCertificate::fromPath("./veri\\.cer",
199                                                            QSsl::Pem,
200                                                            QRegExp::RegExp));
201         if(sslcon.caCertificates().size()==0){
202             throw "There is not verification file \"veri.cer\".";
203         }
204         networkRequest.setSslConfiguration(sslcon);
205
206         //_oauthRequest->setCallbackUrl(QUrl("oob"));
207
208         networkRequest.setRawHeader("Authorization", makeAuthHeaderFrom(_oauthRequest->requestParameters()));
209
210         connect(_oauthManager->networkManager(), SIGNAL(finished(QNetworkReply *)),
211                 _oauthManager, SLOT(onRequestReplyReceived(QNetworkReply *)), Qt::UniqueConnection);
212
213         if (_oauthRequest->httpMethod() == KQOAuthRequest::GET) {
214             // Get the requested additional params as a list of pairs we can give QUrl
215             QList< QPair<QString, QString> > urlParams;
216             for(int i=0; i<_oauthRequest->additionalParameters().keys().size(); i++) {
217                 urlParams.append( qMakePair(_oauthRequest->additionalParameters().keys().at(i),
218                                             _oauthRequest->additionalParameters().values().at(i)) );
219             }
220
221             // Take the original URL and append the query params to it.
222             QUrl urlWithParams = networkRequest.url();
223             urlWithParams.setQueryItems(urlParams);
224             networkRequest.setUrl(urlWithParams);
225
226             // Submit the request including the params.
227             //_replyOfUserStreamsAPI = _oauthManager->networkManager()->get(networkRequest);
228             _subject->setReplyOfUserStreamsAPI(_oauthManager->networkManager()->get(networkRequest));
229             connect(_subject->getReplyOfUserStreamsAPI(), SIGNAL(readyRead()),
230                     this, SLOT(onReadyRead()), Qt::UniqueConnection);
231             connect(_subject->getReplyOfUserStreamsAPI(), SIGNAL(error(QNetworkReply::NetworkError)),
232                     _oauthManager, SLOT(slotError(QNetworkReply::NetworkError)), Qt::UniqueConnection);
233             return true;
234         } else if (_oauthRequest->httpMethod() == KQOAuthRequest::POST) {
235             networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, _oauthRequest->contentType());
236
237             qDebug() << networkRequest.rawHeaderList();
238             qDebug() << networkRequest.rawHeader("Authorization");
239             qDebug() << networkRequest.rawHeader("Content-Type");
240
241             QNetworkReply *reply;
242             if (_oauthRequest->contentType() == "application/x-www-form-urlencoded") {
243                 reply = _oauthManager->networkManager()->post(networkRequest, _oauthRequest->requestBody());
244             } else {
245                 reply = _oauthManager->networkManager()->post(networkRequest, _oauthRequest->rawData());
246             }
247
248             connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
249                     this, SLOT(slotError(QNetworkReply::NetworkError)), Qt::UniqueConnection);
250             return true;
251         }
252         qDebug() << "Unexpected HTTP Method.";
253         return false;
254     }catch(QString str){
255         qDebug() << "error" << str;
256         return false;
257     }
258 }
259
260 void Widget::onReadyRead()
261 {
262     if( this->isOAuthed() == false) {
263         qDebug() << "There are not oauth_token or oauth_token_secret";
264         return;
265     }
266     onRequestReadyTimeline(_subject->getReplyOfUserStreamsAPI()->readAll());
267 }
268
269 void Widget::receiveSSLError(QNetworkReply *reply, const QList<QSslError> &errors)
270 {
271     for(int i=0;i<errors.size();++i) {
272         qDebug() << errors.at(i);
273     }
274 }
275
276 bool Widget::setShortCutKeyAndContext(QShortcut *sc, QKeySequence s, Qt::ShortcutContext c)
277 {
278     sc->setKey(s);
279     sc->setContext(c);
280     return true;
281 }
282
283 bool Widget::initializeRequest(QUrl url,
284                                KQOAuthRequest::RequestHttpMethod requestMethod,
285                                KQOAuthRequest::RequestType requestType)
286 {
287     _oauthRequest->initRequest(requestType, url);
288     _oauthRequest->setHttpMethod(requestMethod);
289     _oauthRequest->setConsumerKey(_consumerKey);
290     _oauthRequest->setConsumerSecretKey(_consumerSecretKey);
291     return true;
292 }
293
294 bool Widget::setTokenAndSecretTokenToRequest()
295 {
296     _oauthRequest->setToken(_oauthSettings->value("oauth_token").toString());
297     _oauthRequest->setTokenSecret(
298                 _oauthSettings->value("oauth_token_secret").toString());
299     return true;
300 }
301
302 bool Widget::initializeOwnPostsWidgets()
303 {
304     if( this->isOAuthed() == false){
305         qDebug() << "Not Verified Yet.";
306         return false;
307     }
308
309     qDebug("Initializing Own Posts");
310     initializeRequest(QUrl("http://api.twitter.com/1/statuses/user_timeline.json"),
311                       KQOAuthRequest::GET);
312     setTokenAndSecretTokenToRequest();
313     KQOAuthParameters params;
314     params.insert("count", QByteArray::number(LATEST_NUMBER_FOR_TIME).constData());
315     _oauthRequest->setAdditionalParameters(params);
316
317     disconnect(_oauthManager, SIGNAL(requestReady(QByteArray)), 0, 0);
318
319     // I cannot understand why this connection is invalid.
320     connect(_oauthManager, SIGNAL(requestReady(QByteArray)),
321             this, SLOT(onRequestReadyOwnPosts(QByteArray)), Qt::UniqueConnection);
322
323     _oauthManager->executeRequest(_oauthRequest);
324
325     connect(_oauthManager->networkManager(), SIGNAL(finished(QNetworkReply*)),
326             this, SLOT(on_showTimeLineButton_clicked()), Qt::UniqueConnection);
327
328     connect(_oauthManager->networkManager(), SIGNAL(finished(QNetworkReply*)),
329             this, SLOT(readOwnPosts(QNetworkReply*)), Qt::UniqueConnection);
330     return true;
331 }
332
333 void Widget::readOwnPosts(QNetworkReply *r)
334 {
335     onRequestReadyOwnPosts(r->readAll());
336 }
337
338 QByteArray Widget::makeAuthHeaderFrom(QList<QByteArray> requestParameters)
339 {
340     bool first = true;
341     QByteArray result;
342     foreach (const QByteArray header, requestParameters) {
343         if (!first) {
344             result.append(", ");
345         } else {
346             result.append("OAuth ");
347             first = false;
348         }
349         result.append(header);
350     }
351     return result;
352 }
353
354 bool Widget::isOAuthed()
355 {
356     return _oauthSettings->value("oauth_token").toString().size()
357             + _oauthSettings->value("oauth_token_secret").toString().size() > 0;
358 }
359
360 QString Widget::getValueOfMatchedKey()
361 {
362     QStringList list(_subject->getKeysHash()->keys());
363     unsigned int check = 0;
364     for(int i=0;i<list.size();++i){
365         if(list.at(i).startsWith(_subject->getKeyString()))
366             ++check;
367         if(check==2){
368             qDebug() << "There are too many candities.";
369             return "";
370         }
371     }
372     if(check==0){
373         qDebug() << "There is not such a short cut key.";
374         return "";
375     }
376     return _subject->getKeysHash()->value(_subject->getKeyString());
377 }
378
379 WidgetDomain* Widget::getWidgetDomain()
380 {
381     return _subject;
382 }
383
384 void Widget::countDownClock(){
385     if(ui->tableWidget_2->rowCount() < LATEST_NUMBER_FOR_TIME)
386         return;
387     if(_latestTweetsForTime.getPostedDateTimeList().size() == 0)
388         return;
389     for(int i=0; i < ui->tableWidget_2->rowCount(); ++i){
390         //latest number for time
391         if(ui->tableWidget_2->item(i, 0) == NULL)
392             break;
393
394         QDateTime postedTime = _latestTweetsForTime.getPostedDateTimeList().at(i);
395         QDateTime fromNow = QDateTime::currentDateTime();
396         fromNow = fromNow.addYears(-postedTime.date().year());
397         fromNow = fromNow.addMonths(-postedTime.date().month());
398         fromNow = fromNow.addDays(-postedTime.date().day());
399         fromNow = fromNow.addSecs(-postedTime.time().hour()*60*60
400                                   -postedTime.time().minute()*60
401                                   -postedTime.time().second()
402                                   );
403         ui->tableWidget_2->setItem(
404                     LATEST_NUMBER_FOR_TIME - i - 1 , 1, new QTableWidgetItem(
405                         ( (postedTime.secsTo(QDateTime::currentDateTime()) > 60*60*24)
406                           ? (
407                                 QString::number(postedTime.secsTo(QDateTime::currentDateTime())/(60*60*24))
408                                 + (
409                                     (postedTime.secsTo(QDateTime::currentDateTime())/(60*60*24) == 1)
410                                     ? ( QString("day +") )
411                                     : ( QString("days +") )
412                                       )
413                                 )
414                           : QString("")
415                             )
416                         + fromNow.toString("hh:mm:ss")
417                         )
418                     );
419         if(postedTime.secsTo(QDateTime::currentDateTime()) <= 60*60*3){
420             for(int j=0;j<ui->tableWidget_2->columnCount();++j){
421                 if(ui->tableWidget_2->item(LATEST_NUMBER_FOR_TIME - i - 1,j)==NULL)
422                     continue;
423                 ui->tableWidget_2->item(LATEST_NUMBER_FOR_TIME - i - 1,j)->setBackground(QBrush(QColor(255, 0, 0), Qt::SolidPattern));
424             }
425         }
426     }
427 }
428
429 void Widget::updateData()
430 {
431 }
432
433 bool Widget::setConsumerKeyAndConsumerSecretSettings(){
434     _sizeSettings->beginGroup("consumerKey");
435     _sizeSettings->setValue("consumerKey", ui->consumerKeyLineEdit->text());
436     _sizeSettings->setValue("consumerSecretKey", ui->consumerSecretKeyLineEdit->text());
437     _sizeSettings->endGroup();
438     return true;
439 }
440
441 /*
442   protected functions
443   */
444 void Widget::keyPressEvent(QKeyEvent *keyEvent)
445 {
446     if(keyEvent->isAutoRepeat()
447             || (keyEvent->modifiers()!=Qt::ControlModifier)
448             || (keyEvent->key()==Qt::Key_Control) )
449         return;
450     setAttribute(Qt::WA_KeyCompression);
451     /*
452           0x00:^@
453           0x00-0x1a:^A-^Z
454           0x1b:^[
455           0x1c:^\
456           0x1d:^]
457           0x1e:^
458           0x1f:^_
459
460           0x40:@
461           0x41-0x4a:A-Z
462           ...
463         */
464     QString key = (keyEvent->text().toAscii().toHex().toInt(0, 16) <= 31)
465             ? QByteArray::fromHex(QByteArray::number(keyEvent->text().toAscii().toHex().toInt(0, 16) + 64, 16))
466             : keyEvent->text();
467     _subject->setKeyString(_subject->getKeyString() + key.toLower());
468     qDebug() << "Pressed Keys :" << keyEvent->text() << _subject->getKeyString() << keyEvent->count();
469
470     for(int i=0;i<ui->buttonsGridLayout->count();++i){
471         if(dynamic_cast<ExtraPushButton*>(ui->buttonsGridLayout->itemAt(i)->widget())->getShortCutKey().indexOf(_subject->getKeyString())==0){
472             continue;
473         }
474         ui->buttonsGridLayout->itemAt(i)->widget()->setEnabled(false);
475     }
476 }
477
478 void Widget::keyReleaseEvent(QKeyEvent *keyEvent)
479 {
480     if(keyEvent->isAutoRepeat()
481             ||  keyEvent->key()!=Qt::Key_Control
482             || _subject->getKeyString().size()==0 )
483         return;
484     qDebug() << "ctrl!" << _subject->getKeyString();
485     QString tweet = getValueOfMatchedKey();
486     // Exception of Exchanging Strings
487     if(tweet.contains(QRegExp("\\(\\d.*\\)"))){
488         ui->plainTextEdit->setPlainText(tweet);
489         for(int i=0;i<ui->buttonsGridLayout->count();++i)
490             if(ui->buttonsGridLayout->itemAt(i)->widget()->isEnabled()==true)
491                 ui->buttonsGridLayout->itemAt(i)->widget()->setEnabled(false);
492         ui->lineEdit_2->setFocus();
493     }else{
494         // Enable All Buttons
495         for(int i=0;i<ui->buttonsGridLayout->count();++i)
496             if(ui->buttonsGridLayout->itemAt(i)->widget()->isEnabled()==false)
497                 ui->buttonsGridLayout->itemAt(i)->widget()->setEnabled(true);
498         sendTweet(tweet);
499     }
500     _subject->setKeyString("");
501     tweet.clear();
502 }
503
504 void Widget::resizeEvent(QResizeEvent *)
505 {
506     _sizeSettings->beginGroup("size");
507     _sizeSettings->setValue("width", width());
508     _sizeSettings->setValue("height", height());
509     _sizeSettings->endGroup();
510     //replace buttons.
511     int beforeColumnsNumber =0;
512     for(int i=ui->buttonsGridLayout->columnCount()-1;i>=0;--i)
513     {
514         if(ui->buttonsGridLayout->itemAtPosition(0,i)!=NULL)
515         {
516             beforeColumnsNumber = i+1;
517             break;
518         }
519     }
520     if(beforeColumnsNumber==0) {
521         return;
522     }
523
524     QRect r;
525     for(int i=beforeColumnsNumber-1;i>=0;--i){
526         if(ui->buttonsGridLayout->itemAtPosition(0, i)!=NULL){
527             r = ui->buttonsGridLayout->itemAtPosition(0, i)->widget()->frameGeometry();
528             break;
529         }
530     }
531
532     // When widget size becomes too small.
533     if(r.x()+r.width() > ui->groupBox->frameGeometry().x()+ui->groupBox->frameGeometry().width()){
534         int afterColumnsNumber = 0;
535         for(int i=beforeColumnsNumber-1;i>=0;--i){
536             r = ui->buttonsGridLayout->itemAtPosition(0,i)->widget()->frameGeometry();
537             if(r.x()+r.width()
538                     < ui->groupBox->frameGeometry().x()+ui->groupBox->frameGeometry().width()){
539                 afterColumnsNumber = i+1;
540                 break;
541             }
542         }
543         if(afterColumnsNumber==0) {
544             return;
545         }
546         QList<QLayoutItem*> *list = new QList<QLayoutItem*>();
547         while(ui->buttonsGridLayout->itemAt(0)!=NULL){
548             list->append(ui->buttonsGridLayout->itemAt(0)); // There are only extraPushButtons.
549             ui->buttonsGridLayout->removeItem(ui->buttonsGridLayout->itemAt(0));
550         }
551         for(int i=0;i<list->size();++i){
552             ui->buttonsGridLayout->addItem(list->at(i),
553                                            floor((double)i/(double)afterColumnsNumber),
554                                            i%afterColumnsNumber);
555         }
556     }
557     // When widget size becomes too big
558     else if(r.x() + r.width() + ui->buttonsGridLayout->horizontalSpacing() + r.width()
559             < ui->groupBox->x() + ui->groupBox->frameGeometry().width()){
560         int afterColumnsNumber = 0;
561         for(int i=1;i<200;++i){
562             if(r.x()+r.width() + i*(ui->buttonsGridLayout->horizontalSpacing() + ui->buttonsGridLayout->itemAt(0)->widget()->width())
563                     > ui->groupBox->frameGeometry().x()+ui->groupBox->frameGeometry().width()){
564                 afterColumnsNumber = beforeColumnsNumber+i;
565                 break;
566             }
567         }
568         if(afterColumnsNumber > ui->buttonsGridLayout->count() || afterColumnsNumber==0){
569             return;
570         }
571         QList<QLayoutItem*> *list = new QList<QLayoutItem*>();
572         while(ui->buttonsGridLayout->itemAt(0)!=NULL){
573             list->append(ui->buttonsGridLayout->itemAt(0)); // There are only extraPushButtons.
574             ui->buttonsGridLayout->removeItem(ui->buttonsGridLayout->itemAt(0));
575         }
576         for(int i=0;i<list->size();++i){
577             ui->buttonsGridLayout->addItem(list->at(i),
578                                            floor((double)i/(double)afterColumnsNumber),
579                                            i%afterColumnsNumber);
580         }
581     }
582 }
583
584 void Widget::showEvent(QShowEvent *)
585 {
586     // Here is for use of resizeEvent() when program is going to start.
587     resize(size()-QSize(1,0));
588     resize(size()+QSize(1,0));
589 }
590
591 /*
592   private slots
593   */
594 void Widget::onTemporaryTokenReceived(QString token, QString tokenSecret)
595 {
596     if( _oauthManager->lastError() != KQOAuthManager::NoError) {
597         return;
598     }
599     qDebug() << "Opening authorization web site: " << QUrl("https://api.twitter.com/oauth/authorize");
600     _oauthManager->getUserAuthorization(QUrl("https://api.twitter.com/oauth/authorize"));
601 }
602
603 void Widget::onAuthorizationReceived(QString token, QString verifier)
604 {
605     qDebug() << "User authorization received: " << token << verifier;
606
607     _oauthManager->getUserAccessTokens(QUrl(tr("https://api.twitter.com/oauth/access_token")));
608     if (_oauthManager->lastError() != KQOAuthManager::NoError) {
609         showOAuthError(_oauthManager->lastError());
610         //QCoreApplication::exit();
611     }
612 }
613
614 void Widget::onAccessTokenReceived(QString token, QString tokenSecret)
615 {
616     qDebug() << "Access token received: " << token << tokenSecret;
617
618     _oauthSettings->setValue(tr("oauth_token"), token);
619     _oauthSettings->setValue(tr("oauth_token_secret"), tokenSecret);
620
621     qDebug() << "Access tokens now stored. "
622                 "You are ready to send Tweets from user's account!";
623
624     this->initializeOwnPostsWidgets();
625     //QCoreApplication::exit();
626 }
627
628 void Widget::onAuthorizedRequestDone() {
629     qDebug() << "Request sent to Twitter!";
630     //QCoreApplication::exit(0);
631 }
632
633 void Widget::onRequestReady(QByteArray response)
634 {
635     if(response.size()<=0){
636         showOAuthError(_oauthManager->lastError());
637         return;
638     }
639     qDebug() << "Response from the service: " << response;
640 }
641
642 void Widget::on_authorizationButton_clicked() {
643     qDebug() << "Attempting new consumer key and consumer secret.";
644
645     _subject->getReplyOfUserStreamsAPI()->disconnect(this);
646     _subject->getReplyOfUserStreamsAPI()->disconnect(SIGNAL(error(QNetworkReply::NetworkError)));
647
648     this->setConsumerKeyAndConsumerSecretSettings();
649     this->setConsumerKeyAndConsumerSecret();
650     ui->lineEdit->clear();
651     _oauthSettings->clear();
652     ui->lineEdit->setEnabled(true);
653     ui->verificationButton->setEnabled(true);
654
655     delete _oauthManager;
656     _oauthManager = new KQOAuthManager();
657     this->initializeKQOAuth();
658     this->initializeOwnPostsWidgets();
659
660     // kQOAuth Slots
661     connect(_oauthManager, SIGNAL(temporaryTokenReceived(QString,QString)),
662             this, SLOT(onTemporaryTokenReceived(QString, QString)), Qt::UniqueConnection);
663
664     connect(_oauthManager, SIGNAL(authorizationReceived(QString,QString)),
665             this, SLOT(onAuthorizationReceived(QString, QString)), Qt::UniqueConnection);
666
667     connect(_oauthManager, SIGNAL(accessTokenReceived(QString,QString)),
668             this, SLOT(onAccessTokenReceived(QString,QString)), Qt::UniqueConnection);
669
670     connect(_oauthManager, SIGNAL(requestReady(QByteArray)),
671             this, SLOT(onRequestReady(QByteArray)), Qt::UniqueConnection);
672
673     // Start OAuth Verification.
674     this->initializeRequest(QUrl("https://api.twitter.com/oauth/request_token"),
675                             KQOAuthRequest::POST,
676                             KQOAuthRequest::TemporaryCredentials);
677
678     _oauthManager->setHandleUserAuthorization(true);
679     //_oauthManager->setHandleUserAuthorization(false);
680
681     _oauthManager->executeRequest(_oauthRequest);
682
683     // Checking Error
684     if (_oauthManager->lastError() != KQOAuthManager::NoError) {
685         qDebug("authorization error");
686         showOAuthError(_oauthManager->lastError());
687     }
688 }
689
690 void Widget::on_showTimeLineButton_clicked() {
691     disconnect(_oauthManager->networkManager(), SIGNAL(finished(QNetworkReply*)),
692                this, SLOT(on_showTimeLineButton_clicked()));
693
694     if( this->isOAuthed() == false){
695         qDebug() << "Not Verified Yet.";
696         return;
697     }
698     qDebug("Attempting reading TimeLine.");
699
700     ui->listWidget->clear();
701
702     //QUrl("https://api.twitter.com/1/statuses/home_timeline.json");
703     initializeRequest(QUrl("https://userstream.twitter.com/2/user.json"),
704                       KQOAuthRequest::GET);
705     setTokenAndSecretTokenToRequest();
706
707     connect(_oauthManager, SIGNAL(requestReady(QByteArray)),
708             this, SLOT(onRequestReadyTimeline(QByteArray)), Qt::UniqueConnection);
709
710     //    connect(_oauthManager, SIGNAL(authorizedRequestDone()),
711     //            this, SLOT(onAuthorizedRequestDone()));
712
713     //_oauthManager->executeRequest(_oauthRequest);
714     this->SSLconnect(_oauthRequest);
715
716     if (_oauthManager->lastError() != KQOAuthManager::NoError) {
717         qDebug("Showing timeline error.");
718         showOAuthError(_oauthManager->lastError());
719     }
720 }
721
722 void Widget::onRequestReadyTimeline(QByteArray response) {
723     qDebug("Reading TimeLine");
724     // For JSON
725     qDebug("This is JSON format.");
726     if(response.startsWith("{\"friends\":[")) { // User Streams
727         response = QString(response).remove(QRegExp("(\\{\"friends\":\\[[\\d,]+\\]\\}|\\r|\\n)")).toUtf8();
728     }
729     value value;
730     string error;
731     parse(value, response.data(), response.data() + response.size(), &error);
732     if (!error.empty()){
733         cerr << error << endl;
734         return;
735     }
736     object jsonObject;
737     if(value.to_str() == string("array")){
738         array jsonArray = value.get<array>();
739         array::iterator it;
740         ui->listWidget->clear();
741         for (it = jsonArray.begin(); it != jsonArray.end(); ++it)
742         {
743             jsonObject = it->get<object>();
744             qDebug() << QString::fromStdString(jsonObject["text"].to_str());
745             if(!QString::fromStdString(jsonObject["text"].to_str()).contains("#commando")){
746                 ui->listWidget->addItem(QString::fromStdString(jsonObject["text"].to_str()));
747             }
748         }
749     }
750     else if(value.to_str() == string("object")){
751         jsonObject = value.get<object>();
752         qDebug() << QString::fromStdString(jsonObject["text"].to_str());
753         if(QString::fromStdString(jsonObject["text"].to_str()).contains("#commando")){
754             ui->listWidget->addItem(QString::fromStdString(jsonObject["text"].to_str()));
755         }
756     }
757     ui->listWidget->scrollToBottom();
758     /*
759             qDebug() <<
760                         ["contributors"] <<
761                         "\n" <<
762                         ["coordinates"] <<
763                         "\n" <<
764                         ["created_at"].toString() <<
765                         "\n" <<
766                         ["geo"]<<
767                         "\n" <<
768                         ["id"].toLongLong() <<
769                         "\n" <<
770                         ["id_str"].toString() <<
771                         "\n" <<
772                         ["in_reply_to_screen_name"] <<
773                         "\n" <<
774                         ["in_reply_to_status_id"]<<
775                         "\n" <<
776                         ["in_reply_to_status_id"] <<
777                         "\n" <<
778                         ["in_reply_to_user_id"] <<
779                         "\n" <<
780                         ["in_reply_to_user_id_str"] <<
781                         "\n" <<
782                         ["place"] <<
783                         "\n" <<
784                         ["possibly_sensitive"].toBool() <<
785                         "\n" <<
786                         ["retweet_count"].toULongLong() <<
787                         "\n" <<
788                         ["retweeted"].toBool() <<
789                         "\n" <<
790                         ["text"].toString() <<
791                         "\n" <<
792                         ["truncated"].toBool() <<
793                         "\n" <<
794                         ["user"]["contributors_enabled"].toBool() <<
795                         "\n" <<
796                         ["user"]["created_at"].toString() <<
797                         "\n" <<
798                         ["user"]["default_profile"].toBool() <<
799                         "\n" <<
800                         ["user"]["default_profile_image"].toBool() <<
801                         "\n" <<
802                         ["user"]["description"].toString() <<
803                         "\n" <<
804                         ["user"]["favourites_count"].toULongLong() <<
805                         "\n" <<
806                         ["user"]["followers_count"].toULongLong() <<
807                         "\n" <<
808                         ["user"]["following"].toBool() <<
809                         "\n" <<
810                         ["user"]["friends_count"].toULongLong() <<
811                         "\n" <<
812                         ["user"]["geo_enabled"].toBool() <<
813                         "\n" <<
814                         ["user"]["id"].toULongLong() <<
815                         "\n" <<
816                         ["user"]["id_str"].toString() <<
817                         "\n" <<
818                         ["user"]["is_translator"].toBool() <<
819                         "\n" <<
820                         ["user"]["lang"].toString() <<
821                         "\n" <<
822                         ["user"]["listed_count"].toULongLong() <<
823                         "\n" <<
824                         ["user"]["location"].toString() <<
825                         "\n" <<
826                         ["user"]["profile_background_color"].toString() <<
827                         "\n" <<
828                         ["user"]["profile_background_image_url"].toString() <<
829                         "\n" <<
830                         ["user"]["profile_background_image_url_https"].toString() <<
831                         "\n" <<
832                         ["user"]["profile_background_tile"].toBool() <<
833                         "\n" <<
834                         ["user"]["profile_image_url_https"].toString() <<
835                         "\n" <<
836                         ["user"]["profile_sidebar_border_color"].toString() <<
837                         "\n" <<
838                         ["user"]["profile_sidebar_fill_color"].toString() <<
839                         "\n" <<
840                         ["user"]["profile_text_color"].toString() <<
841                         "\n" <<
842                         ["user"]["profile_use_background_image"].toString() <<
843                         "\n" <<
844                         ["user"]["protected"].toBool() <<
845                         "\n" <<
846                         ["user"]["screen_name"].toBool() <<
847                         "\n" <<
848                         ["user"]["show_all_inline_media"].toString() <<
849                         "\n" <<
850                         ["user"]["statuses_count"].toULongLong() <<
851                         "\n" <<
852                         ["user"]["time_zone"].toString() <<
853                         "\n" <<
854                         ["user"]["url"].toString() <<
855                         "\n" <<
856                         ["user"]["utc_offset"].toULongLong() <<
857                         "\n" <<
858                         ["user"]["verified"].toBool() <<
859                         "\n\n";
860 */
861 }
862
863 void Widget::onRequestReadyOwnPosts(QByteArray response) {
864     qDebug() << "Request ready own posts";
865     // For JSON
866     qDebug("This is JSON format.");
867     value valueA;
868     string error;
869     parse(valueA, response.data(), response.data() + response.size(), &error);
870     if (!error.empty()){
871         qDebug() << response;
872         cerr << error << endl;
873         return;
874     }
875     object jsonObject;
876     if(valueA.to_str() == string("array")){
877         int tweetNumberBeforeNow=0;
878         QHash<QString, int> monthsHash;
879         monthsHash.insert("Jan", 1);
880         monthsHash.insert("Feb", 2);
881         monthsHash.insert("Mar", 3);
882         monthsHash.insert("Apr", 4);
883         monthsHash.insert("May", 5);
884         monthsHash.insert("Jun", 6);
885         monthsHash.insert("Jul", 7);
886         monthsHash.insert("Aug", 8);
887         monthsHash.insert("Sep", 9);
888         monthsHash.insert("Oct", 10);
889         monthsHash.insert("Nov", 11);
890         monthsHash.insert("Dec", 12);
891
892         for(array::iterator it = valueA.get<array>().begin(); it != valueA.get<array>().end(); ++it){
893             jsonObject = it->get<object>();
894             //latest 130
895             // When latest 127 posts are in 3 hours, a new post is forbidden.
896             // as "Sat Feb 25 15:55:23 +0000 2012"
897             QStringList dateTimeElements = QString::fromStdString(jsonObject["created_at"].to_str()).split(" ");
898             QStringList timeElements = dateTimeElements.at(3).split(":");
899             QDateTime postedDateTime = QDateTime(QDate(dateTimeElements.at(5).toInt(),
900                                                        monthsHash.value(dateTimeElements.at(1)),
901                                                        dateTimeElements.at(2).toInt()
902                                                        ),
903                                                  QTime(timeElements.at(0).toInt(),
904                                                        timeElements.at(1).toInt(),
905                                                        timeElements.at(2).toInt()
906                                                        ),
907                                                  Qt::UTC
908                                                  ).toTimeSpec(Qt::LocalTime);
909             _latestTweetsForTime.appendPostedDateTimeList(postedDateTime);
910
911             ui->tableWidget_2->setItem(
912                         LATEST_NUMBER_FOR_TIME - tweetNumberBeforeNow - 1, 0,
913                         new QTableWidgetItem(
914                             postedDateTime.toString("dd,  hh:mm:ss")
915                             )
916                         );
917
918             //latest 10
919             if(tweetNumberBeforeNow<10){
920                 ui->tableWidget->setItem(10-tweetNumberBeforeNow-1, 0, new QTableWidgetItem(QString::fromStdString(jsonObject["text"].to_str()))); //posted contents
921             }
922             ++tweetNumberBeforeNow;
923         }
924     }
925     else if(valueA.to_str() == string("object")){
926         jsonObject = valueA.get<object>();
927         qDebug() << QString::fromStdString(jsonObject["text"].to_str());
928         if(QString::fromStdString(jsonObject["text"].to_str()).contains("#commando")){
929             ui->listWidget->addItem(QString::fromStdString(jsonObject["text"].to_str()));
930         }
931     }
932 }
933
934 void Widget::sendTweet(QString tweet) {
935
936     if( this->isOAuthed() == false) {
937         qDebug() << "No access tokens. Aborting.";
938         return;
939     }
940     if(tweet.size()==0)
941     {
942         qDebug() << "There are no characters.";
943         return;
944     }
945
946     tweet.replace(QRegExp("\\(\\d+:([^()]+)\\)"), "\\1");
947     tweet.append(" #commando");
948
949     initializeRequest(QUrl("https://api.twitter.com/1/statuses/update.xml"));
950     setTokenAndSecretTokenToRequest();
951     KQOAuthParameters params;
952     params.insert("status", tweet);
953     _oauthRequest->setAdditionalParameters(params);
954
955     disconnect(_oauthManager, SIGNAL(requestReady(QByteArray)),0,0);
956
957     qDebug() << "Attempting send tweet such as " << tweet;
958     _oauthManager->executeRequest(_oauthRequest);
959
960     ui->tableWidget->removeRow(0);
961     ui->tableWidget->setRowCount(ui->tableWidget->rowCount()+1);
962     ui->tableWidget->setItem(9,0,new QTableWidgetItem(tweet));
963
964     ui->tableWidget_2->removeRow(0);
965     ui->tableWidget_2->setRowCount(ui->tableWidget_2->rowCount()+1);
966     ui->tableWidget_2->setItem(129,0, new QTableWidgetItem( (QDateTime::currentDateTime().toString("dd hh:mm:ss"))));
967     //    connect(_oauthManager, SIGNAL(authorizedRequestReady()),
968     //         this, SLOT(onAuthorizedRequestReady()));
969
970     // LineEdits must clear contents.
971     ui->lineEdit_2->clear();
972     ui->lineEdit_3->clear();
973     ui->lineEdit_4->clear();
974     ui->lineEdit_5->clear();
975     ui->lineEdit_6->clear();
976 }
977
978 void Widget::showOAuthError(const int nErrNum)
979 {
980     qDebug() << "error is " << nErrNum;
981 }
982
983 void Widget::on_verificationButton_clicked()
984 {
985     ui->lineEdit->setEnabled(false);
986     ui->verificationButton->setEnabled(false);
987     _oauthSettings->setValue("number", ui->lineEdit->text());
988     _oauthManager->onVerificationReceived1(_oauthSettings->value("number").toString());
989 }
990
991 void Widget::on_postButton_clicked()
992 {
993     QString tweet = ui->plainTextEdit->toPlainText();
994     sendTweet(tweet);
995 }
996
997 void Widget::on_lineEdit_2_textChanged(const QString &arg1)
998 {
999     replacePlainTextEditContent(1, arg1);
1000 }
1001
1002 void Widget::on_lineEdit_3_textChanged(const QString &arg1)
1003 {
1004     replacePlainTextEditContent(1, arg1);
1005 }
1006
1007 void Widget::on_lineEdit_4_textChanged(const QString &arg1)
1008 {
1009     replacePlainTextEditContent(1, arg1);
1010 }
1011
1012 void Widget::on_lineEdit_5_textChanged(const QString &arg1)
1013 {
1014     replacePlainTextEditContent(1, arg1);
1015 }
1016
1017 void Widget::on_lineEdit_6_textChanged(const QString &arg1)
1018 {
1019     replacePlainTextEditContent(1, arg1);
1020 }
1021
1022 bool Widget::replacePlainTextEditContent(int i, QString str)
1023 {
1024     if(str.length()>0)
1025     {
1026         QString text = ui->plainTextEdit->toPlainText();
1027         text.replace(QRegExp("(\\(" + QString::number(i) + ":)[^()]+(\\))"), "\\1" + str + "\\2");
1028         ui->plainTextEdit->setPlainText(text);
1029     }
1030     return true;
1031 }
1032
1033 bool Widget::SetButtonsEnable(bool on)
1034 {
1035     for(int i=0;i<ui->buttonsGridLayout->count();++i)
1036     {
1037         if(ui->buttonsGridLayout->itemAt(i)->widget()->isEnabled()== (!on))
1038         {
1039             ui->buttonsGridLayout->itemAt(i)->widget()->setEnabled(on);
1040         }
1041     }
1042     return true;
1043 }
1044
1045 void Widget::on_proxyButton_clicked()
1046 {
1047     _proxy->setHostName(ui->proxyHostNameLineEdit->text());
1048     _proxy->setPort(ui->proxyPortLineEdit->text().toInt());
1049     _proxy->setUser(ui->proxyUserLineEdit->text());
1050     _proxy->setUser(ui->proxyPasswordLineEdit->text());
1051
1052     _sizeSettings->beginGroup("proxy");
1053     _sizeSettings->setValue("hostName", ui->proxyHostNameLineEdit->text());
1054     _sizeSettings->setValue("port", ui->proxyPortLineEdit->text());
1055     _sizeSettings->setValue("user", ui->proxyUserLineEdit->text());
1056     _sizeSettings->setValue("password", ui->proxyPasswordLineEdit->text());
1057     _sizeSettings->endGroup();
1058 }