/*-*-c++-*-
 * $Id: cnconsole.cpp,v 1.2 2002/04/19 15:24:17 felfert Exp $
 *
 * This file is part of qlcrash, a GUI for the dump-analysis tool lcrash.
 *
 * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *
 * Authors:
 * Michael Geselbracht (let@users.sourceforge.net)
 * Fritz Elfert (elfert@de.ibm.com)
 * Michael Holzheu (holzheu@de.ibm.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */
#include "osdep.h"

#include <qapplication.h>
#include <qclipboard.h>
#include <qfont.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qtimer.h>
#include <qregexp.h>
#include <qstringlist.h>

#include <assert.h>
#include <iostream.h>

#ifndef __USE_ISOC99
#define __USE_ISOC99
#endif
#include <ctype.h>

#include "cnconsole.h"
#include "qlcrash.h"

CNConsole::CNConsole(QWidget* parent, const char* name)
	: QTableView(parent, name, WRepaintNoErase|WNorthWestGravity)
	, oColor(0, 0, 0)
	, oShowCursor(true)
	, oBlinkShow(true)
	, oCursorBuffer(1, 48) // this should be suffient for most fonts
	, oCmdDisplayed(false)
{
	setFrameStyle(QFrame::Panel | QFrame::Plain);
	setBackgroundColor(Qt::white);
	setFocusPolicy(QWidget::ClickFocus);
	setNumCols(1);

	setTableFlags(
		Tbl_vScrollBar |
		Tbl_autoHScrollBar
	);

	// default font
	oFont = QFont("Courier", 10, QFont::Normal);
	setCellHeight(QFontMetrics(oFont).height());
#if (QT_VERSION >= 300)
	setCellWidth(QFontMetrics(oFont).height() * 80);
#endif
	oMaxLines = 5000u;
	oText.setSize(oMaxLines);
	oCursX = 0;
	oCursY = 0;

	clearCursorBuffer();

	oHistory.setAutoDelete(true);

	oBlinker = new QTimer(this);
	connect(oBlinker, SIGNAL(timeout()), SLOT(slotBlink()));
}

CNConsole::~CNConsole()
{
}

void
CNConsole::resizeEvent(QResizeEvent* e)
{
	if (cellWidth() < viewWidth()) {
		setCellWidth(viewWidth());
	}

	QTableView::resizeEvent(e);
	setYOffset(totalHeight() - viewHeight());
	doUpdate();
}

QSize
CNConsole::sizeHint() const
{
	return QSize();
}

void
CNConsole::paintCell(QPainter* p, int row, int)
{
	CString* str = oText.line(row);
	CString tmp = "";

	if (str == 0) {
		str = &tmp;
	}
	str->replace(QRegExp("\t"), " ");

	QFontMetrics fm(oFont);
	int y = fm.ascent();

	QPixmap pm(cellWidth(), cellHeight());
	pm.fill(backgroundColor());
	QPainter p2(&pm);

	p2.setBackgroundMode(QPainter::OpaqueMode);
	p2.setPen(str->color());
	p2.setFont(oFont);

	// handle marked region
	int y1 = oMarkedRegion.markStartY();
	int y2 = oMarkedRegion.markEndY();
	if (y1 > y2) {
		int t = y1;
		y1 = y2;
		y2 = t;
	}

	if (oMarkedRegion.isMarked()) {
		if (row > y1) {
			if (row < y2) {
				p2.setBackgroundColor(palette().active().highlight());
				p2.setPen(palette().active().highlightedText());
				drawLine(&p2, y, str);
			}
			else if (row == y2) {
				drawMarkedLine(&p2, y, str, row, &fm);
			}
			else {
				drawLine(&p2, y, str);
			}
		}
		else if (row == y1) {
			drawMarkedLine(&p2, y, str, row, &fm);
		}
		else {
			drawLine(&p2, y, str);
		}
	}
	else {
		drawLine(&p2, y, str);
	}

	p->drawPixmap(0, 0, pm);
#if (QT_VERSION >= 300)
//	viewport()->update();
#endif

	if (row == oCursY) {
		clearCursorBuffer();
		drawCursor();
	}
}

void
CNConsole::drawLine(QPainter* p, int, QString* str)
{
	p->drawText(5, 0, cellWidth(), cellHeight(), Qt::AlignLeft|Qt::ExpandTabs, *str);
}

