#include "qgpyeditdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 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(""); 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(""); //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()<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; }