void LoginDialog::onButtonClick(QAbstractButton *btn)
{
	QDialogButtonBox::StandardButton b = m_ui->buttonBox->standardButton(btn);

	if(b == QDialogButtonBox::Ok) {
		switch(m_mode) {
		case LABEL: /* no OK button in this mode */; break;
		case PASSWORD:
			m_login->gotPassword(m_ui->password->text());
			resetMode();
			break;
		case LOGIN:
			m_login->selectIdentity(m_ui->username->text(), m_ui->password->text());
			resetMode();
			break;
		case SESSION: {
			Q_ASSERT(!m_ui->sessionlist->selectionModel()->selectedIndexes().isEmpty());

			const int row = m_ui->sessionlist->selectionModel()->selectedIndexes().at(0).row();
			const net::LoginSession &s = static_cast<net::LoginSessionModel*>(m_ui->sessionlist->model())->sessionAt(row);
			m_login->joinSelectedSession(s.idOrAlias(), s.needPassword);
			break; }
		case CERT:
			m_login->acceptServerCertificate();
			resetMode();
			break;
		case CATCHUP:
			deleteLater();
			break;
		}

	} else {
		reject();
	}
}
void LoginDialog::onCertificateCheckNeeded(const QSslCertificate &newCert, const QSslCertificate &oldCert)
{
	Q_UNUSED(newCert);
	Q_UNUSED(oldCert);
	// TODO display certificate for comparison
	resetMode(CERT);
}
void LoginDialog::onLoginDone(bool join)
{
	if(join) {
		// Show catchup progress page when joining
		disconnect(m_loginDestructConnection);
		resetMode(CATCHUP);
	}
}
void Screen::reset(bool clearScreen)
{
    setMode(MODE_Wrap  ); saveMode(MODE_Wrap  );  // wrap at end of margin
    resetMode(MODE_Origin); saveMode(MODE_Origin);  // position refere to [1,1]
    resetMode(MODE_Insert); saveMode(MODE_Insert);  // overstroke
    setMode(MODE_Cursor);                         // cursor visible
    resetMode(MODE_Screen);                         // screen not inverse
    resetMode(MODE_NewLine);

    _topMargin=0;
    _bottomMargin=lines-1;

    setDefaultRendition();
    saveCursor();

    if ( clearScreen )
        clear();
}
/**
 * \brief Uninitialize w32_common framework.
 *
 * Should be called last in video driver's uninit function. First release
 * anything built on top of the created window e.g. rendering context inside
 * and call vo_w32_uninit at the end.
 */
void vo_w32_uninit(void) {
    mp_msg(MSGT_VO, MSGL_V, "vo: win32: uninit\n");
    resetMode();
    ShowCursor(1);
    depthonscreen = 0;
    if (dev_hdc) DeleteDC(dev_hdc);
    dev_hdc = 0;
    DestroyWindow(vo_window);
    vo_window = 0;
    UnregisterClass(classname, 0);
}
static int createRenderingContext(void) {
    HWND layer = HWND_NOTOPMOST;
    RECT r;
    int style = (vo_border && !vo_fs) ?
                (WS_OVERLAPPEDWINDOW | WS_SIZEBOX) : WS_POPUP;

    if (WinID >= 0)
        return 1;

    if (vo_fs || vo_ontop) layer = HWND_TOPMOST;
    if (vo_fs) {
        changeMode();
        while (ShowCursor(0) >= 0) /**/ ;
    } else {
        resetMode();
        while (ShowCursor(1) < 0) /**/ ;
    }
    updateScreenProperties();
    ShowWindow(vo_window, SW_HIDE);
    SetWindowLong(vo_window, GWL_STYLE, style);
    if (vo_fs) {
        prev_width = vo_dwidth;
        prev_height = vo_dheight;
        prev_x = vo_dx;
        prev_y = vo_dy;
        vo_dwidth = vo_screenwidth;
        vo_dheight = vo_screenheight;
        vo_dx = xinerama_x;
        vo_dy = xinerama_y;
    } else {
        // make sure there are no "stale" resize events
        // that would set vo_d* to wrong values
        vo_w32_check_events();
        vo_dwidth = prev_width;
        vo_dheight = prev_height;
        vo_dx = prev_x;
        vo_dy = prev_y;
        // HACK around what probably is a windows focus bug:
        // when pressing 'f' on the console, then 'f' again to
        // return to windowed mode, any input into the video
        // window is lost forever.
        SetFocus(vo_window);
    }
    r.left = vo_dx;
    r.right = r.left + vo_dwidth;
    r.top = vo_dy;
    r.bottom = r.top + vo_dheight;
    AdjustWindowRect(&r, style, 0);
    SetWindowPos(vo_window, layer, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_SHOWWINDOW);
    return 1;
}
Exemple #7
0
/**
 * \brief Uninitialize w32_common framework.
 *
 * Should be called last in video driver's uninit function. First release
 * anything built on top of the created window e.g. rendering context inside
 * and call vo_w32_uninit at the end.
 */