void
CNConsole::drawMarkedLine(QPainter* p, int y, CString* str, int line, QFontMetrics* fm)
{
	int len = str->length();
	int x = 5;

	int x1 = oMarkedRegion.markStartX();
	int y1 = oMarkedRegion.markStartY();
	int x2 = oMarkedRegion.markEndX();
	int y2 = oMarkedRegion.markEndY();
	if (y1 > y2) {
		int t = y1;
		y1 = y2;
		y2 = t;
		t = x1;
		x1 = x2;
		x2 = t;
	}
	else if (y1 == y2 && x1 > x2) {
		int t = x1;
		x1 = x2;
		x2 = t;
	}

	const QColor textcolor = str->color();
	int i;
	if (line == y1) {
		p->setBackgroundColor(backgroundColor());
		p->setPen(textcolor);
		for (i = 0; i < x1; i++) {
			p->drawText(x, y, QString(str->at(i)));
			x += fm->width(str->at(i));
		}

		if (line == y2) {
			p->setBackgroundColor(palette().active().highlight());
			p->setPen(palette().active().highlightedText());
			for (i = x1; i < x2; i++) {
				p->drawText(x, y, QString(str->at(i)));
				x += fm->width(str->at(i));
			}
			p->setBackgroundColor(backgroundColor());
			p->setPen(textcolor);
			for (i = x2; i < len; i++) {
				p->drawText(x, y, QString(str->at(i)));
				x += fm->width(str->at(i));
			}
		}
		else {
			p->setBackgroundColor(palette().active().highlight());
			p->setPen(palette().active().highlightedText());
			for (i = x1; i < len; i++) {
				p->drawText(x, y, QString(str->at(i)));
				x += fm->width(str->at(i));
			}
		}
	}
	else { // line == y2
		p->setBackgroundColor(palette().active().highlight());
		p->setPen(palette().active().highlightedText());
		for (i = 0; i < x2; i++) {
			p->drawText(x, y, QString(str->at(i)));
				x += fm->width(str->at(i));
		}
		p->setBackgroundColor(backgroundColor());
		p->setPen(textcolor);
		for (i = x2; i < len; i++) {
			p->drawText(x, y, QString(str->at(i)));
				x += fm->width(str->at(i));
		}
	}
}

void
CNConsole::drawCursor(bool moveView)
{
	int x;
	int y = oCursY * cellHeight();
	QFontMetrics fm(oFont);
	CString* str = oText.line(oCursY);
	if (str == 0 || str->length() == 0) {
		x = 0;
	}
	else {
		x = fm.width(*str, oCursX) + 1;
	}

	if (oShowCursor) {
		QWidget* device;
		int ch;

#if (QT_VERSION >= 300)
		device = viewport();
		QPainter p(device);
		x -= 1;
		ch = cellHeight() - 1;
#else
		device = this;
		QPainter p(this);
		ch = cellHeight();
#endif

		if (oBlinkShow) { // draw cursor
			// save cursor background
			saveCursorBackground(-xOffset() + 5 + x, 3 + y - yOffset(), ch, device);

			p.setClipRect(0, 0, viewWidth(), viewHeight());
			p.setPen(blue);
			p.translate(-xOffset(), y - yOffset());

			p.drawLine(x + 5, 3, x + 5, ch);
		}
		else { // remove cursor
			restoreCursorBackground(-xOffset() + 5 + x, 3 + y - yOffset(), ch, device);
			clearCursorBuffer();
		}
	}

	if (moveView) {
		setYOffset(totalHeight() - viewHeight());
		int w = x - viewWidth() + 10;
		setXOffset((w > 0) ? w : 0);
	}
}

void
CNConsole::focusInEvent(QFocusEvent*)
{
	setLineWidth(1);
	oShowCursor = true;
	drawCursor();
	oBlinker->start(500);
}

void
CNConsole::focusOutEvent(QFocusEvent* e)
{
	if (e->reason() == QFocusEvent::Tab) {
		setFocus();
		QKeyEvent ke(QEvent::KeyPress, Key_Tab, (int) '\t', 0);
		keyPressEvent(&ke);
	}
	else {
		setLineWidth(0);
		if (oShowCursor) {
			oShowCursor = false;
			drawCursor();
		}

		oBlinker->stop();
	}
}

