1 #include "mainwindow.h"
2 #include "ui_mainwindow.h"
3 
4 #include "todotablemodel.h"
5 
6 #include "todotxt.h"
7 #include "settingsdialog.h"
8 #include "quickadddialog.h"
9 #include "aboutbox.h"
10 #include "globals.h"
11 #include "def.h"
12 
13 #include <QSortFilterProxyModel>
14 #include <QFileSystemWatcher>
15 #include <QTime>
16 #include <QDebug>
17 #include <QSettings>
18 #include <QShortcut>
19 #include <QCloseEvent>
20 #include <QtAwesome.h>
21 #include <QDesktopWidget>
22 #include <QDir>
23 #include <QSystemTrayIcon>
24 #include <QDesktopServices>
25 #include <QUuid>
26 
27 QNetworkAccessManager *networkaccessmanager;
28 TodoTableModel *model=NULL;
29 QString saved_selection; // Used for selection memory
30 
MainWindow(QWidget * parent)31 MainWindow::MainWindow(QWidget *parent) :
32     QMainWindow(parent),
33     ui(new Ui::MainWindow)
34 {
35 
36     ui->setupUi(this);
37     QString title=this->windowTitle();
38 
39 #ifdef QT_NO_DEBUG
40     QCoreApplication::setOrganizationName("Nerdur");
41     QCoreApplication::setOrganizationDomain("nerdur.com");
42     QCoreApplication::setApplicationName("Todour");
43     title.append("-");
44 #else
45     QCoreApplication::setOrganizationName("Nerdur-debug");
46     QCoreApplication::setOrganizationDomain("nerdur-debug.com");
47     QCoreApplication::setApplicationName("Todour-Debug");
48     title.append("-DEBUG-");
49 #endif
50 
51     title.append(VER);
52     baseTitle=title;
53     this->setWindowTitle(title);
54 
55 
56 
57     // Check if we're supposed to have the settings from .ini file or not
58     if(QCoreApplication::arguments().contains("-portable")){
59         QSettings::setDefaultFormat(QSettings::IniFormat);
60         QSettings::setPath(QSettings::IniFormat,QSettings::UserScope,QDir::currentPath());
61         qDebug()<<"Setting ini file path to: "<<QDir::currentPath()<<Qt::endl;
62     }
63 
64     hotkey = new UGlobalHotkeys();
65     setHotkey();
66 
67     // Restore the position of the window
68     auto rec = QApplication::desktop()->screenGeometry();
69     auto maxx = rec.height();
70     auto maxy = rec.width();
71     auto minx = rec.topLeft().x();
72     auto miny = rec.topLeft().y();
73 
74     QSettings settings;
75     restoreGeometry(settings.value( SETTINGS_GEOMETRY, saveGeometry() ).toByteArray());
76     restoreState(settings.value( SETTINGS_SAVESTATE, saveState() ).toByteArray());
77     auto p = settings.value(SETTINGS_POSITION, pos()).toPoint();
78 
79     if(p.x()>=maxx-100 || p.x()<minx){
80        p.setX(minx); // Set to minx for safety
81     }
82     if(p.y()>=maxy-100 || p.y()<miny ){
83         p.setY(miny); // Set to miny for safety
84     }
85     move(p);
86     resize(settings.value( SETTINGS_SIZE, size() ).toSize());
87     if ( settings.value( SETTINGS_MAXIMIZED, isMaximized() ).toBool() )
88         showMaximized();
89 
90     ui->lineEdit_2->setText(settings.value(SETTINGS_SEARCH_STRING,DEFAULT_SEARCH_STRING).toString());
91 
92     // Check that we have an UUID for this application (used for undo for example)
93     if(!settings.contains(SETTINGS_UUID)){
94         settings.setValue(SETTINGS_UUID,QUuid::createUuid().toString());
95     }
96 
97     // Fix some font-awesome stuff
98     QtAwesome* awesome = new QtAwesome(qApp);
99     awesome->initFontAwesome();     // This line is important as it loads the font and initializes the named icon map
100     awesome->setDefaultOption("scale-factor",0.9);
101     ui->btn_Alphabetical->setIcon(awesome->icon( fa::sortalphaasc ));
102     ui->pushButton_3->setIcon(awesome->icon( fa::signout ));
103     ui->pushButton_4->setIcon(awesome->icon( fa::refresh ));
104     ui->pushButton->setIcon(awesome->icon( fa::plus ));
105     ui->pushButton_2->setIcon(awesome->icon( fa::minus ));
106     ui->context_lock->setIcon(awesome->icon(fa::lock));
107     ui->pb_closeVersionBar->setIcon(awesome->icon(fa::times));
108 
109     // Set some defaults if they dont exist
110     if(!settings.contains(SETTINGS_LIVE_SEARCH)){
111         settings.setValue(SETTINGS_LIVE_SEARCH,DEFAULT_LIVE_SEARCH);
112     }
113 
114     // Started. Lets open the todo.txt file, parse it and show it.
115     parse_todotxt();
116     setFileWatch();
117     networkaccessmanager = new QNetworkAccessManager(this);
118 
119 
120     // Set up shortcuts . Mac translates the Ctrl -> Cmd
121     // http://doc.qt.io/qt-5/qshortcut.html
122     auto editshortcut = new QShortcut(QKeySequence(tr("Ctrl+n")),this);
123     QObject::connect(editshortcut,SIGNAL(activated()),ui->lineEdit,SLOT(setFocus()));
124     auto findshortcut = new QShortcut(QKeySequence(tr("Ctrl+f")),this);
125     QObject::connect(findshortcut,SIGNAL(activated()),ui->lineEdit_2,SLOT(setFocus()));
126     //auto contextshortcut = new QShortcut(QKeySequence(tr("Ctrl+l")),this);
127     //QObject::connect(contextshortcut,SIGNAL(activated()),ui->context_lock,SLOT(setChecked(!(ui->context_lock->isChecked()))));
128     QObject::connect(model,SIGNAL(dataChanged (const QModelIndex , const QModelIndex )),this,SLOT(dataInModelChanged(QModelIndex,QModelIndex)));
129 
130     /*
131     These should now be handled in the menu system
132     auto undoshortcut = new QShortcut(QKeySequence(tr("Ctrl+z")),this);
133     QObject::connect(undoshortcut,SIGNAL(activated()),this,SLOT(undo()));
134     auto redoshortcut = new QShortcut(QKeySequence(tr("Ctrl+r")),this);
135     QObject::connect(redoshortcut,SIGNAL(activated()),this,SLOT(redo()));*/
136 
137 
138     // Do this late as it triggers action using data
139     ui->btn_Alphabetical->setChecked(settings.value(SETTINGS_SORT_ALPHA).toBool());
140     ui->context_lock->setChecked(settings.value(SETTINGS_CONTEXT_LOCK,DEFAULT_CONTEXT_LOCK).toBool());
141     updateSearchResults(); // Since we may have set a value in the search window
142 
143     ui->lv_activetags->hide(); //  Not being used yet
144     ui->newVersionView->hide(); // This defaults to not being shown
145     ui->actionShow_All->setChecked(settings.value(SETTINGS_SHOW_ALL,DEFAULT_SHOW_ALL).toBool());
146     ui->actionStay_On_Top->setChecked(settings.value(SETTINGS_STAY_ON_TOP,DEFAULT_STAY_ON_TOP).toBool());
147     ui->cb_threshold_inactive->setChecked(settings.value(SETTINGS_THRESHOLD_INACTIVE,DEFAULT_THRESHOLD_INACTIVE).toBool());
148     stayOnTop();
149     setTray();
150     setFontSize();
151 
152     // Version check
153     if(settings.value(SETTINGS_CHECK_UPDATES,DEFAULT_CHECK_UPDATES).toBool()){
154         QString last_check = settings.value(SETTINGS_LAST_UPDATE_CHECK,"").toString();
155         if(last_check.isEmpty()){
156             // We set this up so that first check will be later, giving users ample time to turn off the feature.
157             last_check = QDate::currentDate().toString("yyyy-MM-dd");
158             settings.setValue(SETTINGS_LAST_UPDATE_CHECK,last_check);
159 
160         }
161         QDate lastCheck = QDate::fromString(last_check,"yyyy-MM-dd");
162         QDate nextCheck = lastCheck.addDays(7);
163 
164         qDebug()<<"Last update check date: "<<last_check<<" and next is "<<nextCheck.toString("yyyy-MM-dd")<<Qt::endl;
165         int daysToNextcheck = QDate::currentDate().daysTo(nextCheck);
166         if(daysToNextcheck<0){
167             QString URL = VERSION_URL;
168             requestPage(URL);
169         }
170     }
171 
172 }
173 
174 
175 
176 // This method is for making sure we're re-selecting the item that has been edited
dataInModelChanged(QModelIndex i1,QModelIndex i2)177 void MainWindow::dataInModelChanged(QModelIndex i1,QModelIndex i2){
178     Q_UNUSED(i2);
179     //qDebug()<<"Data in Model changed emitted:"<<i1.data(Qt::UserRole)<<"::"<<i2.data(Qt::UserRole)<<endl;
180     //qDebug()<<"Changed:R="<<i1.row()<<":C="<<i1.column()<<endl;
181     saved_selection = i1.data(Qt::UserRole).toString();
182     resetTableSelection();
183     updateTitle();
184 
185 }
186 
187 
~MainWindow()188 MainWindow::~MainWindow()
189 {
190     delete ui;
191     delete networkaccessmanager;
192     delete model;
193 }
194 
195 QSortFilterProxyModel *proxyModel=NULL;
196 
197 QFileSystemWatcher *watcher;
198 
updateTitle()199 void MainWindow::updateTitle(){
200     // The title is initialized to the name and version number at start and that is stored in baseTitle
201 
202     if(proxyModel != NULL){
203         int visible = proxyModel->rowCount();
204         int total = proxyModel->sourceModel()->rowCount();
205 
206         this->setWindowTitle(baseTitle+" ("+QString::number(visible)+"/"+QString::number(total)+")");
207     }
208 
209     // Check the undo and redo meny items
210     ui->actionUndo->setEnabled(model->undoPossible());
211     ui->actionRedo->setEnabled(model->redoPossible());
212 
213 }
214 
215 
216 // A simple delay function I pulled of the 'net.. Need to delay reading a file a little bit.. A second seems to be enough
217 // really don't like this though as I have no idea of knowing when a second is enough.
218 // Having more than one second will impact usability of the application as it changes the focus.
delay()219 void delay()
220 {
221     QTime dieTime= QTime::currentTime().addSecs(1);
222     while( QTime::currentTime() < dieTime )
223     QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
224 }
225 
226 
227 
fileModified(const QString & str)228 void MainWindow::fileModified(const QString &str){
229     Q_UNUSED(str);
230     //qDebug()<<"MainWindow::fileModified  "<<watcher->files()<<" --- "<<str;
231     saveTableSelection();
232     model->refresh();
233     if(model->count()==0){
234         // This sometimes happens when the file is being updated. We have gotten the signal a bit soon so the file is still empty. Wait and try again
235         delay();
236         model->refresh();
237         updateTitle();
238     }
239     resetTableSelection();
240     setFileWatch();
241 }
242 
clearFileWatch()243 void MainWindow::clearFileWatch(){
244     if(watcher != NULL){
245         delete watcher;
246         watcher = NULL;
247     }
248 }
249 
setFileWatch()250 void MainWindow::setFileWatch(){
251     QSettings settings;
252     if(settings.value(SETTINGS_AUTOREFRESH).toBool()==false)
253            return;
254 
255     clearFileWatch();
256 
257     watcher = new QFileSystemWatcher();
258     //qDebug()<<"Mainwindow::setFileWatch :: "<<watcher->files();
259     watcher->removePaths(watcher->files()); // Make sure this is empty. Should only be this file we're using in this program, and only one instance
260     watcher->addPath(model->getTodoFile());
261     QObject::connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(fileModified(QString)));
262 }
263 
264 
265 
parse_todotxt()266 void MainWindow::parse_todotxt(){
267 
268     model = new TodoTableModel(this);
269     proxyModel = new QSortFilterProxyModel(this);
270     proxyModel->setSourceModel(model);
271     proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
272     ui->tableView->setModel(proxyModel);
273     //ui->tableView->resizeColumnsToContents();
274     //ui->tableView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
275     ui->tableView->horizontalHeader()->setSectionResizeMode(1,QHeaderView::Stretch);
276     ui->tableView->resizeColumnToContents(0); // Checkboxes kept small
277     //ui->tableView->resizeRowsToContents(); Om denna körs senare blir det riktigt bra, men inte här..
278 }
279 
on_lineEdit_2_textEdited(const QString & arg1)280 void MainWindow::on_lineEdit_2_textEdited(const QString &arg1)
281 {
282     Q_UNUSED(arg1);
283     QSettings settings;
284 
285     bool liveUpdate = settings.value(SETTINGS_LIVE_SEARCH).toBool();
286     if(!ui->actionShow_All->isChecked() && liveUpdate){
287         updateSearchResults();
288     }
289 }
290 
updateSearchResults()291 void MainWindow::updateSearchResults(){
292     // Take the text of the format of match1 match2 !match3 and turn it into
293     //(?=.*match1)(?=.*match2)(?!.*match3) - all escaped of course
294     QSettings settings;
295     QChar search_not_char = settings.value(SETTINGS_SEARCH_NOT_CHAR,DEFAULT_SEARCH_NOT_CHAR).toChar();
296     QStringList words = ui->lineEdit_2->text().split(QRegularExpression("\\s+"));
297     QString regexpstring="(?=^.*$)"; // Seems a negative lookahead can't be first (!?), so this is a workaround
298     for(QString word:words){
299         QString start = "(?=^.*";
300         if(word.length()>0 && word.at(0)==search_not_char){
301             start = "(?!^.*";
302             word = word.remove(0,1);
303         }
304         if(word.length()==0) break;
305         regexpstring += start+QRegExp::escape(word)+".*$)";
306     }
307     QRegExp regexp(regexpstring,Qt::CaseInsensitive);
308     proxyModel->setFilterRegExp(regexp);
309     //qDebug()<<"Setting filter: "<<regexp.pattern();
310     proxyModel->setFilterKeyColumn(1);
311     updateTitle();
312 }
313 
on_lineEdit_2_returnPressed()314 void MainWindow::on_lineEdit_2_returnPressed()
315 {
316     QSettings settings;
317     bool liveUpdate = settings.value(SETTINGS_LIVE_SEARCH).toBool();
318 
319     if(!liveUpdate || ui->actionShow_All->isChecked()){
320         updateSearchResults();
321     }
322 
323 }
324 
on_hotkey()325 void MainWindow::on_hotkey(){
326     auto dlg = new QuickAddDialog();
327     dlg->setModal(true);
328     dlg->show();
329     dlg->exec();
330     if(dlg->accepted){
331         this->addTodo(dlg->text);
332     }
333 }
334 
setHotkey()335 void MainWindow::setHotkey(){
336     QSettings settings;
337     if(settings.value(SETTINGS_HOTKEY_ENABLE).toBool()){
338         hotkey->registerHotkey(settings.value(SETTINGS_HOTKEY,DEFAULT_HOTKEY).toString());
339         connect(hotkey,&UGlobalHotkeys::activated,[=](size_t id){
340             Q_UNUSED(id);
341             on_hotkey();
342         });
343     } else {
344         hotkey->unregisterAllHotkeys();
345     }
346 }
347 
on_actionAbout_triggered()348 void MainWindow::on_actionAbout_triggered(){
349     AboutBox d;
350     d.setModal(true);
351     d.show();
352     d.exec();
353     //myanalytics->check_update();
354 }
355 
on_actionSettings_triggered()356 void MainWindow::on_actionSettings_triggered()
357 {
358     SettingsDialog d;
359     d.setModal(true);
360     d.show();
361     d.exec();
362     if(d.refresh){
363         delete model;
364         model = new TodoTableModel(this);
365         proxyModel->setSourceModel(model);
366         ui->tableView->setModel(proxyModel);
367         ui->tableView->horizontalHeader()->setSectionResizeMode(1,QHeaderView::Stretch);
368         ui->tableView->resizeColumnToContents(0);
369         saveTableSelection();
370         model->refresh();// Not 100% sure why this is needed.. Should be done by re-setting the model above
371         resetTableSelection();
372         setFileWatch();
373         setTray();
374         setFontSize();
375     }
376 }
377 
setFontSize()378 void MainWindow::setFontSize(){
379     QSettings settings;
380     int size = settings.value(SETTINGS_FONT_SIZE).toInt();
381     if(size >0){
382         auto f = qApp->font();
383         f.setPointSize(size);
384         qApp->setFont(f);
385     }
386 }
387 
stayOnTop()388 void MainWindow::stayOnTop()
389 {
390     if(ui->actionStay_On_Top->isChecked()){
391         setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
392     } else {
393         setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
394     }
395     show(); // This is needed as setWindowFlags can hide the window
396 }
397 
setTray()398 void MainWindow::setTray(){
399     QSettings settings;
400     if(settings.value(SETTINGS_TRAY_ENABLED,DEFAULT_TRAY_ENABLED).toBool()){
401         // We should be showing a tray icon. Are we?
402         if(trayicon==NULL){
403             trayicon = new QSystemTrayIcon(this);
404             traymenu = new QMenu(this);
405             minimizeAction = new QAction(tr("Mi&nimize"), this);
406             connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
407             maximizeAction = new QAction(tr("Ma&ximize"), this);
408             connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
409             restoreAction = new QAction(tr("&Restore"), this);
410             connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
411             quitAction = new QAction(tr("&Quit"), this);
412             connect(quitAction, SIGNAL(triggered()), this, SLOT(cleanup()));
413             connect(QApplication::instance(),SIGNAL(aboutToQuit()),this,SLOT(cleanup()));
414 
415             traymenu->addAction(minimizeAction);
416             traymenu->addAction(maximizeAction);
417             traymenu->addAction(restoreAction);
418             traymenu->addSeparator();
419             traymenu->addAction(quitAction);
420             trayicon->setContextMenu(traymenu);
421             connect(trayicon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
422                         this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
423 
424             trayicon->setIcon(QIcon(":/icons/newicon.png"));
425         }
426         trayicon->show();
427     }
428     else{
429         if(trayicon!=NULL){
430             trayicon->hide();
431         }
432     }
433 }
434 
iconActivated(QSystemTrayIcon::ActivationReason reason)435 void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
436 {
437     switch (reason) {
438     case QSystemTrayIcon::Trigger:
439     case QSystemTrayIcon::DoubleClick:
440             // Make sure the window is open
441             this->show();
442         break;
443     case QSystemTrayIcon::MiddleClick:
444         // Do nothing
445         break;
446     default:
447         ;
448     }
449 }
450 
on_pushButton_clicked()451 void MainWindow::on_pushButton_clicked()
452 {
453     // Adding a new value into the model
454    QString txt = ui->lineEdit->text();
455    addTodo(txt);
456    ui->lineEdit->clear();
457 }
458 
addTodo(QString & s)459 void MainWindow::addTodo(QString &s){
460 
461     if(ui->context_lock->isChecked()){
462         // The line should have the context of the search field except any negative search
463         QStringList contexts = ui->lineEdit_2->text().split(QRegExp("\\s"));
464         for(QString context:contexts){
465          if(context.length()>0 && context.at(0)=='!') continue; // ignore this one
466          if(!s.contains(context,Qt::CaseInsensitive)){
467              s.append(" "+context);
468          }
469         }
470     }
471     model->add(s);
472     updateTitle();
473 }
474 
on_lineEdit_returnPressed()475 void MainWindow::on_lineEdit_returnPressed()
476 {
477     on_pushButton_clicked();
478 }
479 
on_pushButton_2_clicked()480 void MainWindow::on_pushButton_2_clicked()
481 {
482     // Remove the selected item
483     QModelIndexList indexes = ui->tableView->selectionModel()->selection().indexes();
484     // Only support for deleting one item at a time
485     if(!indexes.empty()){
486         QModelIndex i=indexes.at(0);
487         QString t=model->data(proxyModel->mapToSource(i),Qt::UserRole).toString(); // User Role is Raw data
488         //QString t=proxyModel->data(i).toString();
489         model->remove(t);
490     }
491     updateTitle();
492 }
493 
on_pushButton_3_clicked()494 void MainWindow::on_pushButton_3_clicked()
495 {
496     // Archive
497     saveTableSelection();
498     model->archive();
499     resetTableSelection();
500     updateTitle();
501 }
502 
on_pushButton_4_clicked()503 void MainWindow::on_pushButton_4_clicked()
504 {
505     saveTableSelection();
506     model->refresh();
507     resetTableSelection();
508     updateTitle();
509 }
510 
511 
512 
saveTableSelection()513 void MainWindow::saveTableSelection(){
514     //auto index = ui->tableView->selectionModel()->selectedIndexes();
515     auto index = ui->tableView->selectionModel()->currentIndex();
516 //    if(index.count()>0){
517     if(index.isValid()){
518         // Vi har någonting valt.
519         // qDebug()<<"Selected index: "<<index.at(0)<<endl;
520         //saved_selection = model->data(index.at(0),Qt::UserRole).toString();
521         saved_selection = model->data(index,Qt::UserRole).toString();
522         //qDebug()<<"Selected text: "<<saved_selection<<endl;
523 
524     }
525 }
526 
resetTableSelection()527 void MainWindow::resetTableSelection(){
528     if(saved_selection.size()>0){
529         // Set the selection again
530         QModelIndexList foundIndexes = model->match(QModelIndex(),Qt::UserRole,saved_selection);
531         if(foundIndexes.count()>0){
532             //qDebug()<<"Found at index: "<<foundIndexes.at(0)<<endl;
533             ui->tableView->setFocus(Qt::OtherFocusReason);
534             ui->tableView->selectionModel()->select(foundIndexes.at(0),QItemSelectionModel::Select);
535             ui->tableView->selectionModel()->setCurrentIndex(foundIndexes.at(0),QItemSelectionModel::ClearAndSelect);
536             //ui->tableView->setCurrentIndex(foundIndexes.at(0));
537        }
538     }
539     saved_selection="";
540 
541 }
542 
cleanup()543 void MainWindow::cleanup(){
544     QSettings settings;
545 
546     settings.setValue( SETTINGS_GEOMETRY, saveGeometry() );
547     settings.setValue( SETTINGS_SAVESTATE, saveState() );
548     settings.setValue( SETTINGS_MAXIMIZED, isMaximized() );
549     if ( !isMaximized() ) {
550         settings.setValue( SETTINGS_POSITION, pos() );
551         settings.setValue( SETTINGS_SIZE, size() );
552     }
553     settings.setValue(SETTINGS_SEARCH_STRING,ui->lineEdit_2->text());
554     if(trayicon!=NULL){
555         delete trayicon;
556         trayicon = NULL;
557     }
558     qApp->quit();
559 }
560 
closeEvent(QCloseEvent * ev)561 void MainWindow::closeEvent(QCloseEvent *ev){
562 
563     if (trayicon != NULL && trayicon->isVisible()) {
564             hide();
565             ev->ignore();
566     } else {
567         cleanup();
568         ev->accept();
569     }
570 
571 }
572 
on_btn_Alphabetical_toggled(bool checked)573 void MainWindow::on_btn_Alphabetical_toggled(bool checked)
574 {
575     QSettings settings;
576     settings.setValue(SETTINGS_SORT_ALPHA,checked);
577     on_pushButton_4_clicked(); // Refresh
578 }
579 
on_context_lock_toggled(bool checked)580 void MainWindow::on_context_lock_toggled(bool checked)
581 {
582     QSettings settings;
583     settings.setValue(SETTINGS_CONTEXT_LOCK,checked);
584 }
585 
586 
on_cb_threshold_inactive_stateChanged(int arg1)587 void MainWindow::on_cb_threshold_inactive_stateChanged(int arg1)
588 {
589     QSettings settings;
590     settings.setValue(SETTINGS_THRESHOLD_INACTIVE,arg1);
591     on_pushButton_4_clicked();
592 }
593 
on_pb_closeVersionBar_clicked()594 void MainWindow::on_pb_closeVersionBar_clicked()
595 {
596     ui->newVersionView->hide();
597 }
598 
599 bool forced_check_version=false;
requestReceived(QNetworkReply * reply)600 void MainWindow::requestReceived(QNetworkReply* reply){
601     QString replyText;
602     QSettings settings;
603     if(reply->error()==QNetworkReply::NoError){
604 
605         // Get the http status code
606         int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
607         if (v >= 200 && v < 300) // Success
608         {
609             replyText = reply->readAll();
610             double latest_version = replyText.toDouble();
611             double this_version = QString(VER).toDouble();
612             qDebug()<<"Checked version - Latest: "<<latest_version<<" this version "<<this_version<<Qt::endl;
613             if(latest_version>this_version || forced_check_version){
614                 if(latest_version >= this_version){
615                     ui->lbl_latestVersion->hide();
616                 } else {
617                     ui->lbl_newVersion->hide();
618                 }
619                 ui->txtLatestVersion->setText("(v"+QString::number(latest_version,'f',2)+")");
620                 ui->newVersionView->show();
621                 forced_check_version=false;
622             }
623             // Update the last checked since we were successful
624             settings.setValue(SETTINGS_LAST_UPDATE_CHECK,QDate::currentDate().toString("yyyy-MM-dd"));
625         }
626     }
627     reply->deleteLater();
628 }
629 
undo()630 void MainWindow::undo()
631 {
632     if(model->undo()){
633         model->refresh();
634     }
635 }
636 
redo()637 void MainWindow::redo()
638 {
639     if(model->redo()){
640         model->refresh();
641     }
642 
643 }
644 
645 // Check if there is an update available
requestPage(QString & s)646 void MainWindow::requestPage(QString &s){
647     connect(networkaccessmanager,SIGNAL(finished(QNetworkReply*)),this,SLOT(requestReceived(QNetworkReply*)));
648     networkaccessmanager->get(QNetworkRequest(QUrl(s)));
649 
650 }
651 
652 
on_actionCheck_for_updates_triggered()653 void MainWindow::on_actionCheck_for_updates_triggered()
654 {
655     forced_check_version=true;
656     QString URL = VERSION_URL+(QString)"?v="+VER;
657     requestPage(URL);
658 
659 }
660 
on_tableView_customContextMenuRequested(const QPoint & pos)661 void MainWindow::on_tableView_customContextMenuRequested(const QPoint &pos)
662 {
663     // This is used for triggering opening of a link.
664     // Find out where we are
665     auto index = ui->tableView->indexAt(pos);
666     QString URL=ui->tableView->model()->data(index,Qt::UserRole+1).toString();
667     if(!URL.isEmpty()){
668         QDesktopServices::openUrl(URL);
669     }
670 
671 }
672 
on_actionQuit_triggered()673 void MainWindow::on_actionQuit_triggered()
674 {
675     cleanup();
676 }
677 
on_actionUndo_triggered()678 void MainWindow::on_actionUndo_triggered()
679 {
680     undo();
681     updateTitle();
682 }
683 
on_actionRedo_triggered()684 void MainWindow::on_actionRedo_triggered()
685 {
686     redo();
687     updateTitle();
688 }
689 
on_actionShow_All_changed()690 void MainWindow::on_actionShow_All_changed()
691 {
692     QSettings settings;
693     settings.setValue(SETTINGS_SHOW_ALL,ui->actionShow_All->isChecked());
694     on_pushButton_4_clicked();
695 }
696 
on_actionStay_On_Top_changed()697 void MainWindow::on_actionStay_On_Top_changed()
698 {
699     QSettings settings;
700     settings.setValue(SETTINGS_STAY_ON_TOP,ui->actionStay_On_Top->isChecked());
701     stayOnTop();
702 }
703