00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "AeslEditor.h"
00025 #include <QtGui>
00026
00027 #include <AeslEditor.moc>
00028
00029 namespace Aseba
00030 {
00033
00034 AeslHighlighter::AeslHighlighter(AeslEditor *editor, QTextDocument *parent) :
00035 QSyntaxHighlighter(parent),
00036 editor(editor)
00037 {
00038 HighlightingRule rule;
00039
00040
00041 QTextCharFormat keywordFormat;
00042 keywordFormat.setForeground(Qt::darkRed);
00043 QStringList keywordPatterns;
00044 keywordPatterns << "\\bemit\\b" << "\\bwhile\\b" << "\\bdo\\b"
00045 << "\\bfor\\b" << "\\bin\\b" << "\\bstep\\b"
00046 << "\\bif\\b" << "\\bthen\\b" << "\\belse\\b" << "\\belseif\\b"
00047 << "\\bend\\b" << "\\bvar\\b" << "\\bcall\\b"
00048 << "\\bonevent\\b" << "\\bontimer\\b" << "\\bwhen\\b"
00049 << "\\band\\b" << "\\bor\\b" << "\\bnot\\b"
00050 << "\\bsub\\b" << "\\bcallsub\\b";
00051 foreach (QString pattern, keywordPatterns)
00052 {
00053 rule.pattern = QRegExp(pattern);
00054 rule.format = keywordFormat;
00055 highlightingRules.append(rule);
00056 }
00057
00058
00059 QTextCharFormat literalsFormat;
00060 literalsFormat.setForeground(Qt::darkBlue);
00061 rule.pattern = QRegExp("\\b(-{0,1}\\d+|0x([0-9]|[a-f]|[A-F])+|0b[0-1]+)\\b");
00062 rule.format = literalsFormat;
00063 highlightingRules.append(rule);
00064
00065
00066 QTextCharFormat commentFormat;
00067 commentFormat.setForeground(Qt::gray);
00068 rule.pattern = QRegExp("#[^\n]*");
00069 rule.format = commentFormat;
00070 highlightingRules.append(rule);
00071
00072
00073 QTextCharFormat todoFormat;
00074 todoFormat.setForeground(Qt::black);
00075 todoFormat.setBackground(QColor(255, 192, 192));
00076 rule.pattern = QRegExp("#.*(\\bTODO\\b|\\bFIXME\\b).*");
00077 rule.format = todoFormat;
00078 highlightingRules.append(rule);
00079 }
00080
00081 void AeslHighlighter::highlightBlock(const QString &text)
00082 {
00083 AeslEditorUserData *uData = static_cast<AeslEditorUserData *>(currentBlockUserData());
00084
00085
00086 bool isActive = uData && uData->properties.contains("active");
00087 bool isExecutionError = uData && uData->properties.contains("executionError");
00088 bool isBreakpointPending = uData && uData->properties.contains("breakpointPending");
00089 bool isBreakpoint = uData && uData->properties.contains("breakpoint");
00090
00091 QColor breakpointPendingColor(255, 240, 178);
00092 QColor breakpointColor(255, 211, 178);
00093 QColor activeColor(220, 220, 255);
00094 QColor errorColor(240, 100, 100);
00095
00096 if (isBreakpointPending)
00097 {
00098 QTextCharFormat format;
00099 format.setBackground(breakpointPendingColor);
00100 setFormat(0, text.length(), format);
00101 }
00102 if (isBreakpoint)
00103 {
00104 QTextCharFormat format;
00105
00106 format.setBackground(breakpointColor);
00107 setFormat(0, text.length(), format);
00108 }
00109 if (editor->debugging)
00110 {
00111 if (isActive)
00112 {
00113 QTextCharFormat format;
00114 format.setBackground(activeColor);
00115 setFormat(0, text.length(), format);
00116 }
00117 if (isExecutionError)
00118 {
00119 QTextCharFormat format;
00120 format.setBackground(errorColor);
00121 setFormat(0, text.length(), format);
00122 }
00123 }
00124
00125
00126 foreach (HighlightingRule rule, highlightingRules)
00127 {
00128 QRegExp expression(rule.pattern);
00129 int index = text.indexOf(expression);
00130 while (index >= 0)
00131 {
00132 int length = expression.matchedLength();
00133 QTextCharFormat format = rule.format;
00134
00135 if (isBreakpointPending)
00136 format.setBackground(breakpointPendingColor);
00137 if (isBreakpoint)
00138 format.setBackground(breakpointColor);
00139 if (editor->debugging)
00140 {
00141 if (isActive)
00142 format.setBackground(activeColor);
00143 if (isExecutionError)
00144 format.setBackground(errorColor);
00145 }
00146
00147 setFormat(index, length, format);
00148 index = text.indexOf(expression, index + length);
00149 }
00150 }
00151
00152
00153 if (uData && uData->properties.contains("errorPos"))
00154 {
00155 int pos = uData->properties["errorPos"].toInt();
00156 int len = 0;
00157
00158 if (pos + len < text.length())
00159 {
00160
00161 while (pos + len < text.length())
00162 if (
00163 (!text[pos + len].isDigit()) &&
00164 (!text[pos + len].isLetter()) &&
00165 (text[pos + len] != '_') &&
00166 (text[pos + len] != '.')
00167 )
00168 break;
00169 else
00170 len++;
00171 }
00172 len = len > 0 ? len : 1;
00173 setFormat(pos, len, Qt::red);
00174 }
00175 }
00176
00177 AeslEditor::AeslEditor() :
00178 debugging(false)
00179 {
00180 QFont font;
00181 font.setFamily("");
00182 font.setStyleHint(QFont::TypeWriter);
00183 font.setFixedPitch(true);
00184
00185 setFont(font);
00186 setAcceptDrops(true);
00187 setTabStopWidth( QFontMetrics(font).width(' ') * 4);
00188 }
00189
00190 void AeslEditor::dropEvent(QDropEvent *event)
00191 {
00192 QTextEdit::dropEvent(event);
00193 setFocus(Qt::MouseFocusReason);
00194 }
00195
00196 void AeslEditor::contextMenuEvent ( QContextMenuEvent * e )
00197 {
00198
00199 QMenu *menu = createStandardContextMenu();
00200 if (!isReadOnly())
00201 {
00202 QAction *breakpointAction;
00203 menu->addSeparator();
00204
00205
00206 QTextBlock block = cursorForPosition(e->pos()).block();
00207 AeslEditorUserData *uData = static_cast<AeslEditorUserData *>(block.userData());
00208 bool breakpointPresent = (uData && (uData->properties.contains("breakpoint") || uData->properties.contains("breakpointPending") )) ;
00209
00210
00211 if (breakpointPresent)
00212 breakpointAction = menu->addAction(tr("Clear breakpoint"));
00213 else
00214 breakpointAction = menu->addAction(tr("Set breakpoint"));
00215 QAction *breakpointClearAllAction = menu->addAction(tr("Clear all breakpoints"));
00216
00217
00218 QAction* selectedAction = menu->exec(e->globalPos());
00219
00220
00221 if (selectedAction == breakpointAction)
00222 {
00223
00224 if (breakpointPresent)
00225 {
00226
00227 uData->properties.remove("breakpointPending");
00228 uData->properties.remove("breakpoint");
00229 if (uData->properties.isEmpty())
00230 {
00231
00232 block.setUserData(0);
00233 }
00234 emit breakpointCleared(cursorForPosition(e->pos()).blockNumber());
00235 }
00236 else
00237 {
00238
00239 if (!uData)
00240 {
00241
00242 uData = new AeslEditorUserData("breakpointPending");
00243 block.setUserData(uData);
00244 }
00245 else
00246 uData->properties.insert("breakpointPending", QVariant());
00247 emit breakpointSet(cursorForPosition(e->pos()).blockNumber());
00248 }
00249 }
00250 if (selectedAction == breakpointClearAllAction)
00251 {
00252 for (QTextBlock it = document()->begin(); it != document()->end(); it = it.next())
00253 {
00254 AeslEditorUserData *uData = static_cast<AeslEditorUserData *>(it.userData());
00255 if (uData)
00256 {
00257 uData->properties.remove("breakpoint");
00258 uData->properties.remove("breakpointPending");
00259 }
00260 }
00261 emit breakpointClearedAll();
00262 }
00263 }
00264 else
00265 menu->exec(e->globalPos());
00266 delete menu;
00267 }
00268
00269 void AeslEditor::keyPressEvent(QKeyEvent * event)
00270 {
00271
00272 if ((event->key() == Qt::Key_Tab) && textCursor().hasSelection())
00273 {
00274 QTextCursor cursor(document()->findBlock(textCursor().selectionStart()));
00275
00276 cursor.beginEditBlock();
00277
00278 while (cursor.position() < textCursor().selectionEnd())
00279 {
00280 cursor.movePosition(QTextCursor::StartOfLine);
00281 if (event->modifiers() & Qt::ControlModifier)
00282 {
00283 cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
00284 if (cursor.selectedText() == "\t")
00285 cursor.removeSelectedText();
00286 }
00287 else
00288 cursor.insertText("\t");
00289 cursor.movePosition(QTextCursor::Down);
00290 cursor.movePosition(QTextCursor::EndOfLine);
00291 }
00292
00293 cursor.movePosition(QTextCursor::StartOfLine);
00294 if (event->modifiers() & Qt::ControlModifier)
00295 {
00296 cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
00297 if (cursor.selectedText() == "\t")
00298 cursor.removeSelectedText();
00299 }
00300 else
00301 cursor.insertText("\t");
00302
00303 cursor.endEditBlock();
00304 return;
00305 }
00306
00307
00308 if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
00309 {
00310 QString headingSpace("\n");
00311 const QString &line = textCursor().block().text();
00312 for (size_t i = 0; i < (size_t)line.length(); i++)
00313 {
00314 const QChar c(line[(unsigned)i]);
00315 if (c.isSpace())
00316 headingSpace += c;
00317 else
00318 break;
00319
00320 }
00321 insertPlainText(headingSpace);
00322 }
00323 else
00324 QTextEdit::keyPressEvent(event);
00325
00326 }
00327
00329 };