1 /*****************************************************************************
2  *                                                                           *
3  *  Elmer, A Finite Element Software for Multiphysical Problems              *
4  *                                                                           *
5  *  Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland   *
6  *                                                                           *
7  *  This program is free software; you can redistribute it and/or            *
8  *  modify it under the terms of the GNU General Public License              *
9  *  as published by the Free Software Foundation; either version 2           *
10  *  of the License, or (at your option) any later version.                   *
11  *                                                                           *
12  *  This program 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 this program (in file fem/GPL-2); if not, write to the        *
19  *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,         *
20  *  Boston, MA 02110-1301, USA.                                              *
21  *                                                                           *
22  *****************************************************************************/
23 
24 /*****************************************************************************
25  *                                                                           *
26  *  ElmerGUI solverlogwindow                                                 *
27  *                                                                           *
28  *****************************************************************************
29  *                                                                           *
30  *  Authors: Mikko Lyly, Juha Ruokolainen and Peter R�back                   *
31  *  Email:   Juha.Ruokolainen@csc.fi                                         *
32  *  Web:     http://www.csc.fi/elmer                                         *
33  *  Address: CSC - IT Center for Science Ltd.                                *
34  *           Keilaranta 14                                                   *
35  *           02101 Espoo, Finland                                            *
36  *                                                                           *
37  *  Original Date: 15 Mar 2008                                               *
38  *                                                                           *
39  *****************************************************************************/
40 
41 #include "solverlogwindow.h"
42 #include "mainwindow.h"
43 #include <QtGui>
44 #include <iostream>
45 
46 #if WITH_QT5
47 #include <QPrintDialog>
48 #include <QPrinter>
49 #include <QtWidgets>
50 #endif
51 
52 using namespace std;
53 
SolverLogHighlighter(int type,QTextDocument * parent)54 SolverLogHighlighter::SolverLogHighlighter(int type, QTextDocument *parent)
55     : QSyntaxHighlighter(parent) {
56 
57   if (type != SOLVERLOG_HIGHLIGHTING_LIGHT &&
58       type != SOLVERLOG_HIGHLIGHTING_DARK)
59     return;
60 
61   QColor yellow = QColor(161, 117, 0);
62   QColor orange = QColor(183, 55, 22);
63   QColor red = QColor(200, 30, 27);
64   QColor magenta = QColor(191, 34, 110);
65   QColor violet = QColor(88, 93, 176);
66   QColor blue = QColor(18, 99, 190);
67   QColor cyan = QColor(22, 141, 132);
68   QColor green = QColor(113, 113, 0);
69 
70   if (type == SOLVERLOG_HIGHLIGHTING_DARK) {
71     yellow = QColor(201, 157, 20);
72     orange = QColor(223, 95, 42);
73     red = QColor(240, 70, 67);
74     magenta = QColor(231, 74, 150);
75     violet = QColor(128, 133, 216);
76     blue = QColor(58, 159, 250);
77     cyan = QColor(62, 181, 172);
78     green = QColor(133, 173, 0);
79   }
80 
81   QColor cBlock = blue;
82   QColor cQuotation = orange;
83 
84   QColor cSuffix = red;
85   QColor cKeyword = yellow;
86   QColor cComment = green;
87   QColor cValue = blue;
88 
89   HighlightingRule rule;
90 
91   keywordFormat.setForeground(cKeyword);
92   rule.pattern = QRegExp("^(.*)\\bWARNING\\b(.*)$", Qt::CaseInsensitive);
93   rule.format = keywordFormat;
94   highlightingRules.append(rule);
95 
96   suffixFormat.setForeground(cSuffix);
97   rule.pattern = QRegExp("^(.*)\\bERROR\\b(.*)$", Qt::CaseInsensitive);
98   rule.format = suffixFormat;
99   highlightingRules.append(rule);
100 
101   commentFormat.setForeground(cComment);
102   rule.pattern =
103       QRegExp("^(.*) Elmer Solver: ALL DONE (.*)$", Qt::CaseSensitive);
104   rule.format = commentFormat;
105   highlightingRules.append(rule);
106 
107   commentFormat.setForeground(cComment);
108   QStringList patterns;
109   patterns << "^(.*) Elmer Solver: ALL DONE (.*)$"
110            << "^(.*)ElmerSolver: The end(.*)$"
111            << "^(.*)SOLVER TOTAL TIME(.*)$"
112            << "^(.*)ELMER SOLVER FINISHED AT:(.*)$";
113   foreach (const QString &pattern, patterns) {
114     rule.pattern = QRegExp(pattern, Qt::CaseInsensitive);
115     rule.format = commentFormat;
116     highlightingRules.append(rule);
117   }
118 
119   valueFormat.setForeground(cValue);
120   patterns.clear();
121   patterns << "^(.*)\\b(\\S)*.ep\\b(.*)$";
122   foreach (const QString &pattern, patterns) {
123     rule.pattern = QRegExp(pattern, Qt::CaseInsensitive);
124     rule.format = valueFormat;
125     highlightingRules.append(rule);
126   }
127 }
128 
highlightBlock(const QString & text)129 void SolverLogHighlighter::highlightBlock(const QString &text) {
130   foreach (const HighlightingRule &rule, highlightingRules) {
131     QRegExp expression(rule.pattern);
132     int index = expression.indexIn(text);
133     while (index >= 0) {
134       int length = expression.matchedLength();
135       setFormat(index, length, rule.format);
136       index = expression.indexIn(text, index + length);
137     }
138   }
139 }
140 
SolverLogWindow(QWidget * parent)141 SolverLogWindow::SolverLogWindow(QWidget *parent) : QMainWindow(parent) {
142   setWindowFlags(Qt::Window);
143 
144   textEdit = new QTextEdit;
145   textEdit->setLineWrapMode(QTextEdit::NoWrap);
146 
147   setCentralWidget(textEdit);
148 
149   lineEdit = new QLineEdit;
150   connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(findSlot()));
151 
152   createActions();
153   createMenus();
154   createToolBars();
155   createStatusBar();
156 
157   firstTime = true;
158   found = false;
159 
160   setWindowTitle(tr("Solver Log"));
161   setWindowIcon(QIcon(":/icons/Mesh3D.png"));
162 
163   highlighter = NULL;
164 
165   QString strFont =
166       ((MainWindow *)parent)
167           ->settings_value(QString("solverlogWindow/font"), QString(""))
168           .toString();
169   QFont font;
170   if (!strFont.isEmpty() && font.fromString(strFont)) {
171     font.setFixedPitch(true);
172     textEdit->setFont(font);
173     lineEdit->setFont(font);
174   }
175 
176   int syntaxHighlighting =
177       ((MainWindow *)parent)
178           ->settings_value(QString("solverlogWindow/highlighting"),
179                            SOLVERLOG_HIGHLIGHTING_NONE)
180           .toInt();
181   if (syntaxHighlighting == SOLVERLOG_HIGHLIGHTING_NONE) {
182     highlightingNoneSlot();
183   } else if (syntaxHighlighting == SOLVERLOG_HIGHLIGHTING_LIGHT) {
184     highlightingLightSlot();
185   } else if (syntaxHighlighting == SOLVERLOG_HIGHLIGHTING_DARK) {
186     highlightingDarkSlot();
187   }
188 }
189 
~SolverLogWindow()190 SolverLogWindow::~SolverLogWindow() {}
191 
getTextEdit(void)192 QTextEdit *SolverLogWindow::getTextEdit(void) { return this->textEdit; }
193 
setFirstTime(bool b)194 void SolverLogWindow::setFirstTime(bool b) { this->firstTime = b; }
195 
setFound(bool b)196 void SolverLogWindow::setFound(bool b) { this->found = b; }
197 
minimumSizeHint() const198 QSize SolverLogWindow::minimumSizeHint() const { return QSize(64, 64); }
199 
sizeHint() const200 QSize SolverLogWindow::sizeHint() const { return QSize(640, 640); }
201 
createActions()202 void SolverLogWindow::createActions() {
203   newAct = new QAction(QIcon(":/icons/document-new.png"), tr("&New"), this);
204   newAct->setShortcut(tr("Ctrl+N"));
205   newAct->setStatusTip(tr("New text document"));
206   connect(newAct, SIGNAL(triggered()), this, SLOT(newSlot()));
207 
208   openAct =
209       new QAction(QIcon(":/icons/document-open.png"), tr("&Open..."), this);
210   openAct->setShortcut(tr("Ctrl+O"));
211   openAct->setStatusTip(tr("Open text file"));
212   connect(openAct, SIGNAL(triggered()), this, SLOT(openSlot()));
213 
214   saveAct =
215       new QAction(QIcon(":/icons/document-save.png"), tr("&Save as..."), this);
216   saveAct->setShortcut(tr("Ctrl+S"));
217   saveAct->setStatusTip(tr("Save text file"));
218   connect(saveAct, SIGNAL(triggered()), this, SLOT(saveSlot()));
219 
220   printAct =
221       new QAction(QIcon(":/icons/document-print.png"), tr("&Print..."), this);
222   printAct->setShortcut(tr("Ctrl+P"));
223   printAct->setStatusTip(tr("Print document"));
224   connect(printAct, SIGNAL(triggered()), this, SLOT(printSlot()));
225 
226   exitAct =
227       new QAction(QIcon(":/icons/application-exit.png"), tr("&Quit"), this);
228   exitAct->setShortcut(tr("Ctrl+Q"));
229   exitAct->setStatusTip(tr("Quit editor"));
230   connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
231 
232   cutAct = new QAction(QIcon(":/icons/edit-cut.png"), tr("Cu&t"), this);
233   cutAct->setShortcut(tr("Ctrl+X"));
234   cutAct->setStatusTip(tr("Cut the current selection to clipboard"));
235   connect(cutAct, SIGNAL(triggered()), this->textEdit, SLOT(cut()));
236 
237   copyAct = new QAction(QIcon(":/icons/edit-copy.png"), tr("&Copy"), this);
238   copyAct->setShortcut(tr("Ctrl+C"));
239   copyAct->setStatusTip(tr("Copy the current selection to clipboard"));
240   connect(copyAct, SIGNAL(triggered()), this->textEdit, SLOT(copy()));
241 
242   pasteAct = new QAction(QIcon(":/icons/edit-paste.png"), tr("&Paste"), this);
243   pasteAct->setShortcut(tr("Ctrl+V"));
244   pasteAct->setStatusTip(tr("Paste clipboard into the current selection"));
245   connect(pasteAct, SIGNAL(triggered()), this->textEdit, SLOT(paste()));
246 
247   findAct = new QAction(QIcon(":/icons/edit-find.png"), tr("&Find"), this);
248   findAct->setShortcut(tr("Ctrl+F"));
249   findAct->setStatusTip(tr("Find text in document"));
250   connect(findAct, SIGNAL(triggered()), this, SLOT(findSlot()));
251 
252   fontAct = new QAction(QIcon(""), tr("&Font"), this);
253   findAct->setStatusTip(tr("Select font"));
254   connect(fontAct, SIGNAL(triggered()), this, SLOT(fontSlot()));
255 
256   highlightingNoneAct = new QAction(QIcon(""), tr("&None"), this);
257   highlightingNoneAct->setStatusTip(tr("No highlighting"));
258   highlightingNoneAct->setCheckable(true);
259   connect(highlightingNoneAct, SIGNAL(triggered()), this,
260           SLOT(highlightingNoneSlot()));
261 
262   highlightingLightAct = new QAction(QIcon(""), tr(" &Light"), this);
263   highlightingLightAct->setStatusTip(tr("Highlight in light theme"));
264   highlightingLightAct->setCheckable(true);
265   connect(highlightingLightAct, SIGNAL(triggered()), this,
266           SLOT(highlightingLightSlot()));
267 
268   highlightingDarkAct = new QAction(QIcon(""), tr(" &Dark"), this);
269   highlightingDarkAct->setStatusTip(tr("Highlight in dark theme"));
270   highlightingDarkAct->setCheckable(true);
271   connect(highlightingDarkAct, SIGNAL(triggered()), this,
272           SLOT(highlightingDarkSlot()));
273 }
274 
createMenus()275 void SolverLogWindow::createMenus() {
276   fileMenu = menuBar()->addMenu(tr("&File"));
277   fileMenu->addAction(newAct);
278   fileMenu->addAction(openAct);
279   fileMenu->addAction(saveAct);
280   fileMenu->addSeparator();
281   fileMenu->addAction(printAct);
282   fileMenu->addSeparator();
283   fileMenu->addAction(exitAct);
284 
285   editMenu = menuBar()->addMenu(tr("&Edit"));
286   editMenu->addAction(cutAct);
287   editMenu->addAction(copyAct);
288   editMenu->addAction(pasteAct);
289   editMenu->addSeparator();
290   editMenu->addAction(findAct);
291 
292   preferenceMenu = menuBar()->addMenu(tr("&Preference"));
293   preferenceMenu->addAction(fontAct);
294   highlightingMenu = preferenceMenu->addMenu(tr("&Syntax highlighting"));
295   highlightingMenu->addAction(highlightingNoneAct);
296   highlightingMenu->addAction(highlightingLightAct);
297   highlightingMenu->addAction(highlightingDarkAct);
298 }
299 
createToolBars()300 void SolverLogWindow::createToolBars() {
301   fileToolBar = addToolBar(tr("&File"));
302   fileToolBar->addAction(newAct);
303   fileToolBar->addAction(openAct);
304   fileToolBar->addAction(saveAct);
305   fileToolBar->addAction(printAct);
306 
307   editToolBar = addToolBar(tr("&Edit"));
308   editToolBar->addAction(cutAct);
309   editToolBar->addAction(copyAct);
310   editToolBar->addAction(pasteAct);
311   editToolBar->addSeparator();
312   editToolBar->addWidget(lineEdit);
313   editToolBar->addAction(findAct);
314 }
315 
createStatusBar()316 void SolverLogWindow::createStatusBar() {
317   statusBar()->showMessage(tr("Ready"));
318 }
319 
newSlot()320 void SolverLogWindow::newSlot() {
321   textEdit->clear();
322 
323   firstTime = true;
324   found = false;
325 
326   statusBar()->showMessage(tr("Ready"));
327 }
328 
openSlot()329 void SolverLogWindow::openSlot() {
330   QString fileName;
331 
332   fileName = QFileDialog::getOpenFileName(this, tr("Open text file"));
333 
334   if (fileName.isEmpty())
335     return;
336 
337   QFile file;
338   file.setFileName(fileName);
339   if (!file.open(QIODevice::ReadOnly))
340     return;
341 
342   QTextStream inputStream(&file);
343 
344   statusBar()->showMessage(tr("Opening file..."));
345 
346   textEdit->clear();
347 
348   QString line = inputStream.readAll();
349 
350   file.close();
351 
352   textEdit->append(line);
353 
354   firstTime = true;
355   found = false;
356 
357   statusBar()->showMessage(tr("Ready"));
358 }
359 
saveSlot()360 void SolverLogWindow::saveSlot() {
361   QString fileName;
362 
363   fileName = QFileDialog::getSaveFileName(this, tr("Save text file"));
364 
365   if (fileName.isEmpty())
366     return;
367 
368   QFile file;
369   file.setFileName(fileName);
370   if (!file.open(QIODevice::WriteOnly))
371     return;
372 
373   QTextStream outputStream(&file);
374 
375   statusBar()->showMessage(tr("Saving file..."));
376 
377   outputStream << textEdit->toPlainText();
378 
379   file.close();
380 
381   statusBar()->showMessage(tr("Ready"));
382 }
383 
printSlot()384 void SolverLogWindow::printSlot() {
385   QTextDocument *document = textEdit->document();
386   QPrinter printer;
387 
388   QPrintDialog *printDialog = new QPrintDialog(&printer, this);
389   if (printDialog->exec() != QDialog::Accepted)
390     return;
391 
392   statusBar()->showMessage(tr("Printing..."));
393 
394   document->print(&printer);
395 
396   statusBar()->showMessage(tr("Ready"));
397 }
398 
findSlot()399 void SolverLogWindow::findSlot() {
400   QString searchString = lineEdit->text().trimmed();
401   QTextDocument *document = textEdit->document();
402 
403   if (!firstTime && found)
404     document->undo();
405 
406   found = false;
407 
408   if (searchString == "") {
409     QMessageBox::information(this, tr("Empty string"),
410                              "Please enter a string in the "
411                              "line edit box in the tool bar");
412   } else {
413 
414     QTextCursor highlightCursor(document);
415     QTextCursor cursor(document);
416 
417     cursor.beginEditBlock();
418 
419     QTextCharFormat plainFormat(highlightCursor.charFormat());
420     QTextCharFormat colorFormat = plainFormat;
421     colorFormat.setForeground(Qt::red);
422     colorFormat.setFontWeight(QFont::Bold);
423 
424     while (!highlightCursor.isNull() && !highlightCursor.atEnd()) {
425       highlightCursor = document->find(searchString, highlightCursor);
426 
427       if (!highlightCursor.isNull()) {
428         found = true;
429         highlightCursor.mergeCharFormat(colorFormat);
430       }
431     }
432 
433     cursor.endEditBlock();
434     firstTime = false;
435 
436     if (!found)
437       QMessageBox::information(this, tr("String not found"),
438                                "The string was not found in the document");
439   }
440 
441   statusBar()->showMessage(tr("Ready"));
442 }
443 
fontSlot()444 void SolverLogWindow::fontSlot() {
445   bool ok;
446   QFont font = QFontDialog::getFont(&ok, textEdit->font());
447   if (ok) {
448     font.setFixedPitch(true);
449     textEdit->setFont(font);
450     lineEdit->setFont(font);
451   }
452   ((MainWindow *)parent())
453       ->settings_setValue(QString("solverlogWindow/font"), font.toString());
454 }
highlightingNoneSlot()455 void SolverLogWindow::highlightingNoneSlot() {
456   QString style = "";
457   setStyleSheet(style);
458   delete highlighter;
459   highlighter = NULL;
460   ((MainWindow *)parent())
461       ->settings_setValue(QString("solverlogWindow/highlighting"),
462                           SOLVERLOG_HIGHLIGHTING_NONE);
463   highlightingNoneAct->setChecked(true);
464   highlightingLightAct->setChecked(false);
465   highlightingDarkAct->setChecked(false);
466 }
467 
highlightingLightSlot()468 void SolverLogWindow::highlightingLightSlot() {
469   QString style = "QTextEdit { color: #384e55; background: #fffdf6}";
470   setStyleSheet(style);
471   delete highlighter;
472   highlighter = new SolverLogHighlighter(SOLVERLOG_HIGHLIGHTING_LIGHT,
473                                          textEdit->document());
474   ((MainWindow *)parent())
475       ->settings_setValue(QString("solverlogWindow/highlighting"),
476                           SOLVERLOG_HIGHLIGHTING_LIGHT);
477   highlightingNoneAct->setChecked(false);
478   highlightingLightAct->setChecked(true);
479   highlightingDarkAct->setChecked(false);
480 }
481 
highlightingDarkSlot()482 void SolverLogWindow::highlightingDarkSlot() {
483   QString style = "QTextEdit { color: #c3b1b1; background: #000814}";
484   setStyleSheet(style);
485   delete highlighter;
486   highlighter = new SolverLogHighlighter(SOLVERLOG_HIGHLIGHTING_DARK,
487                                          textEdit->document());
488   ((MainWindow *)parent())
489       ->settings_setValue(QString("solverlogWindow/highlighting"),
490                           SOLVERLOG_HIGHLIGHTING_DARK);
491   highlightingNoneAct->setChecked(false);
492   highlightingLightAct->setChecked(false);
493   highlightingDarkAct->setChecked(true);
494 }