Source

pynoto / src / PythonEditor / PythonEditorWidget.cpp

Full commit
#include <QDebug>
#include <QPainter>
#include <QPaintEvent>
#include <QIcon>
#include <math.h>
#include <QTextBlock>
#include "PythonEditorWidget.h"
#include "PythonCompliter.h"
#include "Include/IIconProvider.h"
#include "Include/PynotoApplication.h"
#include "ErrorModel.h"
#include "Settings.h"
#include "PythonDocumentLayout.h"
#include "Highlighter.h"

namespace PythonEditor {

PythonEditorWidget::PythonEditorWidget(const QString& fileName, bool sample, QWidget* parent):
    TextEditor::TextEditorWidget(fileName, parent),
    _compliter(NULL),
    _errorListModel(NULL),
    _isSample(sample)
{
    setMouseTracking(true);
    document()->setDocumentLayout(new PythonDocumentLayout(document()));
    _updateErrorsTimer.setSingleShot(true);
    _updateErrorsTimer.setInterval(500);
    _updateErrorsTimer.stop();
    if (!_isSample){
        connect(&_updateErrorsTimer, SIGNAL(timeout()), SLOT(checkIssues()));
    }
    Settings set;
    _showIdent = set.showIndentLine();
    _identColor = set.identColor();
}

void PythonEditorWidget::editorLoaded()
{
    connect(document(), SIGNAL(contentsChanged()), SLOT(onTextChanged()));
    _compliter = new PythonCompliter(this);
    if (!_isSample)
        _compliter->checkErrors();
}

TextEditor::Highlighter* PythonEditorWidget::hightlighter()
{
    return new PythonEditor::Highlighter(document(), "python");
}

void PythonEditorWidget::paintEvent(QPaintEvent *event)
{
    TextEditorWidget::paintEvent(event);

    if (_showIdent){
        QPainter painter(viewport());
        //painter.setRenderHint(QPainter::HighQualityAntialiasing);
        QPen pen(Qt::DotLine);
        pen.setColor(_identColor);
        pen.setCapStyle(Qt::RoundCap);
        painter.setPen(pen);

        QTextBlock block = firstVisibleBlock();

        QPointF offset(contentOffset());

        int whiteWidth = viewport()->fontMetrics().width(' ');
        int x = contentsRect().left()+offset.x()+2;
        PythonDocumentLayout *lay = qobject_cast<PythonDocumentLayout*>(document()->documentLayout());

        while (block.isValid()) {
            if (block.isVisible()) {
                for (int i = 1; i < round(lay->spaces(block)/4)+(lay->spaces(block) % 4 > 0 ? 1 : 0); ++i) {
                    int top = (int)blockBoundingGeometry(block).translated(offset).top();
                    int bottom = top + (int)blockBoundingRect(block).height();
                    painter.drawLine(x+4*whiteWidth*i, top, x+4*whiteWidth*i, bottom);
                }
            }
            block = block.next();
        }
    }
}

void PythonEditorWidget::keyPressEvent(QKeyEvent *e)
{
    if (_compliter->isVisible()){
        switch (e->key()) {
        case Qt::Key_Enter:
        case Qt::Key_Return:
        case Qt::Key_Escape:
        case Qt::Key_Tab:
        case Qt::Key_Backtab:
             e->ignore();
             return;
        default:
            break;
        }
    }
    if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return){
        if (e->modifiers() != Qt::ShiftModifier){
            autoIndentNewLine();
            e->accept();
            return;
        }
    }
    if (e->key() == Qt::Key_Space && e->modifiers() == Qt::CTRL){
        _compliter->showComplit(textCursor().position());
    }
    if (e->key() == Qt::Key_Escape){
        _compliter->hide();
    }
    TextEditorWidget::keyPressEvent(e);
}

void PythonEditorWidget::autoIndentNewLine()
{
    PythonDocumentLayout *lay = qobject_cast<PythonDocumentLayout*>(document()->documentLayout());
    QTextCursor cur = textCursor();
    QTextBlock curBlock = cur.block();
    cur.beginEditBlock();
    cur.insertBlock();
    int indent = lay->foldingIndent(curBlock);
    if  (
        curBlock.text().trimmed().endsWith(":") ||
        curBlock.text().trimmed().endsWith("(") ||
        curBlock.text().trimmed().endsWith("[") ||
        curBlock.text().trimmed().endsWith("{")
        )
        indent++;
    cur.insertText(QString(indent*4, ' '));
    cur.endEditBlock();
}

void PythonEditorWidget::setErrors(const QList<PythonCode::IPythonCode::ErrorItem>& items)
{
    clearMarks();
    foreach(PythonCode::IPythonCode::ErrorItem it, items){
        QString icoName;
        if (it.severity == PythonCode::IPythonCode::Error)
            icoName = "error";
        if (it.severity == PythonCode::IPythonCode::Warning)
            icoName = "warning";
        if (it.severity == PythonCode::IPythonCode::CodeStyle)
            icoName = "codestyle";
        if (it.severity == PythonCode::IPythonCode::Suggestion)
            icoName = "suggestion";
        setMark(it.line, Aux::icons()->icon(icoName), it.message);
    }
    _errorListModel = new ErrorModel(items, this);
    emit errorListChanged(_errorListModel);
}

QAbstractTableModel* PythonEditorWidget::errorListModel()
{
    return _errorListModel;
}

bool PythonEditorWidget::reset()
{
    _compliter->hide();
    return false;
}

void PythonEditorWidget::checkIssues()
{
    if (!_isSample)
        _compliter->checkErrors();
}

void PythonEditorWidget::preferencesChanged(const QString& what)
{
    TextEditorWidget::preferencesChanged(what);
    if (what == "show-ident-line"){
        Settings set;
        _showIdent = set.showIndentLine();
        update();
    }
    if (what == "ident-color"){
        Settings set;
        _identColor = set.identColor();
        update();
    }
}

void PythonEditorWidget::onTextChanged()
{
    _updateErrorsTimer.start();
}

}