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 "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <QContextMenuEvent>
00027 # include <QMenu>
00028 # include <QShortcut>
00029 # include <QTextCursor>
00030 #endif
00031
00032 #include "PythonEditor.h"
00033 #include "Application.h"
00034 #include "BitmapFactory.h"
00035 #include "FileDialog.h"
00036 #include "DlgEditorImp.h"
00037
00038 #include <Base/Interpreter.h>
00039 #include <Base/Exception.h>
00040 #include <Base/Parameter.h>
00041
00042 using namespace Gui;
00043
00044 namespace Gui {
00045 struct PythonEditorP
00046 {
00047 QMap<QString, QColor> colormap;
00048 PythonEditorP()
00049 {
00050 colormap[QLatin1String("Text")] = Qt::black;
00051 colormap[QLatin1String("Bookmark")] = Qt::cyan;
00052 colormap[QLatin1String("Breakpoint")] = Qt::red;
00053 colormap[QLatin1String("Keyword")] = Qt::blue;
00054 colormap[QLatin1String("Comment")] = QColor(0, 170, 0);
00055 colormap[QLatin1String("Block comment")] = QColor(160, 160, 164);
00056 colormap[QLatin1String("Number")] = Qt::blue;
00057 colormap[QLatin1String("String")] = Qt::red;
00058 colormap[QLatin1String("Character")] = Qt::red;
00059 colormap[QLatin1String("Class name")] = QColor(255, 170, 0);
00060 colormap[QLatin1String("Define name")] = QColor(255, 170, 0);
00061 colormap[QLatin1String("Operator")] = QColor(160, 160, 164);
00062 colormap[QLatin1String("Python output")] = QColor(170, 170, 127);
00063 colormap[QLatin1String("Python error")] = Qt::red;
00064 colormap[QLatin1String("Line")] = QColor(224,224,224);
00065 }
00066 };
00067 }
00068
00069
00070
00075 PythonEditor::PythonEditor(QWidget* parent)
00076 : TextEditor(parent)
00077 {
00078 d = new PythonEditorP();
00079 this->setSyntaxHighlighter(new PythonSyntaxHighlighter(this));
00080
00081
00082 QShortcut* comment = new QShortcut(this);
00083 comment->setKey(Qt::ALT + Qt::Key_C);
00084
00085 QShortcut* uncomment = new QShortcut(this);
00086 uncomment->setKey(Qt::ALT + Qt::Key_U);
00087
00088 connect(comment, SIGNAL(activated()),
00089 this, SLOT(onComment()));
00090 connect(uncomment, SIGNAL(activated()),
00091 this, SLOT(onUncomment()));
00092 }
00093
00095 PythonEditor::~PythonEditor()
00096 {
00097 getWindowParameter()->Detach( this );
00098 delete d;
00099 }
00100
00101 void PythonEditor::drawMarker(int line, int x, int y, QPainter* p)
00102 {
00103 #if 0
00104 Breakpoint bp = _dbg->getBreakpoint(fileName());
00105 if (bp.checkLine(line)) {
00106 p->drawPixmap(x, y, breakpoint);
00107 }
00108 if (m_debugLine == line) {
00109 p->drawPixmap(x, y+2, debugMarker);
00110 debugRect = QRect(x, y+2, debugMarker.width(), debugMarker.height());
00111 }
00112 #endif
00113 }
00114
00115 void PythonEditor::contextMenuEvent ( QContextMenuEvent * e )
00116 {
00117 QMenu* menu = createStandardContextMenu();
00118 menu->addSeparator();
00119 menu->addAction( tr("Comment"), this, SLOT( onComment() ), Qt::ALT + Qt::Key_C );
00120 menu->addAction( tr("Uncomment"), this, SLOT( onUncomment() ), Qt::ALT + Qt::Key_U );
00121
00122 menu->exec(e->globalPos());
00123 delete menu;
00124 }
00125
00126 void PythonEditor::onComment()
00127 {
00128 QTextCursor cursor = textCursor();
00129 int selStart = cursor.selectionStart();
00130 int selEnd = cursor.selectionEnd();
00131 QTextBlock block;
00132 cursor.beginEditBlock();
00133 for (block = document()->begin(); block.isValid(); block = block.next()) {
00134 int pos = block.position();
00135 int off = block.length()-1;
00136
00137 if ( pos >= selStart || pos+off >= selStart) {
00138 if ( pos+1 > selEnd )
00139 break;
00140 cursor.setPosition(block.position());
00141 cursor.insertText(QLatin1String("#"));
00142 selEnd++;
00143 }
00144 }
00145
00146 cursor.endEditBlock();
00147 }
00148
00149 void PythonEditor::onUncomment()
00150 {
00151 QTextCursor cursor = textCursor();
00152 int selStart = cursor.selectionStart();
00153 int selEnd = cursor.selectionEnd();
00154 QTextBlock block;
00155 cursor.beginEditBlock();
00156 for (block = document()->begin(); block.isValid(); block = block.next()) {
00157 int pos = block.position();
00158 int off = block.length()-1;
00159
00160 if ( pos >= selStart || pos+off >= selStart) {
00161 if ( pos+1 > selEnd )
00162 break;
00163 if (block.text().startsWith(QLatin1String("#"))) {
00164 cursor.setPosition(block.position());
00165 cursor.deleteChar();
00166 selEnd--;
00167 }
00168 }
00169 }
00170
00171 cursor.endEditBlock();
00172 }
00173
00174
00175
00176 namespace Gui {
00177 class PythonSyntaxHighlighterP
00178 {
00179 public:
00180 PythonSyntaxHighlighterP()
00181 {
00182 keywords << QLatin1String("and") << QLatin1String("as")
00183 << QLatin1String("assert")
00184 << QLatin1String("break") << QLatin1String("class")
00185 << QLatin1String("continue") << QLatin1String("def")
00186 << QLatin1String("del") << QLatin1String("elif")
00187 << QLatin1String("else") << QLatin1String("except")
00188 << QLatin1String("exec") << QLatin1String("finally")
00189 << QLatin1String("for") << QLatin1String("from")
00190 << QLatin1String("global") << QLatin1String("if")
00191 << QLatin1String("import") << QLatin1String("in")
00192 << QLatin1String("is") << QLatin1String("lambda")
00193 << QLatin1String("None") << QLatin1String("not")
00194 << QLatin1String("or") << QLatin1String("pass")
00195 << QLatin1String("print") << QLatin1String("raise")
00196 << QLatin1String("return") << QLatin1String("try")
00197 << QLatin1String("while") << QLatin1String("yield");
00198 }
00199
00200 QStringList keywords;
00201 };
00202 }
00203
00207 PythonSyntaxHighlighter::PythonSyntaxHighlighter(QObject* parent)
00208 : SyntaxHighlighter(parent)
00209 {
00210 d = new PythonSyntaxHighlighterP;
00211 }
00212
00214 PythonSyntaxHighlighter::~PythonSyntaxHighlighter()
00215 {
00216 delete d;
00217 }
00218
00222 void PythonSyntaxHighlighter::highlightBlock (const QString & text)
00223 {
00224 int i = 0;
00225 QChar prev, ch;
00226
00227 const int Standard = 0;
00228 const int Digit = 1;
00229 const int Comment = 2;
00230 const int Literal1 = 3;
00231 const int Literal2 = 4;
00232 const int Blockcomment1 = 5;
00233 const int Blockcomment2 = 6;
00234 const int ClassName = 7;
00235 const int DefineName = 8;
00236
00237 int endStateOfLastPara = previousBlockState();
00238 if (endStateOfLastPara < 0 || endStateOfLastPara > maximumUserState())
00239 endStateOfLastPara = Standard;
00240
00241 while ( i < text.length() )
00242 {
00243 ch = text.at( i );
00244
00245 switch ( endStateOfLastPara )
00246 {
00247 case Standard:
00248 {
00249 switch ( ch.unicode() )
00250 {
00251 case '#':
00252 {
00253
00254 setFormat( i, 1, this->colorByType(SyntaxHighlighter::Comment));
00255 endStateOfLastPara=Comment;
00256 } break;
00257 case '"':
00258 {
00259
00260 if ((i>=2) && text.at(i-1) == QLatin1Char('"') &&
00261 text.at(i-2) == QLatin1Char('"'))
00262 {
00263 setFormat( i-2, 3, this->colorByType(SyntaxHighlighter::BlockComment));
00264 endStateOfLastPara=Blockcomment1;
00265 }
00266 else
00267 {
00268 setFormat( i, 1, this->colorByType(SyntaxHighlighter::String));
00269 endStateOfLastPara=Literal1;
00270 }
00271 } break;
00272 case '\'':
00273 {
00274
00275 if ((i>=2) && text.at(i-1) == QLatin1Char('\'') &&
00276 text.at(i-2) == QLatin1Char('\''))
00277 {
00278 setFormat( i-2, 3, this->colorByType(SyntaxHighlighter::BlockComment));
00279 endStateOfLastPara=Blockcomment2;
00280 }
00281 else
00282 {
00283 setFormat( i, 1, this->colorByType(SyntaxHighlighter::String));
00284 endStateOfLastPara=Literal2;
00285 }
00286 } break;
00287 case ' ':
00288 case '\t':
00289 {
00290
00291 } break;
00292 case '(': case ')': case '[': case ']':
00293 case '+': case '-': case '*': case '/':
00294 case ':': case '%': case '^': case '~':
00295 case '!': case '=': case '<': case '>':
00296 {
00297 setFormat(i, 1, this->colorByType(SyntaxHighlighter::Operator));
00298 endStateOfLastPara=Standard;
00299 } break;
00300 default:
00301 {
00302
00303 if ( ch.isLetter() || ch == QLatin1Char('_') )
00304 {
00305 QString buffer;
00306 int j=i;
00307 while ( ch.isLetterOrNumber() || ch == QLatin1Char('_') ) {
00308 buffer += ch;
00309 ++j;
00310 if (j >= text.length())
00311 break;
00312 ch = text.at(j);
00313 }
00314
00315 if ( d->keywords.contains( buffer ) != 0 ) {
00316 if ( buffer == QLatin1String("def"))
00317 endStateOfLastPara = DefineName;
00318 else if ( buffer == QLatin1String("class"))
00319 endStateOfLastPara = ClassName;
00320
00321 QTextCharFormat keywordFormat;
00322 keywordFormat.setForeground(this->colorByType(SyntaxHighlighter::Keyword));
00323 keywordFormat.setFontWeight(QFont::Bold);
00324 setFormat( i, buffer.length(), keywordFormat);
00325 }
00326 else {
00327 setFormat( i, buffer.length(),this->colorByType(SyntaxHighlighter::Text));
00328 }
00329
00330
00331 if ( !buffer.isEmpty() )
00332 i = j-1;
00333 }
00334
00335 else if ( ch.isDigit() )
00336 {
00337 setFormat(i, 1, this->colorByType(SyntaxHighlighter::Number));
00338 endStateOfLastPara=Digit;
00339 }
00340
00341 else if ( ch.isSymbol() || ch.isPunct() )
00342 {
00343 setFormat( i, 1, this->colorByType(SyntaxHighlighter::Operator));
00344 }
00345 }
00346 }
00347 } break;
00348 case Comment:
00349 {
00350 setFormat( i, 1, this->colorByType(SyntaxHighlighter::Comment));
00351 } break;
00352 case Literal1:
00353 {
00354 setFormat( i, 1, this->colorByType(SyntaxHighlighter::String));
00355 if ( ch == QLatin1Char('"') )
00356 endStateOfLastPara = Standard;
00357 } break;
00358 case Literal2:
00359 {
00360 setFormat( i, 1, this->colorByType(SyntaxHighlighter::String));
00361 if ( ch == QLatin1Char('\'') )
00362 endStateOfLastPara = Standard;
00363 } break;
00364 case Blockcomment1:
00365 {
00366 setFormat( i, 1, this->colorByType(SyntaxHighlighter::BlockComment));
00367 if ( i>=2 && ch == QLatin1Char('"') &&
00368 text.at(i-1) == QLatin1Char('"') &&
00369 text.at(i-2) == QLatin1Char('"'))
00370 endStateOfLastPara = Standard;
00371 } break;
00372 case Blockcomment2:
00373 {
00374 setFormat( i, 1, this->colorByType(SyntaxHighlighter::BlockComment));
00375 if ( i>=2 && ch == QLatin1Char('\'') &&
00376 text.at(i-1) == QLatin1Char('\'') &&
00377 text.at(i-2) == QLatin1Char('\''))
00378 endStateOfLastPara = Standard;
00379 } break;
00380 case DefineName:
00381 {
00382 if ( ch.isLetterOrNumber() || ch == QLatin1Char(' ') || ch == QLatin1Char('_') )
00383 {
00384 setFormat( i, 1, this->colorByType(SyntaxHighlighter::Defname));
00385 }
00386 else
00387 {
00388 if ( ch.isSymbol() || ch.isPunct() )
00389 setFormat(i, 1, this->colorByType(SyntaxHighlighter::Operator));
00390 endStateOfLastPara = Standard;
00391 }
00392 } break;
00393 case ClassName:
00394 {
00395 if ( ch.isLetterOrNumber() || ch == QLatin1Char(' ') || ch == QLatin1Char('_') )
00396 {
00397 setFormat( i, 1, this->colorByType(SyntaxHighlighter::Classname));
00398 }
00399 else
00400 {
00401 if (ch.isSymbol() || ch.isPunct() )
00402 setFormat( i, 1, this->colorByType(SyntaxHighlighter::Operator));
00403 endStateOfLastPara = Standard;
00404 }
00405 } break;
00406 case Digit:
00407 {
00408 if (ch.isDigit() || ch == QLatin1Char('.'))
00409 {
00410 setFormat( i, 1, this->colorByType(SyntaxHighlighter::Number));
00411 }
00412 else
00413 {
00414 if ( ch.isSymbol() || ch.isPunct() )
00415 setFormat( i, 1, this->colorByType(SyntaxHighlighter::Operator));
00416 endStateOfLastPara = Standard;
00417 }
00418 }break;
00419 }
00420
00421 prev = ch;
00422 i++;
00423 }
00424
00425
00426 if ( endStateOfLastPara != Blockcomment1 && endStateOfLastPara != Blockcomment2 )
00427 {
00428 endStateOfLastPara = Standard ;
00429 }
00430
00431 setCurrentBlockState(endStateOfLastPara);
00432 }
00433
00434 #include "moc_PythonEditor.cpp"