1 /*
2  * Copyright 2015-2021 The Regents of the University of California
3  * All rights reserved.
4  *
5  * This file is part of Spoofer.
6  *
7  * Spoofer is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU 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  * Spoofer 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 General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Spoofer.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <QMainWindow>
22 #include <QPlainTextEdit>
23 #include <QTimer>
24 #include "SpooferUI.h"
25 
26 // forward declarations
27 QT_BEGIN_NAMESPACE
28 class QFileSystemWatcher;
29 class QWidget;
30 class QLabel;
31 class QTableWidget;
32 class QFrame;
33 class QVBoxLayout;
34 class QMessageBox;
35 class QAbstractButton;
36 QT_END_NAMESPACE
37 template<class T> class TableRow;
38 class ProgressRow;
39 class SessionResults;
40 class RunResults;
41 class ActionButton;
42 class PreferencesDialog;
43 
44 class MainWindow Q_DECL_FINAL : public QMainWindow, public SpooferUI {
45     Q_OBJECT
46 
47     friend class RunResults;
48 
49     MainWindow(const MainWindow&) NO_METHOD; // no copy-ctor
50     MainWindow operator=(const MainWindow&) NO_METHOD; // no copy-assign
51 
52     class WindowOutput : public QIODevice {
53 	QPlainTextEdit *_textedit;
54 	QTextCursor *_cursor;
55 	int overwritableStart; // position of beginning of overwritable text
56 	WindowOutput(const WindowOutput&) NO_METHOD; // no copy-ctor
57 	WindowOutput operator=(const WindowOutput&) NO_METHOD; // no copy-assign
58     public:
WindowOutput(QPlainTextEdit * textedit)59 	WindowOutput(QPlainTextEdit *textedit) :
60 	    QIODevice(), _textedit(textedit),
61 	    _cursor(new QTextCursor(textedit->textCursor())),
62 	    overwritableStart(-1)
63 	    {}
setLogCharFmt(QtMsgType type)64 	QTextCharFormat setLogCharFmt(QtMsgType type) {
65 	    QTextCharFormat oldFmt = _cursor->charFormat();
66 	    QTextCharFormat newFmt = oldFmt;
67 	    newFmt.setForeground(QBrush(
68 		(type == QtDebugMsg)    ? Qt::darkBlue :
69 		(type == QtWarningMsg)  ? Qt::darkMagenta :
70 		(type == QtCriticalMsg) ? Qt::darkRed :
71 		(type == QtFatalMsg)    ? Qt::darkRed :
72 		Qt::darkBlue));
73 	    _cursor->setCharFormat(newFmt);
74 	    return oldFmt;
75 	}
setProberCharFmt()76 	QTextCharFormat setProberCharFmt() {
77 	    QTextCharFormat oldFmt = _cursor->charFormat();
78 	    QTextCharFormat newFmt = oldFmt;
79 	    QFont font(QSL("Courier"), oldFmt.font().pointSize());
80 	    font.setStyleHint(QFont::TypeWriter);
81 	    newFmt.setFont(font);
82 	    newFmt.setForeground(QBrush(Qt::darkGreen));
83 	    _cursor->setCharFormat(newFmt);
84 	    return oldFmt;
85 	}
setCharFmt(const QTextCharFormat & fmt)86 	void setCharFmt(const QTextCharFormat &fmt) { _cursor->setCharFormat(fmt); }
87     protected:
readData(char * data,qint64 maxSize)88 	qint64 readData(char *data, qint64 maxSize) Q_DECL_OVERRIDE
89 	    { Q_UNUSED(data); Q_UNUSED(maxSize); return -1; }
90 	qint64 writeData(const char *data, qint64 maxSize) Q_DECL_OVERRIDE;
91     };
92 
93 public:
94     static void logHandler(QtMsgType type, const QMessageLogContext &ctx,
95 	const QString &msg);
instance()96     static MainWindow *instance() { return theInstance; }
97     static QString mainTitle;
98 
99     MainWindow(QWidget *parent = nullptr);
100     void init();
101     QStringList additionalArgs() Q_DECL_OVERRIDE;
102 private slots:
103     void initEvents();
104     bool opAllowed(const Config::MemberBase &cfgItem);
105     void openPreferences();
106     void closePreferences();
107     void help();
108     void about();
109     void runProber();
110     void abortProber();
111     void pauseScheduler();
112     void resumeScheduler();
113     void shutdownScheduler();
114     void schedConnected();
115     void schedError();
readScheduler()116     void readScheduler() { SpooferUI::readScheduler(); showStatus(); }
117     void schedDisconnected();
118     void handleProberText(QString *text);
119     bool finishProber() Q_DECL_OVERRIDE;
120     void reconnectScheduler();
121     void setCountdownLabel();
122     void hideBlankTests(bool checked);
123 #ifdef AUTOUPGRADE_ENABLED
124     void showUpgradeTimer();
125     void doUpgrade();
126     void cancelUpgrade();
127 #endif
128     void toggleUpgradeDetails(const QString &link);
129     void handleHistoryColumnClick(int logicalIndex);
130 private:
131     static MainWindow *theInstance;
132     static WindowOutput *winout;
133     QFileSystemWatcher *schedWatcher;
134     QTimer countdownTimer;
135     QVBoxLayout *centralLayout;
136     QLabel *proberInfoLabel;
137     QLabel *proberCountdownLabel;
138     QLabel *schedulerStatusLabel;
139     QVBoxLayout *proberBoxLayout;
140     int firstProberMsgIdx;
141     int nextProberMsgIdx;
142     TableRow<QLabel> *proberTimeRow;
143     ProgressRow *progRow4;
144     ProgressRow *progRow6;
145     RunResults *currentRun;
146     QAction *aboutAct;
147     QAction *exitAct;
148     QAction *runAct;
149     QAction *abortAct;
150     QAction *pauseAct;
151     QAction *resumeAct;
152     QAction *shutdownAct;
153     QAction *hideGuiAct;
154     QAction *showGuiAct;
155     ActionButton *runButton;
156     ActionButton *pauseButton;
157     static QPlainTextEdit *consoleWidget;
158     static ActionButton *consoleButton;
159     QTableWidget *historyWidget;
160     PreferencesDialog *prefDialog;
161     QFrame *upgradeBox;
162     QLabel *upgradeNotice;
163     QLabel *upgradeDetails;
164     QLabel *upgradeAutoNotice;
165 #ifdef AUTOUPGRADE_ENABLED
166     QFrame *upgradeResultBox;
167     QLabel *upgradeResultLabel;
168     time_t upgradeResultTime;
169     QAction *upgradeAct;
170     QAction *upgradeCancelAct;
171     ActionButton *upgradeButton;
172     ActionButton *upgradeCancelButton;
173     QTimer autoupgradeTimer;
174     time_t autoupgradeTime;
175 #endif
176     QString debugFlags;
177     void showEvent(QShowEvent *ev) Q_DECL_OVERRIDE;
178     void schedCleanup(bool isError);
179     bool connectScheduler(bool privileged);
180     void showStatus();
181     void addHistoryCell(int row, int column, Qt::Alignment halign, QLabel *label);
182     bool addHistoryReport(const RunResults *runResults);
183     void initRunDisplay(const RunResults *runResults, const QString &timeTitle);
184     void addHistorySession(SessionResults *results);
185     void endHistorySession(SessionResults *results);
186     void loadHistoricLogs();
187     void startFileTail(QString logname) Q_DECL_OVERRIDE;
188     void watchForSchedulerRestart();
189     void printNextProberStart() Q_DECL_OVERRIDE;
190     bool setCountdownUnit(time_t when, time_t now, int count, int size,
191 	QString unit, QString units);
192     void proberError(const QString &text) Q_DECL_OVERRIDE;
193     void configChanged() Q_DECL_OVERRIDE;
194     void needConfig() Q_DECL_OVERRIDE;
195     void clearProberMessages(int n = 0);
196     void displayProberMessage(const QString &text, bool enabled = true,
197 	const QColor &color = QColor());
198     void promptForUpgrade() Q_DECL_OVERRIDE;
199     void cancelUpgradePrompt() Q_DECL_OVERRIDE;
200 #ifdef AUTOUPGRADE_ENABLED
201     void showUpgradeProgress(const QString &str) Q_DECL_OVERRIDE;
202     void showUpgradeResult(const QString &str) Q_DECL_OVERRIDE;
203 #endif
204 };
205