void
CNConsole::keyPressEvent(QKeyEvent* e)
{
	QString str;

	switch (e->key()) {
		case Qt::Key_Left:
			if (moveCursor(-1)) {
				updateCell(oCursY, 0, false);
			}
			break;
		case Qt::Key_Right:
			if (moveCursor(1)) {
				updateCell(oCursY, 0, false);
			}
			break;
		case Qt::Key_Up:
			keyUp();
			break;
		case Qt::Key_Down:
			keyDown();
			break;
		case Qt::Key_Return:
			str = oText.line(oCursY)->mid(oInsertPos);
			append("\n");
			doUpdate();
			oInsertPos = 0;
			if (str.length() > 1 && (oHistory.first() == 0 || str != *oHistory.first())) {
				oHistory.prepend(new QString(str));
			}
			oHistory.first();
			oHistory.prev();
			emit sigLine(this, str);
			break;
		case Qt::Key_Backspace:
			if (moveCursor(-1)) {
				oText.line(oCursY)->remove(oCursX, 1);
				updateCell(oCursY, 0, false);
			}
			break;
		case Qt::Key_Delete:
			oText.line(oCursY)->remove(oCursX, 1);
			updateCell(oCursY, 0, false);
			break;
		case Qt::Key_Home:
			if (oCursX > 0) {
				setCursorPosition(oInsertPos);
				updateCell(oCursY, 0, false);
			}
			break;
		case Qt::Key_End:
			setCursorPosition(-1);
			updateCell(oCursY, 0, false);
			break;
		default:
			if (e->key() == Qt::Key_PageUp) { // scroll up
				if (e->state() == Qt::ShiftButton) {
					if (yOffset() > 0) {
						setYOffset((yOffset() > viewHeight()) ? yOffset() - viewHeight() : 0);
					}
				}
			}
			else if (e->key() == Qt::Key_PageDown) { // scroll down
				if (e->state() == Qt::ShiftButton) {
					if (yOffset() + viewHeight() < totalHeight()) {
						setYOffset(yOffset() + viewHeight());
					}
				}
			}
			else if (e->key() == Qt::Key_Tab) {
				QString* ll = oText.lastLine();
				int pos = oCursX - 1;

				QString cmd;
				while (pos >= 0 && !isspace(ll->at(pos).latin1())) {
					cmd.prepend(ll->at(pos));
					pos--;
				}

				QStringList match = cmdMatchList(cmd);
				if (match.count() >= 1) {
					if (match.count() == 1) {
						int diff = match.first().length() - cmd.length();
						ll->insert(oCursX, match.first().right(diff) + " ");
						oCursX += diff + 1;
					}
					else {
						if (oCmdDisplayed) {
							oCmdDisplayed = false;
							QString tmp = *ll;
							*ll = "";

							QStringList::Iterator it = match.begin();
							while (it != match.end()) {
								*ll += *it + " ";
								++it;
							}
							int pos = oInsertPos;
							append(QString("\n") + tmp);
							oInsertPos = pos;
						}
						else {
							oCmdDisplayed = true;
						}
					}

					doUpdate();
				}
			}
			else if (e->state() == Qt::ControlButton) {
				if (e->key() == Qt::Key_L) { // clear screen
					QString ll = *oText.lastLine();
					oText.clear();
					setXOffset(0);
					setYOffset(0);
					oCursY = 0;
					oText.append(ll);
					setNumRows(1);

					// reset history
					oHistory.first();
					oHistory.prev();

					doUpdate();
				}
				else if (e->key() == Qt::Key_A) { // Home
					if (oCursX > 0) {
						setCursorPosition(oInsertPos);
						updateCell(oCursY, 0, false);
					}
				}
				else if (e->key() == Qt::Key_E) { // End
					setCursorPosition(-1);
					updateCell(oCursY, 0, false);
				}
				else if (e->key() == Qt::Key_C) { // clear line
					*(oText.line(oCursY)) = CMD_PROMPT;
					oInsertPos = CMD_PROMPT_LEN;
					oCursX = CMD_PROMPT_LEN;
					setXOffset(0);

					//reset history
					oHistory.first();
					oHistory.prev();

					updateCell(oCursY, 0, false);
				}
			}
			else { // text input
				QChar ch = e->text().at(0).latin1();
				if (e->text().length() == 1 && isprint(ch.latin1())) {
					oText.line(oCursY)->insert(oCursX, ch);
					updateWidth(oCursY);
					moveCursor(1);
					updateCell(oCursY, 0, false);
				}

				oCmdDisplayed = false;
			}
	}

	// hide selection
	if (oMarkedRegion.isMarked()) {
		oMarkedRegion.setMarked(false);
		doUpdate();
	}
}

