This commit is contained in:
Igor Malinovskiy
2013-11-27 12:05:30 +02:00
parent d2bb225101
commit a6ba4fe672
5 changed files with 1049 additions and 0 deletions
+1
View File
@@ -46,3 +46,4 @@ deps/libssh/src/Makefile
deps/libssh/src/stamp-h1
build-tests-*/*
tests/Makefile
deps/jsoncpp/buildscons/*
@@ -0,0 +1,221 @@
/* -*- mode: c++ -*- */
/***************************************************************************
qconsole.h - description
-------------------
begin : mar mar 15 2005
copyright : (C) 2005 by Houssem BDIOUI
email : houssem.bdioui@gmail.com
***************************************************************************/
// migrated to Qt4 by YoungTaek Oh. date: Nov 29, 2010
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QCONSOLE_H
#define QCONSOLE_H
#include <QStringList>
#include <QTextEdit>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QMenu>
#include <QDialog>
#include <QListWidget>
#include <QDebug>
/**
* Subclasssing QListWidget
*
* @author YoungTaek Oh
*/
class PopupListWidget : public QListWidget
{
Q_OBJECT
public:
PopupListWidget(QWidget *parent = 0): QListWidget(parent) {
setUniformItemSizes(true);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
virtual ~PopupListWidget() { }
protected:
virtual QSize sizeHint() const;
virtual void keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Tab ||
e->key() == Qt::Key_Return)
Q_EMIT itemActivated(currentItem());
else
QListWidget::keyPressEvent(e);
}
};
/**
* Popup Completer class
*
* @author YoungTaek Oh
* @todo 1. beautifying
* 2. icons for classifying words (eg. functions, properties...)
* 3. bugs?
* @note still experimental
*/
class PopupCompleter : public QDialog
{
Q_OBJECT
public:
PopupCompleter(const QStringList&, QWidget *parent = 0);
virtual ~PopupCompleter();
public:
QString selected(void) { return selected_; }
int exec(QTextEdit*);
protected:
virtual void showEvent(QShowEvent*);
private Q_SLOTS:
void onItemActivated(QListWidgetItem*);
public:
QListWidget *listWidget_;
QString selected_;
};
/**
* An abstract Qt console
* @author Houssem BDIOUI
*/
class QConsole : public QTextEdit
{
Q_OBJECT
public:
//constructor
QConsole(QWidget *parent = NULL, const QString &welcomeText = "");
//set the prompt of the console
void setPrompt(const QString &prompt, bool display = true);
//execCommand(QString) executes the command and displays back its result
bool execCommand(const QString &command, bool writeCommand = true,
bool showPrompt = true, QString *result = NULL);
//clear & reset the console (useful sometimes)
void clear();
void reset(const QString &welcomeText = "");
//cosmetic methods !
// @{
/// get/set command color
QColor cmdColor() const { return cmdColor_; }
void setCmdColor(QColor c) {cmdColor_ = c;}
// @}
// @{
/// get/set error color
QColor errColor() const { return errColor_; }
void setErrColor(QColor c) {errColor_ = c;}
// @}
// @{
/// get/set output color
QColor outColor() const { return outColor_; }
void setOutColor(QColor c) {outColor_ = c;}
// @}
void setCompletionColor(QColor c) {completionColor = c;}
// @{
/// get set font
void setFont(const QFont& f);
QFont font() const { return currentFont(); }
// @}
void correctPathName(QString& pathName);
private:
void dropEvent( QDropEvent * event);
void dragMoveEvent( QDragMoveEvent * event);
void keyPressEvent(QKeyEvent * e);
void contextMenuEvent( QContextMenuEvent * event);
//Return false if the command is incomplete (e.g. unmatched braces)
virtual bool isCommandComplete(const QString &command);
//Get the command to validate
QString getCurrentCommand();
//Replace current command with a new one
void replaceCurrentCommand(const QString &newCommand);
//Test whether the cursor is in the edition zone
bool isInEditionZone();
bool isInEditionZone(const int& pos);
//Test whether the selection is in the edition zone
bool isSelectionInEditionZone();
//Change paste behaviour
void insertFromMimeData(const QMimeData *);
//protected attributes
protected:
//colors
QColor cmdColor_, errColor_, outColor_, completionColor;
int oldPosition;
// cached prompt length
int promptLength;
// The prompt string
QString prompt;
// The commands history
QStringList history;
//Contains the commands that has succeeded
QStringList recordedScript;
// Current history index (needed because afaik QStringList does not have such an index)
int historyIndex;
//Holds the paragraph number of the prompt (useful for multi-line command handling)
int promptParagraph;
protected:
//Implement paste with middle mouse button
void mousePressEvent(QMouseEvent*);
//execute a validated command (should be reimplemented and called at the end)
//the return value of the function is the string result
//res must hold back the return value of the command (0: passed; else: error)
virtual QString interpretCommand(const QString &command, int *res);
//give suggestions to autocomplete a command (should be reimplemented)
//the return value of the function is the string list of all suggestions
//the returned prefix is useful to complete "sub-commands"
virtual QStringList suggestCommand(const QString &cmd, QString &prefix);
public Q_SLOTS:
//Contextual menu slots
void cut();
//void paste();
void del();
//displays the prompt
void displayPrompt();
Q_SIGNALS:
//Signal emitted after that a command is executed
void commandExecuted(const QString &command);
private:
void handleTabKeyPress();
void handleReturnKeyPress();
bool handleBackspaceKeyPress();
void handleUpKeyPress();
void handleDownKeyPress();
void setHome(bool);
};
#endif
@@ -38,6 +38,9 @@
<ClCompile Include="GeneratedFiles\Debug\moc_KeysTreeRenderer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_qconsole.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_qxtsshchannel.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
@@ -113,6 +116,9 @@
<ClCompile Include="GeneratedFiles\Release\moc_KeysTreeRenderer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_qconsole.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_qxtsshchannel.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
@@ -190,6 +196,7 @@
<ClCompile Include="source\updater\Updater.cpp" />
<ClCompile Include="source\widgets\ConnectionTreeView.cpp" />
<ClCompile Include="source\widgets\consoleTab.cpp" />
<ClCompile Include="source\widgets\qconsole.cpp" />
<ClCompile Include="source\widgets\ValueTabView.cpp" />
<ClCompile Include="source\widgets\valueViewTab.cpp" />
<ClCompile Include="source\widgets\serverInfoViewTab.cpp" />
@@ -381,6 +388,16 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -DQT_CONCURRENT_LIB "-I." "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I$(QTDIR)\include\QtConcurrent" "-I$(SolutionDir)\deps\json-cpp\include" "-I$(SolutionDir)\deps\libssh\include"</Command>
</CustomBuild>
<CustomBuild Include="include\widgets\qconsole.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing qconsole.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -DQT_CONCURRENT_LIB "-I." "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I$(QTDIR)\include\QtConcurrent" "-I$(SolutionDir)\deps\jsoncpp\include" "-I$(SolutionDir)\deps\libssh\include"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing qconsole.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -DQT_CONCURRENT_LIB "-I." "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I$(QTDIR)\include\QtConcurrent" "-I$(SolutionDir)\deps\jsoncpp\include" "-I$(SolutionDir)\deps\libssh\include"</Command>
</CustomBuild>
<ClInclude Include="include\widgets\ValueTabView.h" />
<ClInclude Include="resource.h" />
<CustomBuild Include="include\widgets\valueViewTab.h">
@@ -332,6 +332,15 @@
<ClCompile Include="source\models\value-view-formatters\PHPSerializeFormatter.cpp">
<Filter>Source Files\models\value-view-formatters</Filter>
</ClCompile>
<ClCompile Include="source\widgets\qconsole.cpp">
<Filter>Source Files\widgets</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_qconsole.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_qconsole.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="include\connection.h">
@@ -418,6 +427,9 @@
<CustomBuild Include="include\widgets\ConnectionTreeView.h">
<Filter>Header Files\widgets</Filter>
</CustomBuild>
<CustomBuild Include="include\widgets\qconsole.h">
<Filter>Header Files\widgets</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\models\HashKeyModel.h">
@@ -0,0 +1,798 @@
/***************************************************************************
qconsole.cpp - description
-------------------
begin : mar mar 15 2005
copyright : (C) 2005 by Houssem BDIOUI
email : houssem.bdioui@gmail.com
***************************************************************************/
// migrated to Qt4 by YoungTaek Oh. date: Nov 29, 2010
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qconsole.h"
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QVBoxLayout>
#include <QApplication>
#include <QScrollBar>
#include <QDesktopWidget>
//#define USE_POPUP_COMPLETER
#define WRITE_ONLY QIODevice::WriteOnly
QSize PopupListWidget::sizeHint() const
{
QAbstractItemModel *model = this->model();
QAbstractItemDelegate *delegate = this->itemDelegate();
const QStyleOptionViewItem sovi;
int left, top, right, bottom = 0;
QMargins margin = this->contentsMargins();
top = margin.top();
bottom = margin.bottom();
left = margin.left();
right = margin.right();
const int vOffset = top + bottom;
const int hOffset = left + right;
bool vScrollOn = false;
int height = 0;
int width = 0;
for (int i=0; i<this->count(); ++i) {
QModelIndex index = model->index(i, 0);
QSize itemSizeHint = delegate->sizeHint(sovi, index);
if (itemSizeHint.width() > width)
width = itemSizeHint.width();
// height
const int nextHeight = height + itemSizeHint.height();
if (nextHeight + vOffset < this->maximumHeight())
height = nextHeight;
else {
// early termination
vScrollOn = true;
break;
}
}
QSize sizeHint(width + hOffset, 0);
sizeHint.setHeight(height + vOffset);
if (vScrollOn) {
int scrollWidth = this->verticalScrollBar()->sizeHint().width();
sizeHint.setWidth(sizeHint.width() + scrollWidth);
}
return sizeHint;
}
PopupCompleter::PopupCompleter(const QStringList& sl, QWidget *parent)
: QDialog(parent, Qt::Popup)
{
setModal(true);
listWidget_ = new PopupListWidget();
listWidget_->setMaximumHeight(200);
qDebug() << "sizeHint(): " << listWidget_->sizeHint();
Q_FOREACH(QString str, sl) {
QListWidgetItem *item = new QListWidgetItem;
item->setText(str);
listWidget_->addItem(item);
}
qDebug() << "sizeHint(): " << listWidget_->sizeHint();
listWidget_->setFixedSize(listWidget_->sizeHint());
QLayout *layout = new QVBoxLayout();
layout->setSizeConstraint(QLayout::SetFixedSize);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(listWidget_);
setLayout(layout);
// connect signal
connect(listWidget_, SIGNAL(itemActivated(QListWidgetItem *)),
SLOT(onItemActivated(QListWidgetItem*)));
}
PopupCompleter::~PopupCompleter()
{
}
void PopupCompleter::showEvent(QShowEvent *event)
{
listWidget_->setFocus();
}
void PopupCompleter::onItemActivated(QListWidgetItem *event)
{
selected_ = event->text();
done(QDialog::Accepted);
}
/**
* @brief execute PopupCompleter at appropriate position.
*
* @param parent Parent of this popup completer. usually QConsole.
* @return see QDialog::exec
* @see QDialog::exec
*/
int PopupCompleter::exec(QTextEdit *parent)
{
QSize popupSizeHint = this->sizeHint();
QRect cursorRect = parent->cursorRect();
QPoint globalPt = parent->mapToGlobal(cursorRect.bottomRight());
QDesktopWidget *dsk = QApplication::desktop();
QRect screenGeom = dsk->screenGeometry(dsk->screenNumber(this));
if (globalPt.y() + popupSizeHint.height() > screenGeom.height()) {
globalPt = parent->mapToGlobal(cursorRect.topRight());
globalPt.setY(globalPt.y() - popupSizeHint.height());
}
this->move(globalPt);
this->setFocus();
return QDialog::exec();
}
/**
* returns a common word of the given list
*
* @param list String list
*
* @return common word in the given string.
*/
static
QString getCommonWord(QStringList& list)
{
QChar ch;
QVector<QString> strarray = list.toVector();
QString common;
int col = 0, min_len;
bool cont = true;
// get minimum length
min_len = strarray.at(0).size();
for (int i=1; i<strarray.size(); ++i) {
const int len = strarray.at(i).size();
if (len < min_len)
min_len = len;
}
while(col < min_len) {
ch = strarray.at(0)[col];
for (int i=1; i<strarray.size(); ++i) {
const QString& current_string = strarray.at(i);
if (ch != current_string[col])
{
cont = false;
break;
}
}
if (!cont)
break;
common.push_back(ch);
++col;
}
return common;
}
////////////////////////////////////////////////////////////////////////////////
//Clear the console
void QConsole::clear()
{
QTextEdit::clear();
}
//Reset the console
void QConsole::reset(const QString &welcomeText)
{
clear();
//set the style of the QTextEdit
#ifdef __APPLE__
setCurrentFont(QFont("Monaco"));
#else
QFont f;
f.setFamily("Courier");
setCurrentFont(f);
#endif
append(welcomeText);
append("");
//init attributes
historyIndex = 0;
history.clear();
recordedScript.clear();}
//QConsole constructor (init the QTextEdit & the attributes)
QConsole::QConsole(QWidget *parent, const QString &welcomeText)
: QTextEdit(parent), errColor_(Qt::red),
outColor_(Qt::blue), completionColor(Qt::darkGreen),
promptLength(0), promptParagraph(0)
{
QPalette palette = QApplication::palette();
setCmdColor(palette.text().color());
//Disable undo/redo
setUndoRedoEnabled(false);
//Disable context menu
//This menu is useful for undo/redo, cut/copy/paste, del, select all,
// see function QConsole::contextMenuEvent(...)
//setContextMenuPolicy(Qt::NoContextMenu);
//resets the console
reset(welcomeText);
const int tabwidth = QFontMetrics(currentFont()).width('a') * 4;
setTabStopWidth(tabwidth);}
//Sets the prompt and cache the prompt length to optimize the processing speed
void QConsole::setPrompt(const QString &newPrompt, bool display)
{
prompt = newPrompt;
promptLength = prompt.length();
//display the new prompt
if (display)
displayPrompt();
}
//Displays the prompt and move the cursor to the end of the line.
void QConsole::displayPrompt()
{
//Prevent previous text displayed to be undone
setUndoRedoEnabled(false);
//displays the prompt
setTextColor(cmdColor_);
QTextCursor cur = textCursor();
cur.insertText(prompt);
cur.movePosition(QTextCursor::EndOfLine);
setTextCursor(cur);
//Saves the paragraph number of the prompt
promptParagraph = cur.blockNumber();
//Enable undo/redo for the actual command
setUndoRedoEnabled(true);
}
void QConsole::setFont(const QFont& f) {
QTextCharFormat format;
QTextCursor oldCursor = textCursor();
format.setFont(f);
selectAll();
textCursor().setBlockCharFormat(format);
setCurrentFont(f);
setTextCursor(oldCursor);
}
//Give suggestions to autocomplete a command (should be reimplemented)
//the return value of the function is the string list of all suggestions
QStringList QConsole::suggestCommand(const QString&, QString& prefix)
{
prefix = "";
return QStringList();
}
//Treat the tab key & autocomplete the current command
void QConsole::handleTabKeyPress()
{
QString command = getCurrentCommand();
QString commandPrefix;
QStringList sl = suggestCommand(command, commandPrefix);
if (sl.count() == 0)
textCursor().insertText("\t");
else {
if (sl.count() == 1)
replaceCurrentCommand(commandPrefix + sl[0]);
else
{
// common word completion
QString commonWord = getCommonWord(sl);
command = commonWord;
PopupCompleter *popup = new PopupCompleter(sl);
if (popup->exec(this) == QDialog::Accepted)
replaceCurrentCommand(commandPrefix + popup->selected());
delete popup;
}
}
}
// If return pressed, do the evaluation and append the result
void QConsole::handleReturnKeyPress()
{
//Get the command to validate
QString command = getCurrentCommand();
//execute the command and get back its text result and its return value
if (isCommandComplete(command))
execCommand(command, false);
else
{
append("");
moveCursor(QTextCursor::EndOfLine);
}
}
bool QConsole::handleBackspaceKeyPress()
{
QTextCursor cur = textCursor();
const int col = cur.columnNumber();
const int blk = cur.blockNumber();
if (blk == promptParagraph && col == promptLength)
return true;
return false;
}
void QConsole::handleUpKeyPress()
{
if (history.count())
{
QString command = getCurrentCommand();
do
{
if (historyIndex)
historyIndex--;
else
{
break;
}
} while(history[historyIndex] == command);
replaceCurrentCommand(history[historyIndex]);
}
}
void QConsole::handleDownKeyPress()
{
if (history.count())
{
QString command = getCurrentCommand();
do
{
if (++historyIndex >= history.size())
{
historyIndex = history.size() - 1;
break;
}
} while(history[historyIndex] == command);
replaceCurrentCommand(history[historyIndex]);
}
}
void QConsole::setHome(bool select)
{
QTextCursor cursor = textCursor();
cursor.movePosition(QTextCursor::StartOfBlock, select ? QTextCursor::KeepAnchor :
QTextCursor::MoveAnchor);
if(textCursor().blockNumber() == promptParagraph)
{
cursor.movePosition(QTextCursor::Right, select ? QTextCursor::KeepAnchor :
QTextCursor::MoveAnchor,
promptLength);
}
setTextCursor(cursor);
}
//Reimplemented key press event
void QConsole::keyPressEvent( QKeyEvent *e )
{
//If the user wants to copy or cut outside
//the editing area we perform a copy
if(textCursor().hasSelection())
{
if(e->modifiers() == Qt::CTRL)
{
if( e->matches(QKeySequence::Cut) )
{
e->accept();
if(!isInEditionZone())
{
copy();
}
else
{
cut();
}
return;
}
else if(e->matches(QKeySequence::Copy) )
{
e->accept();
copy();
}
else
{
QTextEdit::keyPressEvent( e );
return;
}
}
}
/*
// if the cursor out of editing zone put it back first
if(!isInEditionZone())
{
QTextCursor editCursor = textCursor();
editCursor.setPosition(oldEditPosition);
setTextCursor(editCursor);
}
*/
// control is pressed
if ( (e->modifiers() & Qt::ControlModifier) && (e->key() == Qt::Key_C) )
{
if ( isSelectionInEditionZone())
{
//If Ctrl + C pressed, then undo the current commant
//append("");
//displayPrompt();
//(Thierry Belair:)I humbly suggest that ctrl+C copies the text, as is expected,
//and indicated in the contextual menu
copy();
return;
}
}
else {
switch (e->key()) {
case Qt::Key_Tab:
if(isSelectionInEditionZone())
{
handleTabKeyPress();
}
return;
case Qt::Key_Enter:
case Qt::Key_Return:
if (isSelectionInEditionZone())
{
handleReturnKeyPress();
}
// ignore return key
return;
case Qt::Key_Backspace:
if (handleBackspaceKeyPress() || !isSelectionInEditionZone())
return;
break;
case Qt::Key_Home:
setHome(e->modifiers() & Qt::ShiftModifier);
case Qt::Key_Down:
if (isInEditionZone())
{
handleDownKeyPress();
}
return;
case Qt::Key_Up:
if (isInEditionZone())
{
handleUpKeyPress();
}
return;
//Default behaviour
case Qt::Key_End:
case Qt::Key_Left:
case Qt::Key_Right:
break;
default:
if (textCursor().hasSelection() ) {
if (!isSelectionInEditionZone())
{
moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
}
break;
}
else
{ //no selection
//when typing normal characters,
//make sure the cursor is positionned in the
//edition zone
if ( !isInEditionZone() )
{
moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
}
}
} //end of switch
} //end of else : no control pressed
QTextEdit::keyPressEvent( e );
}
//Get the current command
QString QConsole::getCurrentCommand()
{
QTextCursor cursor = textCursor(); //Get the current command: we just remove the prompt
cursor.movePosition(QTextCursor::StartOfLine);
cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, promptLength);
cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
QString command = cursor.selectedText();
cursor.clearSelection();
return command;
}
//Replace current command with a new one
void QConsole::replaceCurrentCommand(const QString &newCommand)
{
QTextCursor cursor = textCursor();
cursor.movePosition(QTextCursor::StartOfLine);
cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, promptLength);
cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
cursor.insertText(newCommand);
}
//default implementation: command always complete
bool QConsole::isCommandComplete(const QString &)
{
return true;
}
//Tests whether the cursor is in th edition zone or not (after the prompt
//or in the next lines (in case of multi-line mode)
bool QConsole::isInEditionZone()
{
const int para = textCursor().blockNumber();
const int index = textCursor().columnNumber();
return (para > promptParagraph) || ( (para == promptParagraph) && (index >= promptLength) );
}
//Tests whether position (in parameter) is in the edition zone or not (after the prompt
//or in the next lines (in case of multi-line mode)
bool QConsole::isInEditionZone(const int& pos)
{
QTextCursor cur = textCursor();
cur.setPosition(pos);
const int para = cur.blockNumber();
const int index = cur.columnNumber();
return (para > promptParagraph) || ( (para == promptParagraph) && (index >= promptLength) );
}
//Tests whether the current selection is in th edition zone or not
bool QConsole::isSelectionInEditionZone()
{
QTextCursor cursor(document());
int range[2];
range[0] = textCursor().selectionStart();
range[1] = textCursor().selectionEnd();
for (int i = 0; i < 2; i++)
{
cursor.setPosition(range[i]);
int para = cursor.blockNumber();
int index = cursor.columnNumber();
if ((para <= promptParagraph) && ( (para != promptParagraph) || (index < promptLength) ))
{
return false;
}
}
return true;
}
//Basically, puts the command into the history list
//And emits a signal (should be called by reimplementations)
QString QConsole::interpretCommand(const QString &command, int *res)
{
//Add the command to the recordedScript list
if (!*res)
recordedScript.append(command);
//update the history and its index
QString modifiedCommand = command;
modifiedCommand.replace("\n", "\\n");
history.append(modifiedCommand);
historyIndex = history.size();
//emit the commandExecuted signal
Q_EMIT commandExecuted(modifiedCommand);
return "";
}
//execCommand(QString) executes the command and displays back its result
bool QConsole::execCommand(const QString &command, bool writeCommand,
bool showPrompt, QString *result)
{
QString modifiedCommand = command;
correctPathName(modifiedCommand);
//Display the prompt with the command first
if (writeCommand)
{
if (getCurrentCommand() != "")
{
append("");
displayPrompt();
}
textCursor().insertText(modifiedCommand);
}
//execute the command and get back its text result and its return value
int res = 0;
QString strRes = interpretCommand(modifiedCommand, &res);
//According to the return value, display the result either in red or in blue
if (res == 0)
setTextColor(outColor_);
else
setTextColor(errColor_);
if(result){
*result = strRes;
}
if (!(strRes.isEmpty() || strRes.endsWith("\n")))
strRes.append("\n");
append(strRes);
moveCursor(QTextCursor::End);
//Display the prompt again
if (showPrompt)
displayPrompt();
return !res;
}
//Change paste behaviour
void QConsole::insertFromMimeData(const QMimeData *source)
{
if (isSelectionInEditionZone())
{
QTextEdit::insertFromMimeData(source);
}
}
//Implement paste with middle mouse button
void QConsole::mousePressEvent(QMouseEvent* event)
{
oldPosition = textCursor().position();
if (event->button() == Qt::MidButton)
{
copy();
QTextCursor cursor = cursorForPosition(event->pos());
setTextCursor(cursor);
paste();
return;
}
QTextEdit::mousePressEvent(event);
}
//Redefinition of the dropEvent to have a copy paste
//instead of a cut paste when copying out of the
//editable zone
void QConsole::dropEvent ( QDropEvent * event)
{
if(!isInEditionZone())
{
//Execute un drop a drop at the old position
//if the drag started out of the editable zone
QTextCursor cur = textCursor();
cur.setPosition(oldPosition);
setTextCursor(cur);
}
//Execute a normal drop
QTextEdit::dropEvent(event);
}
void QConsole::dragMoveEvent( QDragMoveEvent * event)
{
//Get a cursor for the actual mouse position
QTextCursor cur = textCursor();
cur.setPosition(cursorForPosition(event->pos()).position());
if(!isInEditionZone(cursorForPosition(event->pos()).position()))
{
//Ignore the event if out of the editable zone
event->ignore(cursorRect(cur));
}
else
{
//Accept the event if out of the editable zone
event->accept(cursorRect(cur));
}
}
void QConsole::contextMenuEvent ( QContextMenuEvent * event)
{
QMenu *menu = new QMenu(this);
QAction *undo = new QAction(tr("Undo"), this);
undo->setShortcut(tr("Ctrl+Z"));
QAction *redo = new QAction(tr("Redo"), this);
redo->setShortcut(tr("Ctrl+Y"));
QAction *cut = new QAction(tr("Cut"), this);
cut->setShortcut(tr("Ctrl+X"));
QAction *copy = new QAction(tr("Copy"), this);
copy->setShortcut(tr("Ctrl+Ins"));
QAction *paste = new QAction(tr("Paste"), this);
paste->setShortcut(tr("Ctrl+V"));
QAction *del = new QAction(tr("Delete"), this);
del->setShortcut(tr("Del"));
QAction *selectAll = new QAction(tr("Select All"), this);
selectAll->setShortcut(tr("Ctrl+A"));
menu->addAction(undo);
menu->addAction(redo);
menu->addSeparator();
menu->addAction(cut);
menu->addAction(copy);
menu->addAction(paste);
menu->addAction(del);
menu->addSeparator();
menu->addAction(selectAll);
connect(undo, SIGNAL(triggered()), this, SLOT(undo()));
connect(redo, SIGNAL(triggered()), this, SLOT(redo()));
connect(cut, SIGNAL(triggered()), this, SLOT(cut()));
connect(copy, SIGNAL(triggered()), this, SLOT(copy()));
connect(paste, SIGNAL(triggered()), this, SLOT(paste()));
connect(del, SIGNAL(triggered()), this, SLOT(del()));
connect(selectAll, SIGNAL(triggered()), this, SLOT(selectAll()));
menu->exec(event->globalPos());
delete menu;
}
void QConsole::cut()
{
//Cut only in the editing zone,
//perfom a copy otherwise
if(isInEditionZone())
{
QTextEdit::cut();
return;
}
QTextEdit::copy();
}
/*
//Allows pasting with middle mouse button (x window)
//when clicking outside of the edition zone
void QConsole::paste()
{
restoreOldPosition();
QTextEdit::paste();
}
*/
void QConsole::del()
{
//Delete only in the editing zone
if(isInEditionZone())
{
textCursor().movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
textCursor().deleteChar();
}
}
void QConsole::correctPathName(QString& pathName)
{
if(pathName.contains(tr(":\\")))
{
pathName.replace('\\', tr("/"));
}
}