1 /* 2 * Copyright (C) 2019-2021 Ashar Khan <ashar786khan@gmail.com> 3 * 4 * This file is part of CP Editor. 5 * 6 * CP Editor is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * I will not be responsible if CP Editor behaves in unexpected way and 12 * causes your ratings to go down and or lose any important contest. 13 * 14 * Believe Software is "Software" and it isn't immune to bugs. 15 * 16 */ 17 18 #ifndef MAINWINDOW_HPP 19 #define MAINWINDOW_HPP 20 21 #include <QMainWindow> 22 23 class AppWindow; 24 class MessageLogger; 25 class QCodeEditor; 26 class QFileSystemWatcher; 27 class QPushButton; 28 class QSplitter; 29 class QTemporaryDir; 30 31 QT_BEGIN_NAMESPACE namespace Ui 32 { 33 class MainWindow; 34 } 35 QT_END_NAMESPACE 36 37 namespace Core 38 { 39 class Checker; 40 class Compiler; 41 class Runner; 42 } // namespace Core 43 44 namespace Extensions 45 { 46 class CFTool; 47 struct CompanionData; 48 } // namespace Extensions 49 50 namespace Widgets 51 { 52 class TestCases; 53 } 54 55 class MainWindow : public QMainWindow 56 { 57 Q_OBJECT 58 59 public: 60 struct EditorStatus 61 { 62 bool isLanguageSet{}; 63 QString filePath, savedText, problemURL, editorText, language, customCompileCommand; 64 int editorCursor{}, editorAnchor{}, horizontalScrollBarValue{}, verticalScrollbarValue{}, untitledIndex{}, 65 checkerIndex{}, customTimeLimit{}; 66 QStringList input, expected, customCheckers; 67 QVariantList testcasesIsShow; // This can't be renamed to "isChecked" because that's not compatible 68 QVariantList testCaseSplitterStates; 69 70 EditorStatus() = default; 71 72 explicit EditorStatus(const QMap<QString, QVariant> &status); 73 74 QMap<QString, QVariant> toMap() const; 75 }; 76 77 explicit MainWindow(int index, AppWindow *parent); 78 explicit MainWindow(const QString &fileOpen, int index, AppWindow *parent); 79 explicit MainWindow(const EditorStatus &status, bool duplicate, int index, AppWindow *parent); 80 ~MainWindow() override; 81 82 int getUntitledIndex() const; 83 QString getFileName() const; 84 QString getFilePath() const; 85 QString getProblemURL() const; 86 QString getCompleteTitle() const; 87 QString getTabTitle(bool complete, bool star, int removeLength = 0); 88 QCodeEditor *getEditor() const; 89 bool isUntitled() const; 90 91 void setProblemURL(const QString &url); 92 void setUntitledIndex(int index); 93 94 EditorStatus toStatus() const; 95 void loadStatus(const EditorStatus &status, bool duplicate = false); 96 97 bool save(bool force, const QString &head, bool safe = true); 98 void saveAs(); 99 100 bool isTextChanged() const; 101 bool closeConfirm(); 102 103 void killProcesses(); 104 void detachedExecution(); 105 void compileOnly(); 106 void runOnly(); 107 void compileAndRun(); 108 void formatSource(bool selectionOnly, bool logOnNoChange); 109 110 void applyCompanion(const Extensions::CompanionData &data); 111 112 void setLanguage(const QString &lang); 113 QString getLanguage(); 114 void applySettings(const QString &pagePath); 115 116 MessageLogger *getLogger(); 117 QSplitter *getSplitter(); 118 QSplitter *getRightSplitter(); 119 120 void insertText(const QString &text); 121 122 void setViewMode(const QString &mode); 123 QString tmpPath(); 124 125 /** 126 * @brief get the file path of a titled path, get the tmp path of an untitled path 127 */ 128 QString filePathOrTmpPath(); 129 130 /** 131 * @brief ask the user for the new compile command for this tab 132 */ 133 void updateCompileCommand(); 134 135 /** 136 * @brief ask the user for the new time limit for this tab 137 */ 138 void updateTimeLimit(); 139 140 private slots: 141 void onCompilationStarted(); 142 void onCompilationFinished(const QString &warning); 143 void onCompilationErrorOccurred(const QString &error); 144 void onCompilationFailed(const QString &reason); 145 void onCompilationKilled(); 146 147 void onRunStarted(int index); 148 void onRunFinished(int index, const QString &out, const QString &err, int exitCode, int timeUsed, bool tle); 149 void onFailedToStartRun(int index, const QString &error); 150 void onRunOutputLimitExceeded(int index, const QString &type); 151 void onRunKilled(int index); 152 153 void onFileWatcherChanged(const QString &); 154 void onEditorFontChanged(const QFont &newFont); 155 void onTextChanged(); 156 void updateCursorInfo(); 157 void updateChecker(); 158 void runTestCase(int index); 159 160 // UI Slots 161 162 void on_compile_clicked(); 163 164 void on_runOnly_clicked(); 165 166 void on_run_clicked(); 167 168 void on_clearMessagesButton_clicked(); 169 170 void on_changeLanguageButton_clicked(); 171 172 signals: 173 void editorFileChanged(); 174 void requestUpdateLanguageServerFilePath(MainWindow *window, const QString &path); 175 void editorTextChanged(MainWindow *window); 176 void editorFontChanged(); 177 void confirmTriggered(MainWindow *widget); 178 void requestToastMessage(const QString &head, const QString &body); 179 void editorLanguageChanged(MainWindow *window); 180 void compileOrRunTriggered(); 181 182 private: 183 enum SaveMode 184 { 185 IgnoreUntitled, // save only when filePath is not empty 186 AutoSave, // basically the same as IgnoreUntitled, only different in auto-format 187 AlwaysSave, // save to filePath if it's not empty, otherwise ask for new path 188 SaveAs, // ask for new path no matter filePath is empty or not 189 }; 190 enum AfterCompile 191 { 192 Nothing, 193 Run, 194 RunDetached 195 }; 196 197 Ui::MainWindow *ui; 198 QCodeEditor *editor; 199 QString language; 200 bool isLanguageSet = false; 201 202 Core::Compiler *compiler = nullptr; 203 QVector<Core::Runner *> runner; 204 Core::Checker *checker = nullptr; 205 Core::Runner *detachedRunner = nullptr; 206 QTemporaryDir *tmpDir = nullptr; 207 AfterCompile afterCompile = Nothing; 208 209 MessageLogger *log = nullptr; 210 211 AppWindow *appWindow = nullptr; 212 213 int untitledIndex; 214 QString problemURL; 215 QString filePath; 216 QString savedText; 217 QString cftoolPath; 218 QFileSystemWatcher *fileWatcher; 219 220 std::atomic<bool> reloading; 221 std::atomic<bool> killingProcesses; 222 223 QPushButton *submitToCodeforces = nullptr; 224 Extensions::CFTool *cftool = nullptr; 225 226 Widgets::TestCases *testcases = nullptr; 227 228 QTimer *autoSaveTimer = nullptr; 229 230 int customTimeLimit = -1; // the custom time limit for this tab, -1 represents for the same as settings 231 QString customCompileCommand; // the custom compile command for this tab, empty represents for the same as settings 232 233 void setEditor(); 234 void compile(); 235 void run(); 236 void run(int index); 237 void loadTests(); 238 void saveTests(bool safe); 239 void setCFToolUI(); 240 void setFilePath(QString path, bool updateBinder = true); 241 void setText(const QString &text, bool keep = false); 242 void updateWatcher(); 243 void loadFile(const QString &loadPath); 244 bool saveFile(SaveMode mode, const QString &head, bool safe); 245 void performCompileAndRunDiagonistics(); 246 static QString getRunnerHead(int index); 247 QString compileCommand() const; 248 int timeLimit() const; 249 void updateCompileAndRunButtons() const; 250 }; 251 #endif // MAINWINDOW_HPP 252