void vo_w32_uninit(struct vo *vo)
{
    struct vo_w32_state *w32 = vo->w32;
    mp_msg(MSGT_VO, MSGL_V, "vo: win32: uninit\n");
    if (!w32)
        return;
    resetMode(vo);
    ShowCursor(1);
    if (w32->dev_hdc) DeleteDC(w32->dev_hdc);
    DestroyWindow(w32->window);
    UnregisterClassW(classname, 0);
    talloc_free(w32);
    vo->w32 = NULL;
}
void LoginDialog::onSessionChoiceNeeded(net::LoginSessionModel *sessions)
{
	sessions->setHideNsfm(parentalcontrols::level() >= parentalcontrols::Level::NoList);
	m_ui->sessionlist->setModel(sessions);

	QHeaderView *header = m_ui->sessionlist->horizontalHeader();
	header->setSectionResizeMode(1, QHeaderView::Stretch);
	header->setSectionResizeMode(0, QHeaderView::Fixed);
	header->resizeSection(0, 24);

	auto updateNsfmLabel = [this, sessions]() {
		const int filtered = sessions->filteredCount();
		if(filtered>0) {
			QString label = tr("%n age restricted session(s) hidden.", "", filtered);
			if(!parentalcontrols::isLocked())
				label = "<a href=\"#\">" + label  + "</a>";
			m_ui->nsfmSessionsLabel->setText(label);
		}
		m_ui->nsfmSessionsLabel->setVisible(filtered>0);
	};

	updateNsfmLabel();
	connect(sessions, &net::LoginSessionModel::filteredCountChanged, this, updateNsfmLabel);
	if(!parentalcontrols::isLocked()) {
		connect(m_ui->nsfmSessionsLabel, &QLabel::linkActivated, this, [this, sessions]() {
			QMessageBox::StandardButton btn = QMessageBox::question(this, QString(), tr("Show age restricted sessions?"));

			if(btn == QMessageBox::Yes) {
				sessions->setHideNsfm(false);
				m_ui->nsfmSessionsLabel->setVisible(false);
				QSettings().setValue("pc/level", int(parentalcontrols::Level::Unrestricted));
			}
		});
	}

	connect(m_ui->sessionlist->selectionModel(), &QItemSelectionModel::selectionChanged, [this](const QItemSelection &sel) {
		// Enable/disable OK button depending on the selection
		bool ok;

		if(sel.indexes().isEmpty())
			ok = false;
		else
			ok = sel.indexes().at(0).data(net::LoginSessionModel::JoinableRole).toBool();

		m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
	});

	resetMode(SESSION);
}
LoginDialog::LoginDialog(net::LoginHandler *login, QWidget *parent) :
	QDialog(parent), m_mode(LABEL), m_login(login), m_ui(new Ui_LoginDialog)
{
	setWindowModality(Qt::WindowModal);
	setWindowTitle(login->url().host());

	m_ui->setupUi(this);
	m_ui->servertitle->hide();

	// Login page
	m_ui->username->setText(login->url().userName());
	m_ui->username->setValidator(new UsernameValidator(this));

	auto requireFields = [this]() {
		// Enable Continue button when required fields are not empty
		bool ok = true;
		if(m_ui->username->isEnabled() && m_ui->username->text().trimmed().isEmpty())
			ok = false;
		if(m_ui->password->text().isEmpty())
			ok = false;
		m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
	};
	connect(m_ui->username, &QLineEdit::textChanged, requireFields);
	connect(m_ui->password, &QLineEdit::textChanged, requireFields);

	// Session list page
	m_ui->nsfmSessionsLabel->setVisible(false);

	connect(m_ui->sessionlist, &QTableView::doubleClicked, [this](const QModelIndex&) {
		if(m_ui->buttonBox->button(QDialogButtonBox::Ok)->isEnabled())
			m_ui->buttonBox->button(QDialogButtonBox::Ok)->click();
	});

	// Login process
	connect(m_ui->buttonBox, &QDialogButtonBox::clicked, this, &LoginDialog::onButtonClick);
	connect(this, &QDialog::rejected, login, &net::LoginHandler::cancelLogin);

	m_loginDestructConnection = connect(login, &net::LoginHandler::destroyed, this, &LoginDialog::deleteLater);

	connect(login, &net::LoginHandler::passwordNeeded, this, &LoginDialog::onPasswordNeeded);
	connect(login, &net::LoginHandler::loginNeeded, this, &LoginDialog::onLoginNeeded);
	connect(login, &net::LoginHandler::sessionChoiceNeeded, this, &LoginDialog::onSessionChoiceNeeded);
	connect(login, &net::LoginHandler::certificateCheckNeeded, this, &LoginDialog::onCertificateCheckNeeded);
	connect(login, &net::LoginHandler::serverTitleChanged, this, &LoginDialog::onServerTitleChanged);

	resetMode();
}
Exemple #10
0
// Update the window title, position, size, and border style from vo_* values.
static int reinit_window_state(struct vo *vo)
{
    struct vo_w32_state *w32 = vo->w32;
    HWND layer = HWND_NOTOPMOST;
    RECT r;

    if (WinID >= 0)
        return 1;

    wchar_t *title = mp_from_utf8(NULL, vo_get_window_title(vo));
    SetWindowTextW(w32->window, title);
    talloc_free(title);

    bool toggle_fs = w32->current_fs != vo_fs;
    w32->current_fs = vo_fs;

    DWORD style = update_style(vo, GetWindowLong(w32->window, GWL_STYLE));

    if (vo_fs || vo->opts->vo_ontop)
        layer = HWND_TOPMOST;

    // xxx not sure if this can trigger any unwanted messages (WM_MOVE/WM_SIZE)
    if (vo_fs) {
        changeMode(vo);
        while (ShowCursor(0) >= 0) /**/ ;
    } else {
        resetMode(vo);
        while (ShowCursor(1) < 0) /**/ ;
    }
    updateScreenProperties(vo);

    if (vo_fs) {
        // Save window position and size when switching to fullscreen.
        if (toggle_fs) {
            w32->prev_width = vo->dwidth;
            w32->prev_height = vo->dheight;
            w32->prev_x = w32->window_x;
            w32->prev_y = w32->window_y;
            mp_msg(MSGT_VO, MSGL_V, "[vo] save window bounds: %d:%d:%d:%d\n",
                   w32->prev_x, w32->prev_y, w32->prev_width, w32->prev_height);
        }
        vo->dwidth = vo->opts->vo_screenwidth;
        vo->dheight = vo->opts->vo_screenheight;
        w32->window_x = xinerama_x;
        w32->window_y = xinerama_y;
    } else {
        if (toggle_fs) {
            // Restore window position and size when switching from fullscreen.
            mp_msg(MSGT_VO, MSGL_V, "[vo] restore window bounds: %d:%d:%d:%d\n",
                   w32->prev_x, w32->prev_y, w32->prev_width, w32->prev_height);
            vo->dwidth = w32->prev_width;
            vo->dheight = w32->prev_height;
            w32->window_x = w32->prev_x;
            w32->window_y = w32->prev_y;
        }
    }

    r.left = w32->window_x;
    r.right = r.left + vo->dwidth;
    r.top = w32->window_y;
    r.bottom = r.top + vo->dheight;

    SetWindowLong(w32->window, GWL_STYLE, style);
    add_window_borders(w32->window, &r);

    mp_msg(MSGT_VO, MSGL_V, "[vo] reset window bounds: %ld:%ld:%ld:%ld\n",
           r.left, r.top, r.right - r.left, r.bottom - r.top);

    SetWindowPos(w32->window, layer, r.left, r.top, r.right - r.left,
                 r.bottom - r.top, SWP_FRAMECHANGED);
    // For some reason, moving SWP_SHOWWINDOW to a second call works better
    // with wine: returning from fullscreen doesn't cause a bogus resize to
    // screen size.
    // It's not needed on Windows XP or wine with a virtual desktop.
    // It doesn't seem to have any negative effects.
    SetWindowPos(w32->window, NULL, 0, 0, 0, 0,
                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);

    return 1;
}
void LoginDialog::onLoginNeeded(const QString &prompt)
{
	m_ui->intro->setText(prompt);
	m_ui->password->setText(QString());
	resetMode(LOGIN);
}
void LoginDialog::onPasswordNeeded(const QString &prompt)
{
	m_ui->intro->setText(prompt);
	m_ui->password->setText(QString());
	resetMode(PASSWORD);
}
QgsGrassShell::QgsGrassShell( QgsGrassTools *tools,
                              QTabWidget * parent, const char * name ):
    QDialog( parent ), QgsGrassShellBase(), mTools( tools )
{
  mValid = false;
  mSkipLines = 2;
  mTabWidget = parent;

#ifdef WIN32
  QMessageBox::warning( 0, "Warning",
                        "GRASS Shell is not supported on Windows." );
  return;
#else

  setupUi( this );

  QGridLayout *layout = new QGridLayout( mTextFrame, 1, 1 );
  mText = new QgsGrassShellText( this, mTextFrame );
  layout->addWidget( mText, 0, 0 );
  mText->show();

  connect( mCloseButton, SIGNAL( clicked() ), this, SLOT( closeShell() ) );

  mFont = QFont( "Courier", 10 );

  mAppDir = mTools->appDir();

#ifndef Q_WS_MAC
  // Qt4.3.2/Mac Q3TextEdit readOnly property causes keys to be processed as keyboard actions
  mText->setReadOnly( TRUE );
#endif
  //mText->setFocusPolicy ( QWidget::NoFocus ); // To get key press directly

#ifndef HAVE_OPENPTY
  mText->append( "GRASS shell is not supported" );
  return;
#endif

  // TODO set cursor IbeamCursor
  // This does not work - the cursor is used for scrollbars -> disabled
  //mText->setCursor ( QCursor(Qt::IbeamCursor) );
  mParagraph = -1; // first will be 0
  mIndex = -1;

  mNewLine = true;

  for ( int i = 0; i < ModeCount; i++ )
  {
    resetMode( i );
  }

  int uid;
  seteuid( uid = getuid() ); /* Run unprivileged */

  // Get and open pseudo terminal
  // Note: 0 (stdin), 1 (stdout) or 2 (stderr)
  int fdSlave; // slave file descriptor
  seteuid( 0 );
  int ret =  openpty( &mFdMaster, &fdSlave, NULL, NULL, NULL );
  if ( ret != 0 )
  {
    QMessageBox::warning( 0, "Warning", "Cannot open pseudo terminal" );
    return;
  }
  fchown( fdSlave, uid, ( gid_t ) - 1 );
  fchmod( fdSlave, S_IRUSR | S_IWUSR );
  seteuid( uid );

  QgsDebugMsg( QString( "mFdMaster = %1" ).arg( mFdMaster ) );
  QgsDebugMsg( QString( "fdSlave = %1" ).arg( fdSlave ) );

  fcntl( mFdMaster, F_SETFL, O_NDELAY );
  //fcntl( fdSlave, F_SETFL, O_NDELAY); // enable?

  QString slaveName = ttyname( fdSlave );
  QgsDebugMsg( QString( "master ttyname = %1" ).arg( ttyname( mFdMaster ) ) );
  QgsDebugMsg( QString( "slave ttyname = %1" ).arg( ttyname( fdSlave ) ) );

  //::close( fdSlave ); // -> crash

  // Fork slave and open shell
  int pid = fork();
  QgsDebugMsg( QString( "pid = %1" ).arg( pid ) );
  if ( pid == -1 )
  {
    QMessageBox::warning( 0, "Warning", "Cannot fork shell" );
    return;
  }

  // Child - slave
  if ( pid == 0 )
  {
    QgsDebugMsg( "child ->" );

    // TODO close all opened file descriptors - close(0)???
    ::close( mFdMaster );

    //::close( fdSlave ); // -> freeze

    setsid();
    seteuid( 0 );

    int fd = ::open(( char* ) slaveName.ascii(), O_RDWR );
    if ( fd < 0 )
    {
      QMessageBox::warning( 0, "Warning", "Cannot open slave file "
                            "in child process" );
      return;
    }

    fchown( fd, uid, ( gid_t ) - 1 );
    fchmod( fd, S_IRUSR | S_IWUSR );
    setuid( uid );

    dup2( fd, 0 ); /* stdin */
    dup2( fd, 1 ); /* stdout */
    dup2( fd, 2 ); /* stderr */

    // TODO: test if shell is available
    QString shell = ( getenv( "SHELL" ) );
    if ( shell.isEmpty() )
    {
      shell = "/bin/bash";
    }

    const char *norc = "";
    QFileInfo si( shell );
    if ( si.fileName() ==  "bash" || si.fileName() ==  "sh" )
    {
      norc = "--norc";
    }
    else if ( si.fileName() ==  "tcsh" || si.fileName() ==  "csh" )
    {
      norc = "-f";
    }

    // Warning: execle + --norc will not inherit not given variables
    // -> overwrite here
    const char *env = "GRASS_MESSAGE_FORMAT=gui";
    char *envstr = new char[strlen( env )+1];
    strcpy( envstr, env );
    putenv( envstr );

    putenv(( char * ) "GISRC_MODE_MEMORY" );  // unset

    env = "PS1=GRASS > ";
    envstr = new char[strlen( env )+1];
    strcpy( envstr, env );
    putenv( envstr );

    env = "TERM=vt100";
    envstr = new char[strlen( env )+1];
    strcpy( envstr, env );
    putenv( envstr );

    //char *envar[] = { "PS1=GRASS > ", "TERM=vt100", "GISRC_MODE_MEMORY=",
    //                  "GRASS_MESSAGE_FORMAT=gui", (char *)0 };

    //execle ( (char*)shell.ascii(), (char *)si.fileName().ascii(),
    //         norc, (char *) 0, envar);
    execl(( char* )shell.ascii(), ( char * )si.fileName().ascii(),
          norc, ( char * ) 0 );

    // Failed (QMessageBox here does not work)
    fprintf( stderr, "GRASS_INFO_ERROR(1,1): Cannot start shell %s\n",
             ( char* )shell.ascii() );
    exit( 1 );
  }

  mPid = pid;

  // Create socket notifier
  mOutNotifier = new QSocketNotifier( mFdMaster, QSocketNotifier::Read, this );

  QObject::connect( mOutNotifier, SIGNAL( activated( int ) ),
                    this, SLOT( readStdout( int ) ) );

  // Set tab stops ???
  mTabStop.resize( 200 );
  for ( int i = 0 ; i * 8 < ( int )mTabStop.size(); i++ )
  {
    mTabStop[i*8] = true;
  }

  // Set trap to write history on SIGUSR1
  //QString trap = "trap 'history -w' SIGUSR1\015\012";
  QString trap = "trap 'history -w' SIGUSR1\015";
  write( mFdMaster, trap.ascii(), trap.length() );
  mText->clear();

  resizeTerminal();
  mValid = true;
#endif // !WIN32
}
void QgsGrassShell::printStdout()
{
  // Debug
#ifdef QGISDEBUG
  QString str;
  for ( int i = 0; i < ( int )mStdoutBuffer.length(); i++ )
  {
    int c = mStdoutBuffer[i];
    QString s = "";
    if ( c > '\037' && c != '\177' ) // control characters
    {
      str += c;
    }
    else
    {
      str += "(c=" + QString::number( c, 8 ) + ")";
    }
  }
  QgsDebugMsg( "****** buffer ******" );
  QgsDebugMsg( QString( "-->%1<--" ).arg( str.toLocal8Bit().constData() ) );
#endif

  eraseCursor();
  // To make it faster we want to print maximum lenght blocks from buffer
  while ( mStdoutBuffer.length() > 0 )
  {
    QgsDebugMsg( "------ cycle ------" );

    // Search control character
    int control = -1;
    for ( int i = 0; i < ( int )mStdoutBuffer.length(); i++ )
    {
      int c = mStdoutBuffer[i];
      if ( c < '\037' || c == '\177' )
      {
        control = i;
        break;
      }
    }
    QgsDebugMsg( QString( "control = %1" ).arg( control ) );

    // Process control character if found at index 0
    if ( control == 0 )
    {
      int c = mStdoutBuffer[0];
      QgsDebugMsg( QString( "c = %1" ).arg( QString::number( c, 8 ).local8Bit().data() ) );

      // control sequence
      if ( c == '\033' )
      {
// QgsDebugMsg("control sequence");

        bool found = false;

        // It is sequence, so it should be at least one more character
        // wait for more data
        if ( mStdoutBuffer.length() < 2 ) break;
        if ( mStdoutBuffer[1] == ']' && mStdoutBuffer.length() < 3 ) break;

        // ESC ] Ps ; Pt BEL    (xterm title hack)
        QRegExp rx( "\\](\\d+);([^\\a]+)\\a" );
        if ( rx.search( mStdoutBuffer, 1 ) == 1 )
        {
          int mlen = rx.matchedLength();
          QgsDebugMsg( QString( "ESC(set title): %1" ).arg( rx.cap( 2 ).local8Bit().data() ) );
          mStdoutBuffer.remove( 0, mlen + 1 );
          found = true;
        }

        if ( !found )
        {
          //    ESC [ Pn ; Pn FINAL
          // or ESC [ = Pn ; Pn FINAL
          // or ESC [ = Pn ; Pn FINAL
          // TODO: QRegExp captures only last of repeated patterns
          //       ( ; 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();

            QgsDebugMsg( QString( "final = %1" ).arg( final ) );
// QgsDebugMsg(QString("ESC: %1").arg(rx.cap(0)));

            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:
                    QgsDebugMsg( QString( "ESC ignored: %1" ).arg( rx.cap( 0 ).local8Bit().data() ) );
                    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
                {
                  QgsDebugMsg( QString( "ESC SGR ignored: %1" ).arg( rx.cap( 0 ).local8Bit().data() ) );
                }
                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;
                QgsDebugMsg( QString( "TAB set on %1" ).arg( mIndex ) );
                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
                QgsDebugMsg( "TAB reset" );
                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:
                QgsDebugMsg( QString( "ESC ignored: %1" ).arg( rx.cap( 0 ).local8Bit().data() ) );
                break;
            }

            mStdoutBuffer.remove( 0, mlen + 1 );
            found = true;
          }