mirror of
https://github.com/redis/RedisDesktopManager.git
synced 2026-10-28 02:56:32 +08:00
Init
This commit is contained in:
@@ -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("/"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user