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 <QGridLayout>
00027 # include <QApplication>
00028 # include <QMenu>
00029 # include <QContextMenuEvent>
00030 # include <QTextCursor>
00031 # include <QTextStream>
00032 #endif
00033
00034 #include <Base/Interpreter.h>
00035 #include "ReportView.h"
00036 #include "FileDialog.h"
00037 #include "PythonConsole.h"
00038 #include "PythonConsolePy.h"
00039 #include "BitmapFactory.h"
00040
00041 using namespace Gui;
00042 using namespace Gui::DockWnd;
00043
00044
00045
00050 ReportView::ReportView( QWidget* parent )
00051 : QWidget(parent)
00052 {
00053 setObjectName(QLatin1String("ReportOutput"));
00054
00055 resize( 529, 162 );
00056 QGridLayout* tabLayout = new QGridLayout( this );
00057 tabLayout->setSpacing( 0 );
00058 tabLayout->setMargin( 0 );
00059
00060 tabWidget = new QTabWidget( this );
00061 tabWidget->setObjectName(QString::fromUtf8("tabWidget"));
00062 tabWidget->setTabPosition(QTabWidget::South);
00063 tabWidget->setTabShape(QTabWidget::Rounded);
00064 tabLayout->addWidget( tabWidget, 0, 0 );
00065
00066
00067
00068 tabOutput = new ReportOutput();
00069 tabOutput->setWindowTitle(trUtf8("Output"));
00070 tabOutput->setWindowIcon(BitmapFactory().pixmap("MacroEditor"));
00071 int output = tabWidget->addTab(tabOutput, tabOutput->windowTitle());
00072 tabWidget->setTabIcon(output, tabOutput->windowIcon());
00073
00074
00075 tabPython = new PythonConsole();
00076 tabPython->setWordWrapMode(QTextOption::NoWrap);
00077 tabPython->setWindowTitle(trUtf8("Python console"));
00078 tabPython->setWindowIcon(BitmapFactory().pixmap("python_small"));
00079 int python = tabWidget->addTab(tabPython, tabPython->windowTitle());
00080 tabWidget->setTabIcon(python, tabPython->windowIcon());
00081 tabWidget->setCurrentIndex(0);
00082
00083
00084 ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("General");
00085 int index = hGrp->GetInt("AutoloadTab", 0);
00086 tabWidget->setCurrentIndex(index);
00087 }
00088
00092 ReportView::~ReportView()
00093 {
00094
00095 }
00096
00097 void ReportView::changeEvent(QEvent *e)
00098 {
00099 QWidget::changeEvent(e);
00100 if (e->type() == QEvent::LanguageChange) {
00101 tabOutput->setWindowTitle(trUtf8("Output"));
00102 tabPython->setWindowTitle(trUtf8("Python console"));
00103 for (int i=0; i<tabWidget->count();i++)
00104 tabWidget->setTabText(i, tabWidget->widget(i)->windowTitle());
00105 }
00106 }
00107
00108
00109
00110 namespace Gui {
00111 struct TextBlockData : public QTextBlockUserData
00112 {
00113 struct State {
00114 int length;
00115 ReportHighlighter::Paragraph type;
00116 };
00117 QVector<State> block;
00118 };
00119 }
00120
00121 ReportHighlighter::ReportHighlighter(QTextEdit* edit)
00122 : QSyntaxHighlighter(edit), type(Message)
00123 {
00124 txtCol = Qt::black;
00125 logCol = Qt::blue;
00126 warnCol = QColor(255, 170, 0);
00127 errCol = Qt::red;
00128 }
00129
00130 ReportHighlighter::~ReportHighlighter()
00131 {
00132 }
00133
00134 void ReportHighlighter::highlightBlock (const QString & text)
00135 {
00136 if (text.isEmpty())
00137 return;
00138 TextBlockData* ud = static_cast<TextBlockData*>(this->currentBlockUserData());
00139 if (!ud) {
00140 ud = new TextBlockData;
00141 this->setCurrentBlockUserData(ud);
00142 }
00143
00144 TextBlockData::State b;
00145 b.length = text.length();
00146 b.type = this->type;
00147 ud->block.append(b);
00148
00149 QVector<TextBlockData::State> block = ud->block;
00150 int start = 0;
00151 for (QVector<TextBlockData::State>::Iterator it = block.begin(); it != block.end(); ++it) {
00152 switch (it->type)
00153 {
00154 case Message:
00155 setFormat(start, it->length-start, txtCol);
00156 break;
00157 case Warning:
00158 setFormat(start, it->length-start, warnCol);
00159 break;
00160 case Error:
00161 setFormat(start, it->length-start, errCol);
00162 break;
00163 case LogText:
00164 setFormat(start, it->length-start, logCol);
00165 break;
00166 default:
00167 break;
00168 }
00169
00170 start = it->length;
00171 }
00172 }
00173
00174 void ReportHighlighter::setParagraphType(ReportHighlighter::Paragraph t)
00175 {
00176 type = t;
00177 }
00178
00179 void ReportHighlighter::setTextColor( const QColor& col )
00180 {
00181 txtCol = col;
00182 }
00183
00184 void ReportHighlighter::setLogColor( const QColor& col )
00185 {
00186 logCol = col;
00187 }
00188
00189 void ReportHighlighter::setWarningColor( const QColor& col )
00190 {
00191 warnCol = col;
00192 }
00193
00194 void ReportHighlighter::setErrorColor( const QColor& col )
00195 {
00196 errCol = col;
00197 }
00198
00199
00200
00209 class CustomReportEvent : public QEvent
00210 {
00211 public:
00212 CustomReportEvent(ReportHighlighter::Paragraph p, const QString& s)
00213 : QEvent(QEvent::Type(QEvent::User))
00214 { par = p; msg = s;}
00215 ~CustomReportEvent()
00216 { }
00217 const QString& message() const
00218 { return msg; }
00219 ReportHighlighter::Paragraph messageType() const
00220 { return par; }
00221 private:
00222 ReportHighlighter::Paragraph par;
00223 QString msg;
00224 };
00225
00226
00227
00228 class ReportOutput::Data
00229 {
00230 public:
00231 Data()
00232 {
00233 if (!default_stdout) {
00234 Base::PyGILStateLocker lock;
00235 default_stdout = PySys_GetObject(const_cast<char*>("stdout"));
00236 replace_stdout = new OutputStdout();
00237 redirected_stdout = false;
00238 }
00239
00240 if (!default_stderr) {
00241 Base::PyGILStateLocker lock;
00242 default_stderr = PySys_GetObject(const_cast<char*>("stderr"));
00243 replace_stderr = new OutputStderr();
00244 redirected_stderr = false;
00245 }
00246 }
00247 ~Data()
00248 {
00249 if (replace_stdout) {
00250 Py_DECREF(replace_stdout);
00251 replace_stdout = 0;
00252 }
00253
00254 if (replace_stderr) {
00255 Py_DECREF(replace_stderr);
00256 replace_stderr = 0;
00257 }
00258 }
00259
00260
00261 static bool redirected_stdout;
00262 static PyObject* default_stdout;
00263 static PyObject* replace_stdout;
00264
00265 static bool redirected_stderr;
00266 static PyObject* default_stderr;
00267 static PyObject* replace_stderr;
00268 };
00269
00270 bool ReportOutput::Data::redirected_stdout = false;
00271 PyObject* ReportOutput::Data::default_stdout = 0;
00272 PyObject* ReportOutput::Data::replace_stdout = 0;
00273
00274 bool ReportOutput::Data::redirected_stderr = false;
00275 PyObject* ReportOutput::Data::default_stderr = 0;
00276 PyObject* ReportOutput::Data::replace_stderr = 0;
00277
00278
00279
00284 ReportOutput::ReportOutput(QWidget* parent)
00285 : QTextEdit(parent), WindowParameter("OutputWindow"), d(new Data), gotoEnd(false)
00286 {
00287 bLog = false;
00288 reportHl = new ReportHighlighter(this);
00289
00290 restoreFont();
00291 setReadOnly(true);
00292 clear();
00293 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00294
00295 Base::Console().AttachObserver(this);
00296 getWindowParameter()->Attach(this);
00297
00298 getWindowParameter()->NotifyAll();
00299 _prefs = WindowParameter::getDefaultParameter()->GetGroup("Editor");
00300 _prefs->Attach(this);
00301 _prefs->Notify("FontSize");
00302
00303
00304 ensureCursorVisible();
00305 }
00306
00310 ReportOutput::~ReportOutput()
00311 {
00312 getWindowParameter()->Detach(this);
00313 _prefs->Detach(this);
00314 Base::Console().DetachObserver(this);
00315 delete reportHl;
00316 delete d;
00317 }
00318
00319 void ReportOutput::restoreFont()
00320 {
00321 QFont serifFont(QLatin1String("Courier"), 10, QFont::Normal);
00322 setFont(serifFont);
00323 }
00324
00325 void ReportOutput::Warning(const char * s)
00326 {
00327
00328 CustomReportEvent* ev = new CustomReportEvent(ReportHighlighter::Warning, QString::fromUtf8(s));
00329 QApplication::postEvent(this, ev);
00330 }
00331
00332 void ReportOutput::Message(const char * s)
00333 {
00334
00335 CustomReportEvent* ev = new CustomReportEvent(ReportHighlighter::Message, QString::fromUtf8(s));
00336 QApplication::postEvent(this, ev);
00337 }
00338
00339 void ReportOutput::Error (const char * s)
00340 {
00341
00342 CustomReportEvent* ev = new CustomReportEvent(ReportHighlighter::Error, QString::fromUtf8(s));
00343 QApplication::postEvent(this, ev);
00344 }
00345
00346 void ReportOutput::Log (const char * s)
00347 {
00348 QString msg = QString::fromUtf8(s);
00349 if (msg.length() < 1000){
00350
00351 CustomReportEvent* ev = new CustomReportEvent(ReportHighlighter::LogText, msg);
00352 QApplication::postEvent(this, ev);
00353 }
00354 }
00355
00356 void ReportOutput::customEvent ( QEvent* ev )
00357 {
00358
00359 if ( ev->type() == QEvent::User ) {
00360 CustomReportEvent* ce = (CustomReportEvent*)ev;
00361 reportHl->setParagraphType(ce->messageType());
00362
00363 QTextCursor cursor(this->document());
00364 cursor.beginEditBlock();
00365 cursor.movePosition(QTextCursor::End);
00366 cursor.insertText(ce->message());
00367 cursor.endEditBlock();
00368 if (gotoEnd) {
00369 setTextCursor(cursor);
00370 }
00371 ensureCursorVisible();
00372 }
00373 }
00374
00375 void ReportOutput::contextMenuEvent ( QContextMenuEvent * e )
00376 {
00377 QMenu* menu = createStandardContextMenu();
00378 QAction* first = menu->actions().front();
00379
00380 QMenu* submenu = new QMenu( menu );
00381 QAction* logAct = submenu->addAction(tr("Logging"), this, SLOT(onToggleLogging()));
00382 logAct->setCheckable(true);
00383 logAct->setChecked(bLog);
00384
00385 QAction* wrnAct = submenu->addAction(tr("Warning"), this, SLOT(onToggleWarning()));
00386 wrnAct->setCheckable(true);
00387 wrnAct->setChecked(bWrn);
00388
00389 QAction* errAct = submenu->addAction(tr("Error"), this, SLOT(onToggleError()));
00390 errAct->setCheckable(true);
00391 errAct->setChecked(bErr);
00392
00393 submenu->addSeparator();
00394
00395 QAction* stdoutAct = submenu->addAction(tr("Redirect Python output"), this, SLOT(onToggleRedirectPythonStdout()));
00396 stdoutAct->setCheckable(true);
00397 stdoutAct->setChecked(d->redirected_stdout);
00398
00399 QAction* stderrAct = submenu->addAction(tr("Redirect Python errors"), this, SLOT(onToggleRedirectPythonStderr()));
00400 stderrAct->setCheckable(true);
00401 stderrAct->setChecked(d->redirected_stderr);
00402
00403 submenu->addSeparator();
00404 QAction* botAct = submenu->addAction(tr("Go to end"), this, SLOT(onToggleGoToEnd()));
00405 botAct->setCheckable(true);
00406 botAct->setChecked(gotoEnd);
00407
00408 submenu->setTitle(tr("Options"));
00409 menu->insertMenu(first, submenu);
00410 menu->insertSeparator(first);
00411
00412 menu->addAction(tr("Clear"), this, SLOT(clear()));
00413 menu->addSeparator();
00414 menu->addAction(tr("Save As..."), this, SLOT(onSaveAs()));
00415
00416 menu->exec(e->globalPos());
00417 delete menu;
00418 }
00419
00420 void ReportOutput::onSaveAs()
00421 {
00422 QString fn = QFileDialog::getSaveFileName(this, tr("Save Report Output"), QString(), tr("Plain Text Files (*.txt *.log)"));
00423 if (!fn.isEmpty()) {
00424 QFileInfo fi(fn);
00425 if (fi.completeSuffix().isEmpty())
00426 fn += QLatin1String(".log");
00427 QFile f(fn);
00428 if (f.open(QIODevice::WriteOnly)) {
00429 QTextStream t (&f);
00430 t << toPlainText();
00431 f.close();
00432 }
00433 }
00434 }
00435
00436 bool ReportOutput::isError() const
00437 {
00438 return bErr;
00439 }
00440
00441 bool ReportOutput::isWarning() const
00442 {
00443 return bWrn;
00444 }
00445
00446 bool ReportOutput::isLogging() const
00447 {
00448 return bLog;
00449 }
00450
00451 void ReportOutput::onToggleError()
00452 {
00453 bErr = bErr ? false : true;
00454 getWindowParameter()->SetBool( "checkError", bErr );
00455 }
00456
00457 void ReportOutput::onToggleWarning()
00458 {
00459 bWrn = bWrn ? false : true;
00460 getWindowParameter()->SetBool( "checkWarning", bWrn );
00461 }
00462
00463 void ReportOutput::onToggleLogging()
00464 {
00465 bLog = bLog ? false : true;
00466 getWindowParameter()->SetBool( "checkLogging", bLog );
00467 }
00468
00469 void ReportOutput::onToggleRedirectPythonStdout()
00470 {
00471 if (d->redirected_stdout) {
00472 d->redirected_stdout = false;
00473 Base::PyGILStateLocker lock;
00474 PySys_SetObject(const_cast<char*>("stdout"), d->default_stdout);
00475 }
00476 else {
00477 d->redirected_stdout = true;
00478 Base::PyGILStateLocker lock;
00479 PySys_SetObject(const_cast<char*>("stdout"), d->replace_stdout);
00480 }
00481
00482 getWindowParameter()->SetBool("RedirectPythonOutput", d->redirected_stdout);
00483 }
00484
00485 void ReportOutput::onToggleRedirectPythonStderr()
00486 {
00487 if (d->redirected_stderr) {
00488 d->redirected_stderr = false;
00489 Base::PyGILStateLocker lock;
00490 PySys_SetObject(const_cast<char*>("stderr"), d->default_stderr);
00491 }
00492 else {
00493 d->redirected_stderr = true;
00494 Base::PyGILStateLocker lock;
00495 PySys_SetObject(const_cast<char*>("stderr"), d->replace_stderr);
00496 }
00497
00498 getWindowParameter()->SetBool("RedirectPythonErrors", d->redirected_stderr);
00499 }
00500
00501 void ReportOutput::onToggleGoToEnd()
00502 {
00503 gotoEnd = gotoEnd ? false : true;
00504 getWindowParameter()->SetBool( "checkGoToEnd", gotoEnd );
00505 }
00506
00507 void ReportOutput::OnChange(Base::Subject<const char*> &rCaller, const char * sReason)
00508 {
00509 ParameterGrp& rclGrp = ((ParameterGrp&)rCaller);
00510 if (strcmp(sReason, "checkLogging") == 0) {
00511 bLog = rclGrp.GetBool( sReason, bLog );
00512 }
00513 else if (strcmp(sReason, "checkWarning") == 0) {
00514 bWrn = rclGrp.GetBool( sReason, bWrn );
00515 }
00516 else if (strcmp(sReason, "checkError") == 0) {
00517 bErr = rclGrp.GetBool( sReason, bErr );
00518 }
00519 else if (strcmp(sReason, "colorText") == 0) {
00520 unsigned long col = rclGrp.GetUnsigned( sReason );
00521 reportHl->setTextColor( QColor( (col >> 24) & 0xff,(col >> 16) & 0xff,(col >> 8) & 0xff) );
00522 }
00523 else if (strcmp(sReason, "colorLogging") == 0) {
00524 unsigned long col = rclGrp.GetUnsigned( sReason );
00525 reportHl->setLogColor( QColor( (col >> 24) & 0xff,(col >> 16) & 0xff,(col >> 8) & 0xff) );
00526 }
00527 else if (strcmp(sReason, "colorWarning") == 0) {
00528 unsigned long col = rclGrp.GetUnsigned( sReason );
00529 reportHl->setWarningColor( QColor( (col >> 24) & 0xff,(col >> 16) & 0xff,(col >> 8) & 0xff) );
00530 }
00531 else if (strcmp(sReason, "colorError") == 0) {
00532 unsigned long col = rclGrp.GetUnsigned( sReason );
00533 reportHl->setErrorColor( QColor( (col >> 24) & 0xff,(col >> 16) & 0xff,(col >> 8) & 0xff) );
00534 }
00535 else if (strcmp(sReason, "checkGoToEnd") == 0) {
00536 gotoEnd = rclGrp.GetBool(sReason, gotoEnd);
00537 }
00538 else if (strcmp(sReason, "FontSize") == 0 || strcmp(sReason, "Font") == 0) {
00539 int fontSize = rclGrp.GetInt("FontSize", 10);
00540 QString fontFamily = QString::fromAscii(rclGrp.GetASCII("Font", "Courier").c_str());
00541
00542 QFont font(fontFamily, fontSize);
00543 setFont(font);
00544 QFontMetrics metric(font);
00545 int width = metric.width(QLatin1String("0000"));
00546 setTabStopWidth(width);
00547 }
00548 else if (strcmp(sReason, "RedirectPythonOutput") == 0) {
00549 bool checked = rclGrp.GetBool(sReason);
00550 if (checked != d->redirected_stdout)
00551 onToggleRedirectPythonStdout();
00552 }
00553 else if (strcmp(sReason, "RedirectPythonErrors") == 0) {
00554 bool checked = rclGrp.GetBool(sReason);
00555 if (checked != d->redirected_stderr)
00556 onToggleRedirectPythonStderr();
00557 }
00558 }
00559
00560 #include "moc_ReportView.cpp"