392 lines
12 KiB
C++
392 lines
12 KiB
C++
#include "qgpyeditdialog.h"
|
|
|
|
#include <QMimeData>
|
|
#include <QUrl>
|
|
|
|
#include <QLineEdit>
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
#include <QToolButton>
|
|
#include <QVBoxLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QFormLayout>
|
|
#include <QDialogButtonBox>
|
|
#include <QPlainTextEdit>
|
|
#include <QTextEdit>
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QSpinBox>
|
|
#include <QFile>
|
|
#include <QTextStream>
|
|
#include <QAction>
|
|
#include <QGroupBox>
|
|
#include <QSyntaxHighlighter>
|
|
|
|
#include "qgpython.h"
|
|
|
|
class Highlighter : public QSyntaxHighlighter
|
|
{
|
|
//Q_OBJECT
|
|
|
|
public:
|
|
Highlighter(QTextDocument *parent = 0):
|
|
QSyntaxHighlighter(parent)
|
|
{
|
|
HighlightingRule rule;
|
|
|
|
keywordFormat.setForeground(Qt::darkBlue);
|
|
keywordFormat.setFontWeight(QFont::Bold);
|
|
QStringList keywordPatterns;
|
|
keywordPatterns << "\\bFalse\\b" << "\\bclas\\b" << "\\bfinally\\b"
|
|
<< "\\breturn\\b" << "\\bNone\\b" << "\\bcontinue\\b"
|
|
<< "\\bfor\\b" << "\\blambda\\b" << "\\btry\\b"
|
|
<< "\\bTrue\\b" << "\\bdef\\b" << "\\bfor\\b"
|
|
<< "\\bis\\b" << "\\bfrom\\b" << "\\bnonlocal\\b"
|
|
<< "\\bwhile\\b" << "\\band\\b" << "\\bglobal\\b"
|
|
<< "\\bnot\\b" << "\\bwith\\b" << "\\bas\\b"
|
|
<< "\\belif\\b" << "\\bor\\b" << "\\byeld\\b"
|
|
<< "\\bassert\\b" << "\\belse\\b" << "\\bimport\\b"
|
|
<< "\\bpass\\b" << "\\bbreak\\b" << "\\bin\\b" << "\\braise\\b" << "\\bif\\b" <<"\\bself\\b";
|
|
foreach (const QString &pattern, keywordPatterns) {
|
|
rule.pattern = QRegularExpression(pattern);
|
|
rule.format = keywordFormat;
|
|
highlightingRules.append(rule);
|
|
}
|
|
classFormat.setFontWeight(QFont::Bold);
|
|
classFormat.setForeground(Qt::darkMagenta);
|
|
rule.pattern = QRegularExpression("\\bQ[A-Za-z]+\\b");
|
|
rule.format = classFormat;
|
|
highlightingRules.append(rule);
|
|
|
|
quotationFormat.setForeground(Qt::darkGreen);
|
|
rule.pattern = QRegularExpression("\".*\"");
|
|
rule.format = quotationFormat;
|
|
highlightingRules.append(rule);
|
|
|
|
functionFormat.setFontItalic(true);
|
|
functionFormat.setForeground(Qt::blue);
|
|
rule.pattern = QRegularExpression("\\b[A-Za-z0-9_]+(?=\\()");
|
|
rule.format = functionFormat;
|
|
highlightingRules.append(rule);
|
|
singleLineCommentFormat.setForeground(Qt::red);
|
|
rule.pattern = QRegularExpression("//[^\n]*");
|
|
rule.format = singleLineCommentFormat;
|
|
highlightingRules.append(rule);
|
|
|
|
multiLineCommentFormat.setForeground(Qt::red);
|
|
|
|
commentStartExpression = QRegularExpression("\"\"\"");
|
|
commentEndExpression = QRegularExpression("\"\"\"");
|
|
}
|
|
|
|
protected:
|
|
void highlightBlock(const QString &text) override
|
|
{
|
|
foreach (const HighlightingRule &rule, highlightingRules) {
|
|
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
|
|
while (matchIterator.hasNext()) {
|
|
QRegularExpressionMatch match = matchIterator.next();
|
|
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
|
|
}
|
|
}
|
|
setCurrentBlockState(0);
|
|
int startIndex = 0;
|
|
if (previousBlockState() != 1)
|
|
startIndex = text.indexOf(commentStartExpression);
|
|
while (startIndex >= 0)
|
|
{
|
|
QRegularExpressionMatch match = commentEndExpression.match(text, startIndex);
|
|
int endIndex = match.capturedStart();
|
|
int commentLength = 0;
|
|
if (endIndex == -1) {
|
|
setCurrentBlockState(1);
|
|
commentLength = text.length() - startIndex;
|
|
} else {
|
|
commentLength = endIndex - startIndex
|
|
+ match.capturedLength();
|
|
}
|
|
setFormat(startIndex, commentLength, multiLineCommentFormat);
|
|
startIndex = text.indexOf(commentStartExpression, startIndex + commentLength);
|
|
}
|
|
}
|
|
private:
|
|
struct HighlightingRule
|
|
{
|
|
QRegularExpression pattern;
|
|
QTextCharFormat format;
|
|
};
|
|
QVector<HighlightingRule> highlightingRules;
|
|
|
|
QRegularExpression commentStartExpression;
|
|
QRegularExpression commentEndExpression;
|
|
|
|
QTextCharFormat keywordFormat;
|
|
QTextCharFormat classFormat;
|
|
QTextCharFormat singleLineCommentFormat;
|
|
QTextCharFormat multiLineCommentFormat;
|
|
QTextCharFormat quotationFormat;
|
|
QTextCharFormat functionFormat;
|
|
};
|
|
|
|
class QgPyEditDialog::Implementation
|
|
{
|
|
public:
|
|
//const QMimeData* md;
|
|
|
|
QHBoxLayout* fbox;
|
|
QLineEdit* lblPath;
|
|
QToolButton* btnFile;
|
|
QToolButton* btnEdit;
|
|
|
|
//QLabel* lblContents;
|
|
QTextEdit* txt;
|
|
QVBoxLayout* ly;
|
|
|
|
QLabel* lblMode;
|
|
QComboBox* cbMode;
|
|
|
|
QDialogButtonBox* bbox;
|
|
|
|
QAction* actPreviewOff;
|
|
QAction* actPreviewFull;
|
|
QAction* actPreviewEdit;
|
|
QAction* actDownload;
|
|
|
|
QString fileName;
|
|
QString txtStore;
|
|
|
|
QLineEdit* leRemPattern;
|
|
QCheckBox* cbLinePattern;
|
|
|
|
QGroupBox* boxLineDelay;
|
|
QLabel* lblLineDelay;
|
|
QSpinBox* sbLineDelay;
|
|
QSpinBox* sbCharDelay;
|
|
QLineEdit* lePrompt;
|
|
|
|
//QComboBox* cbEolTranslate;
|
|
Highlighter* highlighter;
|
|
|
|
|
|
void fileMode(bool enable)
|
|
{
|
|
lblPath->setVisible(true); //enable);
|
|
btnFile->setVisible(true); //false);
|
|
btnEdit->setVisible(true); //enable);
|
|
fbox->setEnabled(true); //enable);
|
|
if (!enable)
|
|
fileName.clear();
|
|
}
|
|
|
|
void preview(bool full)
|
|
{
|
|
if (!fileName.isEmpty())
|
|
{
|
|
QFile f(fileName);
|
|
if (f.open(QIODevice::ReadOnly|QIODevice::Text))
|
|
{
|
|
QTextStream in(&f);
|
|
if (full)
|
|
txtStore=in.readAll();
|
|
else
|
|
{
|
|
txtStore=in.read(2048);
|
|
if (f.size()>2048)
|
|
txtStore+="\r\n[...]";
|
|
}
|
|
//p_.lblContents->setVisible(true);
|
|
}
|
|
else
|
|
txtStore="Error reading file: "+f.errorString();
|
|
}
|
|
|
|
txt->setPlainText(txtStore);
|
|
}
|
|
};
|
|
|
|
QgPyEditDialog::QgPyEditDialog(QWidget *parent):
|
|
QDialog(parent, Qt::Tool),
|
|
p_(*new Implementation)
|
|
{
|
|
//File name box:
|
|
p_.fbox=new QHBoxLayout;
|
|
p_.lblPath=new QLineEdit("<path>");
|
|
p_.lblPath->setReadOnly(true);
|
|
p_.lblPath->setDisabled(true);
|
|
p_.btnFile=new QToolButton;
|
|
p_.btnFile->setText("<");
|
|
p_.btnEdit=new QToolButton;
|
|
p_.btnEdit->setText("+");
|
|
p_.btnEdit->setPopupMode(QToolButton::InstantPopup);
|
|
p_.actPreviewOff=new QAction("Small Preview", this);
|
|
p_.actPreviewFull=new QAction("Full Preview", this);
|
|
p_.actPreviewEdit=new QAction("Edit", this);
|
|
//p_.actDownload=new QAction("Download...", this);
|
|
p_.btnEdit->addAction(p_.actPreviewOff);
|
|
p_.btnEdit->addAction(p_.actPreviewFull);
|
|
p_.btnEdit->addAction(p_.actPreviewEdit);
|
|
//p_.btnEdit->addAction(p_.actDownload);
|
|
|
|
p_.fbox->addWidget(p_.lblPath);
|
|
p_.fbox->addWidget(p_.btnFile);
|
|
p_.fbox->addWidget(p_.btnEdit);
|
|
|
|
p_.ly=new QVBoxLayout;
|
|
p_.ly->addLayout(p_.fbox); //lblPath);
|
|
//p_.lblContents=new QLabel("<Contents>");
|
|
//p_.lblContents->setFrameShape(QFrame::Box);
|
|
p_.txt=new QTextEdit;
|
|
p_.txt->setReadOnly(true);
|
|
p_.txt->addAction(p_.actPreviewEdit);
|
|
p_.txt->setContextMenuPolicy(Qt::ActionsContextMenu);
|
|
p_.txt->setVisible(false);
|
|
p_.txt->setAcceptDrops(false);
|
|
p_.ly->addWidget(p_.txt);
|
|
//p_.ly->addWidget(p_.lblContents);
|
|
|
|
p_.highlighter = new Highlighter(p_.txt->document());
|
|
|
|
//p_.lblMode=new QLabel("Mode:");
|
|
#if 0
|
|
QFormLayout* hly=new QFormLayout;
|
|
|
|
p_.cbMode=new QComboBox;
|
|
p_.cbMode->addItems(QStringList()<<"auto"<<"Text"<<"Binary");
|
|
p_.cbMode->setEnabled(true);
|
|
hly->addRow("Mode:", p_.cbMode);
|
|
p_.cbLinePattern=new QCheckBox("Remove:", this);
|
|
p_.leRemPattern=new QLineEdit("-----", this);
|
|
p_.leRemPattern->setEnabled(false);
|
|
connect(p_.cbLinePattern, SIGNAL(toggled(bool)), p_.leRemPattern, SLOT(setEnabled(bool)));
|
|
hly->addRow(p_.cbLinePattern, p_.leRemPattern);
|
|
//hly->addWidget(p_.lblMode);
|
|
//hly->addWidget(p_.cbMode);
|
|
|
|
p_.ly->addLayout(hly);
|
|
|
|
//Line delay
|
|
{
|
|
p_.boxLineDelay=new QGroupBox("Line Control:");
|
|
QVBoxLayout* lyCtrl=new QVBoxLayout;
|
|
QHBoxLayout* lyDelay=new QHBoxLayout;
|
|
p_.lblLineDelay=new QLabel("Char/Line delay (ms)");
|
|
lyDelay->addWidget(p_.lblLineDelay);
|
|
p_.sbCharDelay=new QSpinBox;
|
|
p_.sbCharDelay->setRange(-1, 1000);
|
|
p_.sbCharDelay->setToolTip("<0 = wait for echo with timeout");
|
|
lyDelay->addWidget(p_.sbCharDelay);
|
|
p_.sbLineDelay=new QSpinBox;
|
|
p_.sbLineDelay->setRange(-1, 1000);
|
|
p_.sbLineDelay->setToolTip("<0 = wait for prompt, with timeout");
|
|
lyDelay->addWidget(p_.sbLineDelay);
|
|
p_.lePrompt=new QLineEdit;
|
|
p_.lePrompt->setToolTip("Prompt pettern");
|
|
p_.lePrompt->setPlaceholderText("Prompt");
|
|
lyDelay->addWidget(p_.lePrompt);
|
|
|
|
lyCtrl->addLayout(lyDelay);
|
|
p_.boxLineDelay->setLayout(lyCtrl);
|
|
|
|
p_.ly->addWidget(p_.boxLineDelay);
|
|
}
|
|
#endif
|
|
p_.bbox=new QDialogButtonBox(QDialogButtonBox::Ok
|
|
| QDialogButtonBox::Cancel); //|QDialogButtonBox::Open);
|
|
//p_.bbox->button(QDialogButtonBox::Open)->setText("Execute");
|
|
p_.bbox->button(QDialogButtonBox::Ok)->setText("Execute");
|
|
|
|
p_.ly->addWidget(p_.bbox);
|
|
setLayout(p_.ly);
|
|
|
|
connect(p_.actPreviewEdit, SIGNAL(triggered()), SLOT(previewEdit()));
|
|
connect(p_.actPreviewFull, SIGNAL(triggered()), SLOT(previewFull()));
|
|
connect(p_.actPreviewOff, SIGNAL(triggered()), SLOT(previewSmall()));
|
|
|
|
connect(p_.bbox, SIGNAL(rejected()), SLOT(reject()));
|
|
//connect(p_.bbox, SIGNAL(accepted()), SLOT(accept()));
|
|
connect(p_.bbox, SIGNAL(accepted()), SLOT(executeScript()));
|
|
}
|
|
|
|
QgPyEditDialog::~QgPyEditDialog()
|
|
{
|
|
delete &p_;
|
|
}
|
|
|
|
void QgPyEditDialog::previewSmall()
|
|
{
|
|
p_.txt->setVisible(true);
|
|
p_.preview(false);
|
|
}
|
|
|
|
void QgPyEditDialog::previewFull()
|
|
{
|
|
p_.txt->setVisible(true);
|
|
p_.preview(true);
|
|
}
|
|
|
|
void QgPyEditDialog::previewEdit()
|
|
{
|
|
previewFull();
|
|
p_.txt->setContextMenuPolicy(Qt::DefaultContextMenu);
|
|
p_.txt->setReadOnly(false);
|
|
p_.btnEdit->setEnabled(false);
|
|
p_.fileMode(false);
|
|
//p_.cbMode->setCurrentIndex(1);
|
|
//p_.cbMode->setEnabled(false);
|
|
}
|
|
|
|
void QgPyEditDialog::executeScript()
|
|
{
|
|
QgPython::instance().mainContext().evalScript(p_.txt->toPlainText());
|
|
}
|
|
|
|
void QgPyEditDialog::showFile(const QString& filename)
|
|
{
|
|
QMimeData md;
|
|
md.setUrls(QList<QUrl>()<<QUrl::fromLocalFile(filename));
|
|
setMimeInfo(&md);
|
|
show();
|
|
}
|
|
|
|
void QgPyEditDialog::setMimeInfo(const QMimeData* md)
|
|
{
|
|
//p_.md=md;
|
|
p_.btnEdit->setEnabled(true);
|
|
p_.txt->setReadOnly(true);
|
|
p_.txt->setContextMenuPolicy(Qt::ActionsContextMenu);
|
|
|
|
if (md->hasUrls())
|
|
{
|
|
p_.lblPath->setText(md->urls()[0].fileName());
|
|
p_.fileName=md->urls()[0].toLocalFile();
|
|
p_.txtStore.clear();
|
|
p_.txt->clear();
|
|
p_.txt->setVisible(false);
|
|
p_.fileMode(true);
|
|
}
|
|
else if (md->hasText())
|
|
{
|
|
p_.txtStore=md->text();
|
|
p_.fileMode(false);
|
|
previewFull();
|
|
}
|
|
}
|
|
|
|
QString QgPyEditDialog::text()
|
|
{
|
|
if (!p_.txt->isReadOnly())
|
|
return p_.txt->toPlainText();
|
|
return QString();
|
|
}
|
|
|
|
QString QgPyEditDialog::execFile()
|
|
{
|
|
return p_.fileName;
|
|
}
|
|
|
|
QgPyEditDialog* QgPyEditDialog::singleInstance()
|
|
{
|
|
static QgPyEditDialog dlg;
|
|
return &dlg;
|
|
}
|