void
CNConsole::closeEvent(QCloseEvent* e)
{
	emit sigClosed(this);
	e->accept();
}

void
CNConsole::mousePressEvent(QMouseEvent* e)
{
	if (e->button() == Qt::MidButton || e->button() == Qt::RightButton) {
		// insert clipboard content
		QClipboard* board = QApplication::clipboard();
		if (board->text().length() > 0) {
			int x = oInsertPos;
			int pos = -1;
			if (oCursX < (int) oText.lastLine()->length() - 1) { // cursor not at EOL
				pos = oCursX;
			}
			append(board->text(), pos);
			oInsertPos = x;

			updateWidth(oCursY);
			drawCursor(true);
		}
	}
	else if (e->button() == LeftButton) {
		QPoint p = textPosition(e->pos());

		// if there was a previously marked range, un-mark it
		if (oMarkedRegion.isMarked()) {
			oMarkedRegion.setMarked(false);
			QClipboard* board = QApplication::clipboard();
			board->clear();
			doUpdate();
		}

		oMarkedRegion.setMarkStartY(p.y());
		oMarkedRegion.setMarkEndY(p.y());
		oMarkedRegion.setMarkStartX(p.x());
		oMarkedRegion.setMarkEndX(p.x());
	}
}

void
CNConsole::mouseDoubleClickEvent(QMouseEvent* e)
{
	if (e->button() != LeftButton) {
		return;
	}

	QPoint p = textPosition(e->pos());
	QClipboard* board = QApplication::clipboard();

	// unmark any selected range
	if (oMarkedRegion.isMarked()) {
		oMarkedRegion.setMarked(false);
		board->clear();
		doUpdate();
	}

	CString* line = oText.line(p.y());
	if (line != 0) {
		int x1=0, x2=0;

		// word start
		int i;
		for (i = p.x(); i >= 0; i--) {
			if (isblank(line->at(i).latin1())) {
				x1 = i+1;
				break;
			}
		}

		// word end
		for (i = p.x(); ; i++) {
			if (isblank(line->at(i).latin1()) || i >= (int) line->length()) {
				x2 = i;
				break;
			}
		}

		// finally, set marked range
		if (x2 > x1) {
			oMarkedRegion.setMarkStartY(p.y());
			oMarkedRegion.setMarkEndY(p.y());
			oMarkedRegion.setMarkStartX(x1);
			oMarkedRegion.setMarkEndX(x2);
			oMarkedRegion.setMarked(true);

			doUpdate();
		}
	}
}

void
CNConsole::mouseReleaseEvent(QMouseEvent*)
{
	if (oMarkedRegion.isMarked()) {
		int y1 = oMarkedRegion.markStartY();
		int y2 = oMarkedRegion.markEndY();

		if (y1 > y2) {
			int t = y1;
			y1 = y2;
			y2 = t;
		}
		int x1 = oMarkedRegion.markStartX();
		int x2 = oMarkedRegion.markEndX();
		if (y1 == y2 && x1 > x2) {
			int t = x1;
			x1 = x2;
			x2 = t;
		}

		// do nothing if start and end point are identical
		if (y1 == y2 && x1 == x2) {
			return;
		}

		QString str;
		if (y1 == y2) {
			QString* line = oText.line(y1);
			assert(line != 0);
			str = line->mid(x1, x2 - x1);
		}
		else { // y2 > y1
			QString* line = oText.line(y1);
			assert(line != 0);
			str = line->mid(x1);

			for (int i = y1 + 1; i < y2; i++) {
				line = oText.line(i);
				assert(line != 0);
				str += *line;
			}

			line = oText.line(y2);
			assert(line != 0);
			str += line->left(x2);
		}

		QClipboard* cb = QApplication::clipboard();
		cb->setText(str);
	}
}

