📄 qgsgrassshell.cpp
字号:
// ( ; separated nums - (;\\d+)* ) rx.setPattern ( "\\[([?=])*(\\d+)*(;\\d+)*([A-z])" ); if ( rx.search ( mStdoutBuffer, 1 ) == 1 ) { int mlen = rx.matchedLength(); char final = rx.cap(4).at(0).latin1(); std::cerr << "final = " << final << std::endl; //std::cerr << "ESC: " << rx.cap(0) << std::endl; switch ( final ) { case 'l' : // RM - Reset Mode case 'h' : // SM - Set Mode { int mode = -1; switch ( rx.cap(2).toInt() ) { case 4 : mode = Insert; break; default: std::cerr << "ESC ignored: " << rx.cap(0).local8Bit().data() << std::endl; break; } if ( mode >= 0 ) { if ( final == 'l' ) resetMode ( mode ); else setMode ( mode ); } break; } case 'm' : // SGR - Select Graphic Rendition if ( rx.cap(2).isEmpty() || rx.cap(2).toInt() == 0 ) { for ( int i = 0; i < RendetionCount; i++ ) { mRendetion[i] = false; } } else { std::cerr << "ESC SGR ignored: " << rx.cap(0).local8Bit().data() << std::endl; } break; case 'P' : // DCH - Delete Character { int n = rx.cap(2).toInt(); mText->setSelection ( mParagraph, mIndex, mParagraph, mIndex+n, 0 ); mText->removeSelectedText ( 0 ); break; } case 'K' : // EL - Erase In Line if ( rx.cap(2).isEmpty() || rx.cap(2).toInt() == 0 ) { //mText->setSelectionAttributes ( 1, QColor(255,255,255), true ); mText->setSelection ( mParagraph, mIndex, mParagraph, mText->paragraphLength(mParagraph), 0 ); mText->removeSelectedText ( 0 ); } break; // TODO: multiple tab stops case 'H' : // Horizontal Tabulation Set (HTS) mTabStop[mIndex] = true; std::cerr << "TAB set on " << mIndex << std::endl; break; case 'g' : // Tabulation Clear (TBC) // ESC [ g Clears tab stop at the cursor // ESC [ 2 g Clears all tab stops in the line // ESC [ 3 g Clears all tab stops in the Page std::cerr << "TAB reset" << std::endl; if ( rx.cap(2).isEmpty() || rx.cap(2).toInt() == 0 ) { mTabStop[mIndex] = false; } else { for (int i = 0; i < (int)mTabStop.size(); i++ ) mTabStop[mIndex] = false; } break; default: std::cerr << "ESC ignored: " << rx.cap(0).local8Bit().data() << std::endl; break; } mStdoutBuffer.remove ( 0, mlen+1 ); found = true; } } if ( !found ) { // ESC # DIGIT rx.setPattern ( "#(\\d)" ); if ( rx.search ( mStdoutBuffer, 1 ) == 1 ) { std::cerr << "ESC ignored: " << rx.cap(0).local8Bit().data() << std::endl; mStdoutBuffer.remove ( 0, 3 ); found = true; } } if ( !found ) { // ESC CHARACTER rx.setPattern ( "[A-z<>=]" ); if ( rx.search ( mStdoutBuffer, 1 ) == 1 ) { std::cerr << "ESC ignored: " << rx.cap(0).local8Bit().data() << std::endl; mStdoutBuffer.remove ( 0, 2 ); found = true; } } // TODO: it can happen that the sequence is not complete -> // no match -> how to distinguish unknown sequence from // missing characters if ( !found ) { // For now move forward std::cerr << "UNKNOWN ESC ignored: " << mStdoutBuffer.mid(1,5).data() << std::endl; mStdoutBuffer.remove ( 0, 1 ); } } else { // control character switch ( c ) { case '\015' : // CR //std::cerr << "CR" << std::endl; mStdoutBuffer.remove ( 0, 1 ); // TODO : back tab stops? mIndex = 0; break; case '\012' : // NL //std::cerr << "NL" << std::endl; newLine(); mStdoutBuffer.remove ( 0, 1 ); break; case '\010' : // BS //std::cerr << "BS" << std::endl; mIndex--; mStdoutBuffer.remove ( 0, 1 ); break; case '\011' : // HT (tabulator) { //std::cerr << "HT" << std::endl; QString space; for ( int i = mIndex; i < (int)mTabStop.size(); i++ ) { space.append ( " " ); if ( mTabStop[i] ) break; } insert (space); mStdoutBuffer.remove ( 0, 1 ); break; } case '>' : // Keypad Numeric Mode std::cerr << "Keypad Numeric Mode ignored: " << QString::number(c,8).local8Bit().data() << std::endl; mStdoutBuffer.remove ( 0, 2 ); break; default : // unknown control, do nothing std::cerr << "UNKNOWN control char ignored: " << QString::number(c,8).local8Bit().data() << std::endl; mStdoutBuffer.remove ( 0, 1 ); break; } } continue; } // GRASS messages. GRASS messages start with GRASS_INFO_ // and stop with \015\012 (\n) // first info QRegExp rxinfo ( "GRASS_INFO_" ); int message = rxinfo.search(mStdoutBuffer); if ( message == 0 ) // Info found at index 0 { // First try percent QRegExp rxpercent ( "GRASS_INFO_PERCENT: (\\d+)\\015\\012" ); if ( rxpercent.search(mStdoutBuffer) == 0 ) { int mlen = rxpercent.matchedLength(); int progress = rxpercent.cap(1).toInt(); mProgressBar->setProgress ( progress, 100 ); mStdoutBuffer.remove ( 0, mlen ); continue; } QRegExp rxwarning ( "GRASS_INFO_WARNING\\(\\d+,\\d+\\): ([^\\015]*)\\015\\012" ); QRegExp rxerror ( "GRASS_INFO_ERROR\\(\\d+,\\d+\\): ([^\\015]*)\\015\\012" ); QRegExp rxend ( "GRASS_INFO_END\\(\\d+,\\d+\\)\\015\\012" ); int mlen = 0; QString msg; QString img; if ( rxwarning.search(mStdoutBuffer) == 0 ) { mlen = rxwarning.matchedLength(); msg = rxwarning.cap(1); img = QgsApplication::pkgDataPath() + "/themes/default/grass/grass_module_warning.png"; } else if ( rxerror.search(mStdoutBuffer) == 0 ) { mlen = rxerror.matchedLength(); msg = rxerror.cap(1); img = QgsApplication::pkgDataPath() + "/themes/default/grass/grass_module_error.png"; } if ( mlen > 0 ) // found error or warning {#ifdef QGISDEBUG std::cerr << "MSG: " << msg.local8Bit().data() << std::endl;#endif // Delete all previous empty paragraphs. // Messages starts with \n (\015\012) which is previously interpreted // as new line, so it is OK delete it, but it is not quite correct // to delete more because it can be regular module output // but it does not look nice to have empty rows before removeEmptyParagraphs(); msg.replace ( "&", "&" ); msg.replace ( "<", "<" ); msg.replace ( ">", ">" ); msg.replace ( " ", " " ); mText->setTextFormat(Qt::RichText); mText->append ( "<img src=\"" + img + "\">" + QString::fromLocal8Bit( msg ) ); mParagraph++; mNewLine = true; mStdoutBuffer.remove ( 0, mlen ); continue; } if ( rxend.search(mStdoutBuffer) == 0 ) { mlen = rxend.matchedLength(); mStdoutBuffer.remove ( 0, mlen ); continue; } // No complete message found => wait for input // TODO: 1) Sleep for a moment because GRASS writes // 1 character in loop // 2) Fix GRASS to write longer strings break; } // Print plain text int length = mStdoutBuffer.length(); if ( control >= 0 ) length = control; if ( message >= 0 && (control == -1 || control > message ) ) { length = message; } if ( length > 0 ) { QString out = mStdoutBuffer.left ( length ) ;#ifdef QGISDEBUG std::cerr << "TXT: '" << out.local8Bit().data()<< "'" << std::endl;#endif insert ( QString::fromLocal8Bit( out ) ); mStdoutBuffer.remove ( 0, length ); } } showCursor(); mText->ensureCursorVisible();}void QgsGrassShell::removeEmptyParagraphs(){ while ( mParagraph >= 0 && mText->text(mParagraph).stripWhiteSpace().length() <= 0 ) { mText->removeParagraph ( mParagraph ); mParagraph--; } mIndex = mText->paragraphLength(mParagraph);}void QgsGrassShell::insert ( QString s ){#ifdef QGISDEBUG std::cerr << "insert()" << std::endl;#endif if ( s.isEmpty() ) return; // In theory mParagraph == mText->paragrephs()-1 // but if something goes wrong (more paragraphs) we want to write // at the end if ( mParagraph > -1 && mParagraph != mText->paragraphs()-1 ) { std::cerr << "WRONG mParagraph!" << std::endl; mNewLine = true; } // Bug?: QTextEdit::setOverwriteMode does not work, always 'insert' // -> if Insert mode is not set, delete first the string // to the right // mText->setOverwriteMode ( !mMode[Insert] ); // does not work if ( !mMode[Insert] && !mNewLine && mParagraph >= 0 && mText->paragraphLength(mParagraph) > mIndex ) {#ifdef QGISDEBUG std::cerr << "erase old " << mIndex+s.length() << " chars " << std::endl;#endif mText->setSelection ( mParagraph, mIndex, mParagraph, mIndex+s.length(), 0 ); mText->removeSelectedText ( 0 ); } if ( mNewLine ) { // Start new paragraph mText->setTextFormat(Qt::PlainText); mText->setCurrentFont ( mFont ); mText->append ( s ); mIndex = s.length(); //mParagraph++; mParagraph = mText->paragraphs()-1; mNewLine = false; } else { // Append to existing paragraph mText->setCursorPosition ( mParagraph, mIndex ); mText->setTextFormat(Qt::PlainText); mText->setCurrentFont ( mFont ); mText->insert ( s ); mIndex += s.length(); }}void QgsGrassShell::newLine(){ if ( mSkipLines > 0 ) { mText->clear(); mSkipLines--; } if ( mNewLine ) { mText->setTextFormat(Qt::PlainText); mText->setCurrentFont ( mFont ); mText->append ( " " ); //mParagraph++; // To be sure that we are at the end mParagraph = mText->paragraphs()-1; mIndex = 0; } mNewLine = true;}void QgsGrassShell::eraseCursor(){ // Remove space representing cursor from the end of current paragraph if ( !mNewLine && mCursorSpace && mParagraph >= 0 ) { mText->setSelection ( mParagraph, mIndex, mParagraph, mIndex+1, 0 ); mText->removeSelectedText ( 0 ); } mCursorSpace = false;}void QgsGrassShell::showCursor(){ // Do not highlite cursor if last printed paragraph was GRASS message if ( mNewLine ) return; // If cursor is at the end of paragraph add space if ( mParagraph >= 0 && mIndex > mText->paragraphLength(mParagraph)-1 ) { mText->setCursorPosition(mParagraph,mIndex); mText->setCursorPosition ( mParagraph, mIndex ); mText->insert ( " " ); // Warning: do not increase mIndex, // the space if after current position mCursorSpace = true; } // Selection 1 is used as cursor highlite mText->setSelection ( mParagraph, mIndex, mParagraph, mIndex+1, 1 ); mText->setSelectionAttributes ( 1, QColor(0,0,0), true ); }void QgsGrassShell::mousePressEvent(QMouseEvent* e){#ifdef QGISDEBUG std::cerr << "mousePressEvent()" << std::endl;#endif if ( !mValid ) return; // paste clipboard if ( e->button() == Qt::MidButton ) { QClipboard *cb = QApplication::clipboard(); QString text = cb->text(QClipboard::Selection); write( mFdMaster, (char*) text.ascii(), text.length() ); }}void QgsGrassShell::resizeTerminal(){#ifndef WIN32 int width = mText->visibleWidth(); int height = mText->visibleHeight(); QFontMetrics fm ( mFont ); int col = (int) (width / fm.width("x")); int row = (int) (height / fm.height()); struct winsize winSize; memset(&winSize, 0, sizeof(winSize)); winSize.ws_row = row; winSize.ws_col = col; ioctl( mFdMaster, TIOCSWINSZ, (char *)&winSize );#endif}void QgsGrassShell::readStderr(){}void QgsGrassShell::closeShell(){#ifdef QGISDEBUG std::cerr << "QgsGrassShell::closeShell()" << std::endl;#endif mTabWidget->removePage (this ); delete this;}QgsGrassShellText::QgsGrassShellText ( QgsGrassShell *gs, QWidget * parent, const char *name ): Q3TextEdit (parent,name),mShell(gs){}QgsGrassShellText::~QgsGrassShellText() {} void QgsGrassShellText::contentsMousePressEvent(QMouseEvent* e){#ifdef QGISDEBUG std::cerr << "contentsMousePressEvent()" << std::endl;#endif mShell->mousePressEvent(e); Q3TextEdit::contentsMousePressEvent(e);}void QgsGrassShellText::keyPressEvent ( QKeyEvent * e ){#ifdef QGISDEBUG std::cerr << "QgsGrassShellText::keyPressEvent()" << std::endl;#endif mShell->keyPressEvent(e);}void QgsGrassShellText::keyReleaseEvent ( QKeyEvent * e ){#ifdef QGISDEBUG std::cerr << "QgsGrassShellText::keyReleaseEvent()" << std::endl;#endif mShell->keyReleaseEvent(e);}void QgsGrassShellText::resizeEvent(QResizeEvent *e){#ifdef QGISDEBUG std::cerr << "resizeEvent()" << std::endl;#endif mShell->resizeTerminal(); Q3TextEdit::resizeEvent(e);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -