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 sifwindow                                                       *
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 "sifwindow.h"
42 #include "mainwindow.h"
43 #include <QtGui>
44 #include <iostream>
45 
46 
47 #if WITH_QT5
48 #include <QPrintDialog>
49 #include <QPrinter>
50 #include <QtWidgets>
51 
52 #endif
53 
54 using namespace std;
55 
SifHighlighter(int type,QTextDocument * parent)56 SifHighlighter::SifHighlighter(int type, QTextDocument *parent)
57     : QSyntaxHighlighter(parent) {
58   if (type != SIF_HIGHLIGHTING_LIGHT && type != SIF_HIGHLIGHTING_DARK)
59     return;
60 
61   QColor yellow = QColor(161, 97, 0);
62   QColor orange = QColor(183, 55, 22);
63   QColor red = QColor(100, 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 == SIF_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(153, 173, 0);
79   }
80 
81   QColor cBlock = blue;
82   QColor cKeyword = violet;
83   QColor cValue = cyan;
84   QColor cQuotation = orange;
85   QColor cComment = green;
86   QColor cSuffix = magenta;
87 
88   HighlightingRule rule;
89 
90   blockFormat.setForeground(cBlock);
91   QStringList blockPatterns;
92   blockPatterns << "^\\s*Equation\\s+[1-9][0-9]*\\s*$"
93                 << "^\\s*Material\\s+[1-9][0-9]*\\s*$"
94                 << "^\\s*Body\\s+Force\\s+[1-9][0-9]*\\s*$"
95                 << "^\\s*Initial\\s+Condition\\s+[1-9][0-9]*\\s*$"
96                 << "^\\s*Boundary\\s+Condition\\s+[1-9][0-9]*\\s*$"
97                 << "^\\s*Component\\s+[1-9][0-9]*\\s*$"
98                 << "^\\s*Solver\\s+[1-9][0-9]*\\s*$"
99                 << "^\\s*Body\\s+[1-9][0-9]*\\s*$"
100                 << "^\\s*Header\\s*$"
101                 << "^\\s*Simulation\\s*$"
102                 << "^\\s*Constants\\s*$"
103                 << "^\\s*End\\s*$"
104 
105                 << "^\\s*Equation\\s+[1-9][0-9]*\\s*!"
106                 << "^\\s*Material\\s+[1-9][0-9]*\\s*!"
107                 << "^\\s*Body\\s+Force\\s+[1-9][0-9]*\\s*!"
108                 << "^\\s*Initial\\s+Condition\\s+[1-9][0-9]*\\s*!"
109                 << "^\\s*Boundary\\s+Condition\\s+[1-9][0-9]*\\s*!"
110                 << "^\\s*Component\\s+[1-9][0-9]*\\s*!"
111                 << "^\\s*Solver\\s+[1-9][0-9]*\\s*!"
112                 << "^\\s*Body\\s+[1-9][0-9]*\\s*!"
113                 << "^\\s*Header\\s*!"
114                 << "^\\s*Simulation\\s*!"
115                 << "^\\s*Constants\\s*!"
116                 << "^\\s*End\\s*!";
117   foreach (const QString &pattern, blockPatterns) {
118     rule.pattern = QRegExp(pattern, Qt::CaseInsensitive);
119     rule.format = blockFormat;
120     highlightingRules.append(rule);
121   }
122 
123   keywordFormat.setForeground(cKeyword);
124   rule.pattern = QRegExp("\\bInteger\\b", Qt::CaseInsensitive);
125   rule.format = keywordFormat;
126   highlightingRules.append(rule);
127   rule.pattern = QRegExp("\\bReal\\b", Qt::CaseInsensitive);
128   rule.format = keywordFormat;
129   highlightingRules.append(rule);
130   rule.pattern = QRegExp("\\bLogical\\b", Qt::CaseInsensitive);
131   rule.format = keywordFormat;
132   highlightingRules.append(rule);
133   rule.pattern = QRegExp("\\bMATC\\b", Qt::CaseInsensitive);
134   rule.format = keywordFormat;
135   highlightingRules.append(rule);
136   rule.pattern = QRegExp("\\bEquals\\b", Qt::CaseInsensitive);
137   rule.format = keywordFormat;
138   highlightingRules.append(rule);
139 
140   valueFormat.setForeground(cValue);
141   rule.pattern = QRegExp("\\bTrue\\b", Qt::CaseInsensitive);
142   rule.format = valueFormat;
143   highlightingRules.append(rule);
144   rule.pattern = QRegExp("\\bFalse\\b", Qt::CaseInsensitive);
145   rule.format = valueFormat;
146   highlightingRules.append(rule);
147 
148   quotationFormat.setForeground(cQuotation);
149   rule.pattern = QRegExp("\".*\"");
150   rule.format = quotationFormat;
151   highlightingRules.append(rule);
152 
153   suffixFormat.setForeground(cSuffix);
154   rule.pattern = QRegExp("\\([1-9][0-9]*\\)", Qt::CaseInsensitive);
155   rule.format = suffixFormat;
156   highlightingRules.append(rule);
157 
158   commentFormat.setForeground(cComment);
159   commentFormat.setFontWeight(QFont::Normal);
160   rule.pattern = QRegExp("![^\n]*");
161   rule.format = commentFormat;
162   highlightingRules.append(rule);
163 }
164 
highlightBlock(const QString & text)165 void SifHighlighter::highlightBlock(const QString &text) {
166   foreach (const HighlightingRule &rule, highlightingRules) {
167     QRegExp expression(rule.pattern);
168     int index = expression.indexIn(text);
169     while (index >= 0) {
170       int length = expression.matchedLength();
171       setFormat(index, length, rule.format);
172       index = expression.indexIn(text, index + length);
173     }
174   }
175 }
176 
SifWindow(QWidget * parent)177 SifWindow::SifWindow(QWidget *parent) : QMainWindow(parent) {
178   setWindowFlags(Qt::Window);
179 
180   textEdit = new QTextEdit;
181   textEdit->setLineWrapMode(QTextEdit::NoWrap);
182 
183   setCentralWidget(textEdit);
184 
185   lineEdit = new QLineEdit;
186   connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(findSlot()));
187 
188   createActions();
189   createMenus();
190   createToolBars();
191   createStatusBar();
192 
193   firstTime = true;
194   found = false;
195 
196   setWindowTitle(tr("Solver Input File"));
197   setWindowIcon(QIcon(":/icons/Mesh3D.png"));
198 
199   highlighter = NULL;
200 
201   QString strFont = ((MainWindow *)parent)
202                         ->settings_value(QString("sifWindow/font"), QString(""))
203                         .toString();
204   QFont font;
205   if (!strFont.isEmpty() && font.fromString(strFont)) {
206     font.setFixedPitch(true);
207     textEdit->setFont(font);
208     lineEdit->setFont(font);
209   }
210 
211   int syntaxHighlighting =
212       ((MainWindow *)parent)
213           ->settings_value(QString("sifWindow/highlighting"),
214                            SIF_HIGHLIGHTING_NONE)
215           .toInt();
216   if (syntaxHighlighting == SIF_HIGHLIGHTING_NONE) {
217     highlightingNoneSlot();
218   } else if (syntaxHighlighting == SIF_HIGHLIGHTING_LIGHT) {
219     highlightingLightSlot();
220   } else if (syntaxHighlighting == SIF_HIGHLIGHTING_DARK) {
221     highlightingDarkSlot();
222   }
223 }
224 
~SifWindow()225 SifWindow::~SifWindow() {}
226 
getTextEdit(void)227 QTextEdit *SifWindow::getTextEdit(void) { return this->textEdit; }
228 
setFirstTime(bool b)229 void SifWindow::setFirstTime(bool b) { this->firstTime = b; }
230 
setFound(bool b)231 void SifWindow::setFound(bool b) { this->found = b; }
232 
minimumSizeHint() const233 QSize SifWindow::minimumSizeHint() const { return QSize(64, 64); }
234 
sizeHint() const235 QSize SifWindow::sizeHint() const { return QSize(640, 640); }
236 
createActions()237 void SifWindow::createActions() {
238   newAct = new QAction(QIcon(":/icons/document-new.png"), tr("&New"), this);
239   newAct->setShortcut(tr("Ctrl+N"));
240   newAct->setStatusTip(tr("New text document"));
241   connect(newAct, SIGNAL(triggered()), this, SLOT(newSlot()));
242 
243   openAct =
244       new QAction(QIcon(":/icons/document-open.png"), tr("&Open..."), this);
245   openAct->setShortcut(tr("Ctrl+O"));
246   openAct->setStatusTip(tr("Open text file"));
247   connect(openAct, SIGNAL(triggered()), this, SLOT(openSlot()));
248 
249   saveAct =
250       new QAction(QIcon(":/icons/document-save.png"), tr("&Save as..."), this);
251   saveAct->setShortcut(tr("Ctrl+S"));
252   saveAct->setStatusTip(tr("Save text file"));
253   connect(saveAct, SIGNAL(triggered()), this, SLOT(saveSlot()));
254 
255   printAct =
256       new QAction(QIcon(":/icons/document-print.png"), tr("&Print..."), this);
257   printAct->setShortcut(tr("Ctrl+P"));
258   printAct->setStatusTip(tr("Print document"));
259   connect(printAct, SIGNAL(triggered()), this, SLOT(printSlot()));
260 
261   exitAct =
262       new QAction(QIcon(":/icons/application-exit.png"), tr("&Quit"), this);
263   exitAct->setShortcut(tr("Ctrl+Q"));
264   exitAct->setStatusTip(tr("Quit editor"));
265   connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
266 
267   cutAct = new QAction(QIcon(":/icons/edit-cut.png"), tr("Cu&t"), this);
268   cutAct->setShortcut(tr("Ctrl+X"));
269   cutAct->setStatusTip(tr("Cut the current selection to clipboard"));
270   connect(cutAct, SIGNAL(triggered()), this->textEdit, SLOT(cut()));
271 
272   copyAct = new QAction(QIcon(":/icons/edit-copy.png"), tr("&Copy"), this);
273   copyAct->setShortcut(tr("Ctrl+C"));
274   copyAct->setStatusTip(tr("Copy the current selection to clipboard"));
275   connect(copyAct, SIGNAL(triggered()), this->textEdit, SLOT(copy()));
276 
277   pasteAct = new QAction(QIcon(":/icons/edit-paste.png"), tr("&Paste"), this);
278   pasteAct->setShortcut(tr("Ctrl+V"));
279   pasteAct->setStatusTip(tr("Paste clipboard into the current selection"));
280   connect(pasteAct, SIGNAL(triggered()), this->textEdit, SLOT(paste()));
281 
282   findAct = new QAction(QIcon(":/icons/edit-find.png"), tr("&Find"), this);
283   findAct->setShortcut(tr("Ctrl+F"));
284   findAct->setStatusTip(tr("Find text in document"));
285   connect(findAct, SIGNAL(triggered()), this, SLOT(findSlot()));
286 
287   fontAct = new QAction(QIcon(""), tr("&Font"), this);
288   findAct->setStatusTip(tr("Select font"));
289   connect(fontAct, SIGNAL(triggered()), this, SLOT(fontSlot()));
290 
291   highlightingNoneAct = new QAction(QIcon(""), tr("&None"), this);
292   highlightingNoneAct->setStatusTip(tr("No highlighting"));
293   highlightingNoneAct->setCheckable(true);
294   connect(highlightingNoneAct, SIGNAL(triggered()), this,
295           SLOT(highlightingNoneSlot()));
296 
297   highlightingLightAct = new QAction(QIcon(""), tr(" &Light"), this);
298   highlightingLightAct->setStatusTip(tr("Highlight in light theme"));
299   highlightingLightAct->setCheckable(true);
300   connect(highlightingLightAct, SIGNAL(triggered()), this,
301           SLOT(highlightingLightSlot()));
302 
303   highlightingDarkAct = new QAction(QIcon(""), tr(" &Dark"), this);
304   highlightingDarkAct->setStatusTip(tr("Highlight in dark theme"));
305   highlightingDarkAct->setCheckable(true);
306   connect(highlightingDarkAct, SIGNAL(triggered()), this,
307           SLOT(highlightingDarkSlot()));
308 
309   saveAndRunAct =
310       new QAction(QIcon(":/icons/arrow-right.png"), tr("&Save and run"), this);
311   saveAndRunAct->setStatusTip(tr("Save the sif and project (without "
312                                  "auto-generating sif),  then run solver "));
313   connect(saveAndRunAct, SIGNAL(triggered()), this, SLOT(saveAndRunSlot()));
314 }
315 
createMenus()316 void SifWindow::createMenus() {
317   fileMenu = menuBar()->addMenu(tr("&File"));
318   fileMenu->addAction(newAct);
319   fileMenu->addAction(openAct);
320   fileMenu->addAction(saveAct);
321   fileMenu->addAction(saveAndRunAct);
322   fileMenu->addSeparator();
323   fileMenu->addAction(printAct);
324   fileMenu->addSeparator();
325   fileMenu->addAction(exitAct);
326 
327   editMenu = menuBar()->addMenu(tr("&Edit"));
328   editMenu->addAction(cutAct);
329   editMenu->addAction(copyAct);
330   editMenu->addAction(pasteAct);
331   editMenu->addSeparator();
332   editMenu->addAction(findAct);
333 
334   preferenceMenu = menuBar()->addMenu(tr("&Preference"));
335   preferenceMenu->addAction(fontAct);
336   highlightingMenu = preferenceMenu->addMenu(tr("&Syntax highlighting"));
337   highlightingMenu->addAction(highlightingNoneAct);
338   highlightingMenu->addAction(highlightingLightAct);
339   highlightingMenu->addAction(highlightingDarkAct);
340 }
341 
createToolBars()342 void SifWindow::createToolBars() {
343   fileToolBar = addToolBar(tr("&File"));
344   fileToolBar->addAction(newAct);
345   fileToolBar->addAction(openAct);
346   fileToolBar->addAction(saveAct);
347   fileToolBar->addAction(saveAndRunAct);
348   fileToolBar->addAction(printAct);
349 
350   editToolBar = addToolBar(tr("&Edit"));
351   editToolBar->addAction(cutAct);
352   editToolBar->addAction(copyAct);
353   editToolBar->addAction(pasteAct);
354   editToolBar->addSeparator();
355   editToolBar->addWidget(lineEdit);
356   editToolBar->addAction(findAct);
357 }
358 
createStatusBar()359 void SifWindow::createStatusBar() { statusBar()->showMessage(tr("Ready")); }
360 
newSlot()361 void SifWindow::newSlot() {
362   textEdit->clear();
363 
364   firstTime = true;
365   found = false;
366 
367   statusBar()->showMessage(tr("Ready"));
368 }
369 
openSlot()370 void SifWindow::openSlot() {
371   QString fileName;
372 
373   fileName = QFileDialog::getOpenFileName(this, tr("Open text file"));
374 
375   if (fileName.isEmpty())
376     return;
377 
378   QFile file;
379   file.setFileName(fileName);
380   if (!file.open(QIODevice::ReadOnly))
381     return;
382 
383   QTextStream inputStream(&file);
384 
385   statusBar()->showMessage(tr("Opening file..."));
386 
387   textEdit->clear();
388 
389   QString line = inputStream.readAll();
390 
391   file.close();
392 
393   textEdit->append(line);
394 
395   firstTime = true;
396   found = false;
397 
398   statusBar()->showMessage(tr("Ready"));
399 }
400 
saveSlot()401 void SifWindow::saveSlot() {
402   QString fileName;
403 
404   fileName = QFileDialog::getSaveFileName(this, tr("Save text file"));
405 
406   if (fileName.isEmpty())
407     return;
408 
409   QFile file;
410   file.setFileName(fileName);
411   if (!file.open(QIODevice::WriteOnly))
412     return;
413 
414   QTextStream outputStream(&file);
415 
416   statusBar()->showMessage(tr("Saving file..."));
417 
418   outputStream << textEdit->toPlainText();
419 
420   file.close();
421 
422   statusBar()->showMessage(tr("Ready"));
423 }
424 
printSlot()425 void SifWindow::printSlot() {
426   QTextDocument *document = textEdit->document();
427   QPrinter printer;
428 
429   QPrintDialog *printDialog = new QPrintDialog(&printer, this);
430   if (printDialog->exec() != QDialog::Accepted)
431     return;
432 
433   statusBar()->showMessage(tr("Printing..."));
434 
435   document->print(&printer);
436 
437   statusBar()->showMessage(tr("Ready"));
438 }
439 
findSlot()440 void SifWindow::findSlot() {
441   QString searchString = lineEdit->text().trimmed();
442   QTextDocument *document = textEdit->document();
443 
444   if (!firstTime && found)
445     document->undo();
446 
447   found = false;
448 
449   if (searchString == "") {
450     QMessageBox::information(this, tr("Empty string"),
451                              "Please enter a string in the "
452                              "line edit box in the tool bar");
453   } else {
454 
455     QTextCursor highlightCursor(document);
456     QTextCursor cursor(document);
457 
458     cursor.beginEditBlock();
459 
460     QTextCharFormat plainFormat(highlightCursor.charFormat());
461     QTextCharFormat colorFormat = plainFormat;
462     colorFormat.setForeground(Qt::red);
463     colorFormat.setFontWeight(QFont::Bold);
464 
465     while (!highlightCursor.isNull() && !highlightCursor.atEnd()) {
466       highlightCursor = document->find(searchString, highlightCursor);
467 
468       if (!highlightCursor.isNull()) {
469         found = true;
470         highlightCursor.mergeCharFormat(colorFormat);
471       }
472     }
473 
474     cursor.endEditBlock();
475     firstTime = false;
476 
477     if (!found)
478       QMessageBox::information(this, tr("String not found"),
479                                "The string was not found in the document");
480   }
481 
482   statusBar()->showMessage(tr("Ready"));
483 }
484 
fontSlot()485 void SifWindow::fontSlot() {
486   bool ok;
487   QFont font = QFontDialog::getFont(&ok, textEdit->font());
488   if (ok) {
489     font.setFixedPitch(true);
490     textEdit->setFont(font);
491     lineEdit->setFont(font);
492   }
493   ((MainWindow *)parent())
494       ->settings_setValue(QString("sifWindow/font"), font.toString());
495 }
highlightingNoneSlot()496 void SifWindow::highlightingNoneSlot() {
497   QString style = "";
498   setStyleSheet(style);
499   delete highlighter;
500   highlighter = NULL;
501   ((MainWindow *)parent())
502       ->settings_setValue(QString("sifWindow/highlighting"),
503                           SIF_HIGHLIGHTING_NONE);
504   highlightingNoneAct->setChecked(true);
505   highlightingLightAct->setChecked(false);
506   highlightingDarkAct->setChecked(false);
507 }
508 
highlightingLightSlot()509 void SifWindow::highlightingLightSlot() {
510   QString style = "QTextEdit { color: #384e55; background: #fffdf6}";
511   setStyleSheet(style);
512   delete highlighter;
513   highlighter =
514       new SifHighlighter(SIF_HIGHLIGHTING_LIGHT, textEdit->document());
515   ((MainWindow *)parent())
516       ->settings_setValue(QString("sifWindow/highlighting"),
517                           SIF_HIGHLIGHTING_LIGHT);
518   highlightingNoneAct->setChecked(false);
519   highlightingLightAct->setChecked(true);
520   highlightingDarkAct->setChecked(false);
521 }
522 
highlightingDarkSlot()523 void SifWindow::highlightingDarkSlot() {
524   QString style = "QTextEdit { color: #c3b1b1; background: #000814}";
525   setStyleSheet(style);
526   delete highlighter;
527   highlighter = new SifHighlighter(SIF_HIGHLIGHTING_DARK, textEdit->document());
528   ((MainWindow *)parent())
529       ->settings_setValue(QString("sifWindow/highlighting"),
530                           SIF_HIGHLIGHTING_DARK);
531   highlightingNoneAct->setChecked(false);
532   highlightingLightAct->setChecked(false);
533   highlightingDarkAct->setChecked(true);
534 }
535 
saveAndRunSlot()536 void SifWindow::saveAndRunSlot() {
537   ((MainWindow *)parent())->saveAndRun(false);
538 }