void
CNConsole::mouseMoveEvent(QMouseEvent* e)
{
	if (e->state() == Qt::LeftButton) {
		QPoint p = textPosition(e->pos());
		bool changed = false;

		if (p.y() != oMarkedRegion.markEndY()) {
			oMarkedRegion.setMarkEndY(p.y());
			changed = true;
		}
		if (p.x() != oMarkedRegion.markEndX()) {
			oMarkedRegion.setMarkEndX(p.x());
			changed = true;
		}

		if (e->y() > viewHeight() && yOffset() + viewHeight() < totalHeight()) {
			setYOffset(yOffset() + cellHeight());
		}
		else if (e->y() < 0 && yOffset() > 0) {
			setYOffset(yOffset() - cellHeight());
		}
		if (e->x() > viewWidth() && xOffset() + viewHeight() < cellWidth()) {
			setXOffset(xOffset() + oFont.pixelSize());
		}
		else if (e->x() < 0 && xOffset() > 0) {
			setXOffset(xOffset() - oFont.pixelSize());
		}

		if (changed) {
			oMarkedRegion.setMarked(true);
			doUpdate();
		}
	}
}

void
CNConsole::updateWidth(int row)
{
	CString* str = oText.line(row);
	if (str != 0) {
		QFontMetrics fm(oFont);
		int w = fm.width(*str);
		if (w > cellWidth() - 10) {
			setCellWidth(w + 10);
		}
	}
}

void
CNConsole::append(QString str, int pos)
{
	bool addPrompt = false;

	// strip prompt and append it with black color
	if (str.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
		str.truncate(str.length() - CMD_PROMPT_LEN);
		addPrompt = true;
	}

	// remove cursor from previous line
	oBlinkShow = false;
	drawCursor();

	// determine the number of characters right of the cursor
	int rol = 0;
	if (pos >= 0) {
		CString* ll = oText.lastLine();
		if (ll != 0) {
			rol = ll->mid(pos).length();
		}
	}

	int oldCount = oText.numLines();
	oText.append(str, oColor, pos);
	int newCount = oText.numLines();

	QFontMetrics fm(oFont);

	for (int i = oldCount; i < newCount; i++) {
		updateWidth(i);
	}

	if (addPrompt) {
		oText.add(CMD_PROMPT, Qt::black);
	}

	// determine cursor position
	if (pos >= 0) {
		CString* str = oText.lastLine();
		pos = str->length() - rol;
	}

	setNumRows(oText.numLines());
	setCursorPosition(pos);
	doUpdate();
	setYOffset(totalHeight() - viewHeight());
	oInsertPos = oText.line(oCursY)->length();
}

void
CNConsole::slotLine(QString str)
{
	append(str);
}

void
CNConsole::setCursorPosition(int col)
{
	int row = oText.numLines() - 1;
	if (row < 0) {
		row = 0;
	}

	if (col < 0) {
		CString* text = oText.line(row);
		if (text == 0) {
			col = 0;
		}
		else {
			col = text->length();
			if (col < 0) {
				col = 0;
			}
		}
	}

	oCursX = col;
	oCursY = row;

	drawCursor(true);
}

bool
CNConsole::moveCursor(int offset)
{
	int pos = oCursX + offset;
	CString* str = oText.line(oCursY);
	int max = (str == 0) ? 0 : str->length();

	if (pos >= oInsertPos && pos <= max && offset != 0) {
		setCursorPosition(pos);
		oBlinkShow = true;
		clearCursorBuffer();
		return true;
	}

	return false;
}

void
CNConsole::keyUp()
{
	if (oHistory.current() != oHistory.getLast()) {
		if (oHistory.current() == 0) {
			oHistory.first();
		}
		else {
			oHistory.next();
		}

		if (oHistory.current() != 0) {
			oText.line(oCursY)->remove(oInsertPos, 1000);
			append(*oHistory.current());
			updateCell(oCursY, 0, false);
			oInsertPos -= oHistory.current()->length();
		}
	}
}

void
CNConsole::keyDown()
{
	if (oHistory.current() != 0) {
		oText.line(oCursY)->remove(oInsertPos, 1000);
		setCursorPosition(oInsertPos);
		oHistory.prev();
		if (oHistory.current() != 0) {
			append(*oHistory.current());
			oInsertPos -= oHistory.current()->length();
		}
		updateCell(oCursY, 0, false);
	}
}

