Nicolas Winkler 6 лет назад
Родитель
Сommit
37a1d0b5a9
5 измененных файлов с 115 добавлено и 58 удалено
  1. 55 13
      brainywindow.cpp
  2. 5 3
      brainywindow.h
  3. 18 18
      brainywindow.ui
  4. 36 24
      syntaxhighlighter.cpp
  5. 1 0
      syntaxhighlighter.h

+ 55 - 13
brainywindow.cpp

@@ -2,20 +2,24 @@
 #include "ui_brainywindow.h"
 #include <QFileDialog>
 #include <QFontDialog>
+#include <QMessageBox>
 #include <QFile>
 #include <QTextStream>
 #include <QFontMetrics>
 #include <iostream>
+#include <memory>
 
 BrainyWindow::BrainyWindow(QWidget *parent) :
-    QMainWindow(parent),
-    ui(new Ui::BrainyWindow)
+    QMainWindow{ parent },
+    ui{ std::make_unique<Ui::BrainyWindow>() }
 {
     ui->setupUi(this);
-    sh = new SyntaxHighlighter(ui->textEdit->document());
+    ui->textEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
+    sh = std::make_unique<SyntaxHighlighter>(ui->textEdit->document());
 
-    ui->actionOpen_2->connect(ui->actionOpen_2, &QAction::triggered, this, &BrainyWindow::openFile);
-    ui->actionSave_2->connect(ui->actionSave_2, &QAction::triggered, this, &BrainyWindow::saveFile);
+    ui->actionOpen->connect(ui->actionOpen, &QAction::triggered, this, &BrainyWindow::openFile);
+    ui->actionSave->connect(ui->actionSave, &QAction::triggered, this, &BrainyWindow::saveFile);
+    ui->actionSave_As->connect(ui->actionSave_As, &QAction::triggered, this, &BrainyWindow::saveFileAs);
     ui->actionEditor_Font->connect(ui->actionEditor_Font, &QAction::triggered, this, [this] () {
         bool ok;
         QFont font = QFontDialog::getFont(&ok, ui->textEdit->font(), this);
@@ -26,30 +30,68 @@ BrainyWindow::BrainyWindow(QWidget *parent) :
 
 BrainyWindow::~BrainyWindow()
 {
-    delete ui;
 }
 
 
 void BrainyWindow::openFile()
 {
+    /*auto dialog = std::make_unique<QFileDialog>(this, tr("Open File"), "", tr("Brainfuck File (*.bf);; Any File (*.*)"));
+    dialog->show();*/
+
     auto filename = QFileDialog::getOpenFileName(this,
         tr("Open File"), "", tr("Brainfuck File (*.bf);; Any File (*.*)"));
-    openedFile = new QFile(filename);
-    if (!openedFile->open(QIODevice::ReadWrite | QFile::Text)) return;
-    QTextStream in(openedFile);
+    if (filename == "")
+        return;
+
+    QFileInfo fileInfo(filename);
+    if (!fileInfo.exists()) {
+        QMessageBox::critical(this, "Error opening file", "File does not exist");
+    }
+
+    openedFile = std::make_unique<QFile>(filename);
+    if (!openedFile->open(QIODevice::ReadOnly | QFile::Text)) {
+        QMessageBox::critical(this, "Error opening file", "Could not open file");
+        return;
+    }
+    QTextStream in(openedFile.get());
     ui->textEdit->setText(in.readAll());
 }
 
 
 void BrainyWindow::saveFile()
 {
-    if (!openedFile->isOpen()) {
-        openedFile->open(QIODevice::WriteOnly | QFile::Text | QFile::Truncate);
+    if (!openedFile) {
+        auto filename = QFileDialog::getSaveFileName(this,
+            tr("Save File"), "", tr("Brainfuck File (*.bf);; Any File (*.*)"));
+        if (filename == "")
+            return;
+        openedFile = std::make_unique<QFile>(filename);
     }
-    if (openedFile->isOpen()) {
-        openedFile->write(ui->textEdit->document()->toPlainText().toUtf8().data());
+    if (openedFile) {
+        if (openedFile->isOpen() && !openedFile->isWritable()) {
+            openedFile->close();
+        }
+        if (!openedFile->isOpen()) {
+            openedFile->open(QIODevice::WriteOnly | QFile::Text | QFile::Truncate);
+        }
+        if (openedFile->isOpen()) {
+            openedFile->write(ui->textEdit->document()->toPlainText().toUtf8().data());
+            openedFile->close();
+        }
+        else {
+            QMessageBox::critical(this, "Error saving file", "Could not open file to save");
+        }
+    }
+}
+
+
+void BrainyWindow::saveFileAs()
+{
+    if (openedFile) {
         openedFile->close();
+        openedFile.reset(nullptr);
     }
+    saveFile();
 }
 
 

+ 5 - 3
brainywindow.h

@@ -3,6 +3,7 @@
 
 #include <QMainWindow>
 #include "syntaxhighlighter.h"
+#include <memory>
 
 namespace Ui
 {
@@ -18,14 +19,15 @@ public:
     ~BrainyWindow();
 
     bool changedAnything;
-    QFile* openedFile;
+    std::unique_ptr<QFile> openedFile;
     void openFile();
     void saveFile();
+    void saveFileAs();
     bool changesToSave() const;
 
 private:
-    Ui::BrainyWindow* ui;
-    SyntaxHighlighter* sh;
+    std::unique_ptr<Ui::BrainyWindow> ui;
+    std::unique_ptr<SyntaxHighlighter> sh;
 };
 
 #endif // EDITORWINDOW_H

+ 18 - 18
brainywindow.ui

@@ -14,7 +14,8 @@
    <string>Brainy</string>
   </property>
   <property name="windowIcon">
-   <iconset theme="document-new"/>
+   <iconset theme="document-new">
+    <normaloff>.</normaloff>.</iconset>
   </property>
   <widget class="QWidget" name="centralWidget">
    <layout class="QVBoxLayout" name="verticalLayout">
@@ -22,7 +23,7 @@
      <widget class="QTextEdit" name="textEdit">
       <property name="font">
        <font>
-        <family>Courier New</family>
+        <family>Courier</family>
         <pointsize>10</pointsize>
        </font>
       </property>
@@ -33,8 +34,8 @@
        <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
 &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
 p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Courier New'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Courier'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New';&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
       </property>
       <property name="acceptRichText">
        <bool>false</bool>
@@ -49,7 +50,7 @@ p, li { white-space: pre-wrap; }
      <x>0</x>
      <y>0</y>
      <width>1091</width>
-     <height>21</height>
+     <height>28</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
@@ -58,8 +59,9 @@ p, li { white-space: pre-wrap; }
     </property>
     <addaction name="actionNew_File"/>
     <addaction name="separator"/>
-    <addaction name="actionOpen_2"/>
-    <addaction name="actionSave_2"/>
+    <addaction name="actionOpen"/>
+    <addaction name="actionSave"/>
+    <addaction name="actionSave_As"/>
    </widget>
    <widget class="QMenu" name="menuOptions">
     <property name="title">
@@ -84,23 +86,13 @@ p, li { white-space: pre-wrap; }
   </action>
   <action name="actionOpen">
    <property name="text">
-    <string>Open</string>
-   </property>
-  </action>
-  <action name="actionSave">
-   <property name="text">
-    <string>Save</string>
-   </property>
-  </action>
-  <action name="actionOpen_2">
-   <property name="text">
     <string>&amp;Open</string>
    </property>
    <property name="shortcut">
     <string>Ctrl+O</string>
    </property>
   </action>
-  <action name="actionSave_2">
+  <action name="actionSave">
    <property name="text">
     <string>&amp;Save</string>
    </property>
@@ -113,6 +105,14 @@ p, li { white-space: pre-wrap; }
     <string>Editor Font</string>
    </property>
   </action>
+  <action name="actionSave_As">
+   <property name="text">
+    <string>Save &amp;As</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+S</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <resources/>

+ 36 - 24
syntaxhighlighter.cpp

@@ -1,25 +1,29 @@
 #include "syntaxhighlighter.h"
-#include <set>
 
 SyntaxHighlighter::SyntaxHighlighter(QTextDocument *parent) :
     QSyntaxHighlighter(parent)
 {
+    // TODO: export into config
     levelColor.push_back(QTextCharFormat());
     levelColor.push_back(QTextCharFormat());
     levelColor.push_back(QTextCharFormat());
     levelColor.push_back(QTextCharFormat());
     levelColor.push_back(QTextCharFormat());
     levelColor.push_back(QTextCharFormat());
-    levelColor[0].setForeground(Qt::blue);
-    levelColor[1].setForeground(Qt::red);
-    levelColor[2].setForeground(Qt::darkGreen);
-    levelColor[3].setForeground(Qt::darkRed);
-    levelColor[4].setForeground(Qt::darkYellow);
+    levelColor[0].setForeground(Qt::cyan);
+    levelColor[1].setForeground(Qt::darkGreen);
+    levelColor[2].setForeground(Qt::darkRed);
+    levelColor[3].setForeground(Qt::darkYellow);
+    levelColor[4].setForeground(Qt::magenta);
     levelColor[5].setForeground(Qt::green);
     for (auto& tcf : levelColor) {
         tcf.setFontWeight(99);
     }
     comment.setForeground(Qt::gray);
+
+    error.setForeground(Qt::red);
+    error.setFontItalic(true);
+    error.setFontWeight(99);
 }
 
 
@@ -50,35 +54,32 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
         }
     };
 
+    const int INVALID_LEVEL = -2;
     int level = previousBlockState();
-    if (level < 0) level = 0;
+
+    // if uninitialized set to zero
+    if (level == -1) level = 0;
     FormatState fs(this);
     for (int i = 0; i < text.length(); i++) {
         auto& c = text[i];
-        if (c == '[') {
+        if (c == '[' && level >= 0) {
             level++;
         }
         if (isBfChar(c)) {
-            fs.upateFormat(1, &levelColor[level % levelColor.size()]);
+            if (level < 0 || (level == 0 && c == ']')) {
+                fs.upateFormat(1, &error);
+                level = INVALID_LEVEL;
+            }
+            else {
+                fs.upateFormat(1, &levelColor[level % levelColor.size()]);
+            }
         }
         else {
             fs.upateFormat(1, &comment);
         }
-        if (c == ']') {
+        if (c == ']' && level != INVALID_LEVEL) {
             level--;
         }
-        /*if (c == '[') {
-            level++;
-        }
-        if (isBfChar(c)) {
-            setFormat(i, 1, levelColor[level % levelColor.size()]);
-        }
-        else {
-            setFormat(i, 1, comment);
-        }
-        if (c == ']') {
-            level--;
-        }*/
     }
     fs.finish();
     setCurrentBlockState(level);
@@ -87,6 +88,17 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
 
 bool SyntaxHighlighter::isBfChar(const QChar& c)
 {
-    static const std::set<QChar> x{'+', '-', '<', '>', ',', '.', '[', ']'};
-    return x.find(c) != x.end();
+    switch (c.unicode()) {
+    case '+':
+    case '-':
+    case '<':
+    case '>':
+    case ',':
+    case '.':
+    case '[':
+    case ']':
+        return true;
+    default:
+        return false;
+    }
 }

+ 1 - 0
syntaxhighlighter.h

@@ -30,6 +30,7 @@ private:
      */
     std::vector<QTextCharFormat> levelColor;
     QTextCharFormat comment;
+    QTextCharFormat error;
 
     bool isBfChar(const QChar& c);
 };