void
CNConsole::slotBlink()
{
	oBlinkShow = !oBlinkShow;
	drawCursor();
}

void
CNConsole::setFont(const QFont& f)
{
	QFontMetrics fm(f);
	setCellHeight(fm.height());
	oFont = f;
}

QPoint
CNConsole::textPosition(QPoint mousePos)
{
	// calc. absolute line
	int y = yOffset();
	if (mousePos.y() >= 0) {
		y += mousePos.y();
	}
	int line = y / cellHeight();

	int col = 0;
	if (line < (int) oText.numLines()) {
		// calc. column
		int x = xOffset();
		mousePos.setX(mousePos.x() - 5); // consider left border
		if (mousePos.x() >= 0) {
			x += mousePos.x();
		}
		QString* str = oText.line(line);
		assert(str != 0);
		int len = str->length();
		QFontMetrics fm(oFont);

		for (; col < len && x > 0; col++) {
			x -= fm.width(str->at(col));
		}
		if (x < 0) {
			col--;
		}
	}
	else {
		line = oText.numLines() - 1;
		if (line >= 0) {
			QString* str = oText.line(line);
			assert(str != 0);
			col = str->length();
		}
		else {
			QString* str = oText.line(0);
			if (str != 0) {
				col = str->length();
			}
			else {
				col = 0;
			}
		}
	}

	return QPoint(col, line);
}

void
CNConsole::doUpdate()
{
	int from = yOffset() / cellHeight();
	int to = (yOffset() + viewHeight()) / cellHeight();

#if (QT_VERSION >= 300)
	QPainter p(viewport());
#else
	QPainter p(this);
#endif

	p.setClipRect(0, 0, viewWidth(), viewHeight());
	p.setFont(oFont);

	setUpdatesEnabled(false);

#if (QT_VERSION >= 300)
#define OFFSET 0
#else
#define OFFSET 1
#endif

	for (int i = from; i <= to; i++) {
		p.resetXForm();
		p.translate(-xOffset() + OFFSET, i * cellHeight() - yOffset() + OFFSET);
		paintCell(&p, i, 0);
	}

#undef OFFSET

	setUpdatesEnabled(true);
}

#if (QT_VERSION >= 300)
bool
CNConsole::eventFilter(QObject* obj, QEvent* e)
{
	if (e->type() == QEvent::FocusIn) {
		QFocusEvent* fe = dynamic_cast<QFocusEvent*>(e);
		focusInEvent(fe);
	}
	else if (e->type() == QEvent::FocusOut) {
		QFocusEvent* fe = dynamic_cast<QFocusEvent*>(e);
		focusOutEvent(fe);
	}

	return QGridView::eventFilter(obj, e);
}

#endif

void
CNConsole::clearCursorBuffer()
{
	oCursorBuffer.fill(backgroundColor());
	oCursorBufferClear = true;
}

void
CNConsole::saveCursorBackground(int x, int y, int h, QWidget* src)
{
	if (oCursorBufferClear) {
		bitBlt(&oCursorBuffer, 0, 0, src, x, y, 1, h, CopyROP);
		oCursorBufferClear = false;
	}
}

void
CNConsole::restoreCursorBackground(int x, int y, int h, QWidget* dst)
{
	if (!oCursorBufferClear) {
		bitBlt(dst, x, y, &oCursorBuffer, 0, 0, 1, h + 1, CopyROP); // why h+1 ?
	}
}

void
CNConsole::updateCommandSet(const QString& cmds)
{
	oCmdSet = QStringList::split(QRegExp("[ \t\n]"), cmds);
	QStringList::Iterator it = oCmdSet.begin();

	while (it != oCmdSet.end()) {
		if ((*it).length() < 4) {
			QStringList::Iterator tmp = it++;
			oCmdSet.remove(tmp);
		}
		else {
			++it;
		}
	}
}

QStringList
CNConsole::cmdMatchList(const QString& cmd)
{
	QStringList list;
	QStringList::Iterator it = oCmdSet.begin();

	while (it != oCmdSet.end()) {
		if ((*it).length() >= cmd.length()) {
			QString f = (*it).left(cmd.length());
			if (f == cmd) {
				list.append(*it);
			}
		}

		++it;
	}

	return list;
}
