Commit bfcc2959 authored by Victor Yacovlev's avatar Victor Yacovlev

GUI: Implemented mouse select + right click copy from IO terminal

parent 9344eb8f
......@@ -230,25 +230,21 @@ Right click to navigate target</source>
<translation>До конца алгоритма</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="382"/>
<source>Unknown error</source>
<translation>Нераспознанная ошибка</translation>
<translation type="obsolete">Нераспознанная ошибка</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="383"/>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="392"/>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="432"/>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="419"/>
<source>Evaluation error</source>
<translation>Ошибка выполнения</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="392"/>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="440"/>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="427"/>
<source>Evaluation finished</source>
<translation>Выполнение завершено</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="423"/>
<location filename="../../../src/plugins/coregui/kumirprogram.cpp" line="410"/>
<source>Evaluation terminated</source>
<translation>Выполнение прервано</translation>
</message>
......@@ -804,58 +800,64 @@ p, li { white-space: pre-wrap; }
<context>
<name>Terminal::OneSession</name>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="87"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="129"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="272"/>
<source>&gt;&gt; %1:%2:%3 - %4 - Process started</source>
<translation>&gt;&gt; %1:%2:%3 - %4 - Начало выполнения</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="93"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="135"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="282"/>
<source>&gt;&gt; %1:%2:%3 - %4 - Process finished</source>
<translation>&gt;&gt; %1:%2:%3 - %4 - Выполнение завершено</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="239"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="334"/>
<source>INPUT </source>
<translation>ВВОД </translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="246"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="341"/>
<source>string</source>
<translation>лит</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="248"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="343"/>
<source>integer</source>
<translation>цел</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="250"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="345"/>
<source>real</source>
<translation>вещ</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="252"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="347"/>
<source>charect</source>
<translation>сим</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="254"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="349"/>
<source>boolean</source>
<translation>лог</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="409"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="504"/>
<source>Not a &apos;%1&apos; value</source>
<translation type="unfinished"></translation>
<translation>Это не значение типа %1</translation>
</message>
<message>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="445"/>
<location filename="../../../src/plugins/coregui/terminal_onesession.cpp" line="540"/>
<source>RUNTIME ERROR: %1</source>
<translation>ОШИБКА ВЫПОЛНЕНИЯ: %1</translation>
</message>
</context>
<context>
<name>Terminal::Plane</name>
<message>
<location filename="../../../src/plugins/coregui/terminal_plane.cpp" line="21"/>
<source>Copy to clipboard</source>
<translation>Копировать</translation>
</message>
</context>
<context>
<name>Terminal::Term</name>
<message>
......
......@@ -89,10 +89,10 @@ void Term::resizeEvent(QResizeEvent *e)
void Term::changeGlobalState(ExtensionSystem::GlobalState , ExtensionSystem::GlobalState current)
{
if (current==ExtensionSystem::GS_Unlocked || current==ExtensionSystem::GS_Observe) {
a_saveAll->setEnabled(l_sessions.size()>0);
a_saveLast->setEnabled(l_sessions.size()>0);
a_editLast->setEnabled(l_sessions.size()>0);
a_clear->setEnabled(l_sessions.size()>0);
a_saveAll->setEnabled(sessions_.size()>0);
a_saveLast->setEnabled(sessions_.size()>0);
a_editLast->setEnabled(sessions_.size()>0);
a_clear->setEnabled(sessions_.size()>0);
}
else {
a_saveAll->setEnabled(false);
......@@ -104,25 +104,25 @@ void Term::changeGlobalState(ExtensionSystem::GlobalState , ExtensionSystem::Glo
void Term::handleInputTextChanged(const QString &text)
{
if (l_sessions.isEmpty())
if (sessions_.isEmpty())
return;
OneSession * last = l_sessions.last();
OneSession * last = sessions_.last();
last->changeInputText(text);
}
void Term::handleInputCursorPositionChanged(quint16 pos)
{
if (l_sessions.isEmpty())
if (sessions_.isEmpty())
return;
OneSession * last = l_sessions.last();
OneSession * last = sessions_.last();
last->changeCursorPosition(pos);
}
void Term::handleInputFinishRequested()
{
if (l_sessions.isEmpty())
if (sessions_.isEmpty())
return;
OneSession * last = l_sessions.last();
OneSession * last = sessions_.last();
last->tryFinishInput();
}
......@@ -140,10 +140,10 @@ void Term::focusOutEvent(QFocusEvent *e)
void Term::clear()
{
for (int i=0; i<l_sessions.size(); i++) {
l_sessions[i]->deleteLater();
for (int i=0; i<sessions_.size(); i++) {
sessions_[i]->deleteLater();
}
l_sessions.clear();
sessions_.clear();
m_plane->update();
a_saveAll->setEnabled(false);
a_saveLast->setEnabled(false);
......@@ -156,12 +156,12 @@ void Term::start(const QString & fileName)
int fixedWidth = -1;
OneSession * session = new OneSession(fixedWidth, QFileInfo(fileName).fileName(), m_plane);
connect(session, SIGNAL(updateRequest()), m_plane, SLOT(update()));
l_sessions << session;
connect (l_sessions.last(), SIGNAL(inputDone(QVariantList)),
sessions_ << session;
connect (sessions_.last(), SIGNAL(inputDone(QVariantList)),
this, SIGNAL(inputFinished(QVariantList)));
connect (l_sessions.last(), SIGNAL(message(QString)),
connect (sessions_.last(), SIGNAL(message(QString)),
this, SIGNAL(message(QString)));
connect (l_sessions.last(), SIGNAL(inputDone(QVariantList)),
connect (sessions_.last(), SIGNAL(inputDone(QVariantList)),
this, SLOT(handleInputDone()));
m_plane->updateScrollBars();
if (sb_vertical->isEnabled())
......@@ -171,10 +171,10 @@ void Term::start(const QString & fileName)
void Term::finish()
{
if (l_sessions.isEmpty())
l_sessions << new OneSession(-1,"unknown", m_plane);
if (sessions_.isEmpty())
sessions_ << new OneSession(-1,"unknown", m_plane);
l_sessions.last()->finish();
sessions_.last()->finish();
m_plane->updateScrollBars();
if (sb_vertical->isEnabled())
sb_vertical->setValue(sb_vertical->maximum());
......@@ -182,9 +182,9 @@ void Term::finish()
void Term::terminate()
{
if (l_sessions.isEmpty())
l_sessions << new OneSession(-1,"unknown", m_plane);
l_sessions.last()->terminate();
if (sessions_.isEmpty())
sessions_ << new OneSession(-1,"unknown", m_plane);
sessions_.last()->terminate();
m_plane->updateScrollBars();
if (sb_vertical->isEnabled())
sb_vertical->setValue(sb_vertical->maximum());
......@@ -194,9 +194,9 @@ void Term::terminate()
void Term::output(const QString & text)
{
emit showWindowRequest();
if (l_sessions.isEmpty())
l_sessions << new OneSession(-1,"unknown", m_plane);
l_sessions.last()->output(text);
if (sessions_.isEmpty())
sessions_ << new OneSession(-1,"unknown", m_plane);
sessions_.last()->output(text);
// qDebug() << "output " << text;
m_plane->updateScrollBars();
if (sb_vertical->isEnabled())
......@@ -206,16 +206,16 @@ void Term::output(const QString & text)
void Term::input(const QString & format)
{
emit showWindowRequest();
if (l_sessions.isEmpty()) {
l_sessions << new OneSession(-1,"unknown", m_plane);
connect (l_sessions.last(), SIGNAL(inputDone(QVariantList)),
if (sessions_.isEmpty()) {
sessions_ << new OneSession(-1,"unknown", m_plane);
connect (sessions_.last(), SIGNAL(inputDone(QVariantList)),
this, SIGNAL(inputFinished(QVariantList)));
connect (l_sessions.last(), SIGNAL(message(QString)),
connect (sessions_.last(), SIGNAL(message(QString)),
this, SIGNAL(message(QString)));
connect (l_sessions.last(), SIGNAL(inputDone(QVariantList)),
connect (sessions_.last(), SIGNAL(inputDone(QVariantList)),
this, SLOT(handleInputDone()));
}
OneSession * lastSession = l_sessions.last();
OneSession * lastSession = sessions_.last();
......@@ -236,9 +236,9 @@ void Term::handleInputDone()
void Term::error(const QString & message)
{
emit showWindowRequest();
if (l_sessions.isEmpty())
l_sessions << new OneSession(-1,"unknown", m_plane);
l_sessions.last()->error(message);
if (sessions_.isEmpty())
sessions_ << new OneSession(-1,"unknown", m_plane);
sessions_.last()->error(message);
m_plane->updateScrollBars();
if (sb_vertical->isEnabled())
sb_vertical->setValue(sb_vertical->maximum());
......@@ -249,17 +249,17 @@ void Term::saveAll()
{
const QString suggestedFileName = QDir::current().absoluteFilePath("output-all.txt");
QString allText;
for (int i=0; i<l_sessions.size(); i++) {
allText += l_sessions[i]->plainText(true);
for (int i=0; i<sessions_.size(); i++) {
allText += sessions_[i]->plainText(true);
}
saveText(suggestedFileName, allText);
}
void Term::saveLast()
{
QString suggestedFileName = QDir::current().absoluteFilePath(l_sessions.last()->fileName());
QString suggestedFileName = QDir::current().absoluteFilePath(sessions_.last()->fileName());
suggestedFileName = suggestedFileName.left(suggestedFileName.length()-4)+"-out.txt";
saveText(suggestedFileName, l_sessions.last()->plainText(false));
saveText(suggestedFileName, sessions_.last()->plainText(false));
}
void Term::saveText(const QString &suggestedFileName, const QString &text)
......@@ -288,10 +288,10 @@ void Term::saveText(const QString &suggestedFileName, const QString &text)
void Term::editLast()
{
Q_ASSERT(!l_sessions.isEmpty());
QString suggestedFileName = QDir::current().absoluteFilePath(l_sessions.last()->fileName());
Q_ASSERT(!sessions_.isEmpty());
QString suggestedFileName = QDir::current().absoluteFilePath(sessions_.last()->fileName());
suggestedFileName = suggestedFileName.left(suggestedFileName.length()-4)+"-out.txt";
emit openTextEditor(suggestedFileName, l_sessions.last()->plainText(false));
emit openTextEditor(suggestedFileName, sessions_.last()->plainText(false));
}
} // namespace Terminal
......@@ -49,7 +49,7 @@ protected slots:
void handleInputDone();
private:
QList<class OneSession*> l_sessions;
QList<class OneSession*> sessions_;
QScrollBar * sb_vertical;
QScrollBar * sb_horizontal;
class Plane * m_plane;
......
This diff is collapsed.
......@@ -23,14 +23,18 @@ public:
OneSession(int fixedWidth, const QString & fileName, QWidget * parent);
QSize visibleSize(int realWidth) const;
QString plainText(bool footer_header) const;
inline QString fileName() const { return s_fileName; }
inline QDateTime startTime() const { return m_startTime; }
inline QDateTime endTime() const { return m_endTime; }
inline int fixedWidth() const { return i_fixedWidth; }
inline QString fileName() const { return fileName_; }
inline QDateTime startTime() const { return startTime_; }
inline QDateTime endTime() const { return endTime_; }
inline int fixedWidth() const { return fixedWidth_; }
void draw(QPainter * p, int realWidth);
inline void setFont(const QFont &font) { m_font = font; }
inline QFont font() const { return m_font; }
void triggerTextSelection(const QPoint & fromPos, const QPoint & toPos);
void clearSelection();
inline void setFont(const QFont &font) { font_ = font; }
inline QFont font() const { return font_; }
int widthInChars(int realWidth) const;
bool hasSelectedText() const;
QString selectedText() const;
public slots:
void output(const QString & text);
void input(const QString & format);
......@@ -47,22 +51,26 @@ signals:
void message(const QString & txt);
void inputDone(const QVariantList &);
private:
QPoint cursorPositionByVisiblePosition(const QPoint & pos) const;
QString headerText() const;
QString footerText() const;
QFont utilityFont() const;
void timerEvent(QTimerEvent * e);
QSize charSize() const;
QStringList m_lines;
QList<LineProp> m_props;
QString s_fileName;
QDateTime m_startTime;
QDateTime m_endTime;
QString s_inputFormat;
int i_fixedWidth;
QFont m_font;
int i_inputLineStart;
int i_inputPosStart;
int i_inputCursorPosition;
bool b_inputCursorVisible;
int i_timerId;
QWidget * parent_;
QStringList lines_;
QList<LineProp> props_;
QString fileName_;
QDateTime startTime_;
QDateTime endTime_;
QString inputFormat_;
int fixedWidth_;
QFont font_;
int inputLineStart_;
int inputPosStart_;
int inputCursorPosition_;
bool inputCursorVisible_;
int timerId_;
};
......
......@@ -2,34 +2,43 @@
#include "terminal.h"
#include "terminal_onesession.h"
#include <algorithm>
namespace Terminal {
static int sessionMargin = 4;
Plane::Plane(Term *parent)
: QWidget(parent)
, m_terminal(parent)
, terminal_(parent)
, inputMode_(false)
, inputPosition_(0)
, selectedSession_(nullptr)
, actionCopyToClipboard_(new QAction(this))
{
b_inputMode = false;
i_inputPosition = 0;
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
actionCopyToClipboard_->setText(tr("Copy to clipboard"));
connect(actionCopyToClipboard_, SIGNAL(triggered()),
this, SLOT(copyToClipboard()));
}
void Plane::keyPressEvent(QKeyEvent *e)
{
if (!b_inputMode) {
if (!inputMode_) {
e->ignore();
return;
}
if (e->matches(QKeySequence::MoveToNextChar)) {
i_inputPosition++;
emit inputCursorPositionChanged(i_inputPosition);
inputPosition_++;
emit inputCursorPositionChanged(inputPosition_);
e->accept();
}
else if (e->matches(QKeySequence::MoveToPreviousChar)) {
if (i_inputPosition>0) {
i_inputPosition --;
emit inputCursorPositionChanged(i_inputPosition);
if (inputPosition_>0) {
inputPosition_ --;
emit inputCursorPositionChanged(inputPosition_);
e->accept();
}
}
......@@ -37,38 +46,38 @@ void Plane::keyPressEvent(QKeyEvent *e)
|| e->matches(QKeySequence::MoveToStartOfDocument)
|| e->matches(QKeySequence::MoveToPreviousLine)
) {
i_inputPosition = 0;
emit inputCursorPositionChanged(i_inputPosition);
inputPosition_ = 0;
emit inputCursorPositionChanged(inputPosition_);
e->accept();
}
else if (e->matches(QKeySequence::MoveToEndOfLine)
|| e->matches(QKeySequence::MoveToEndOfDocument)
|| e->matches(QKeySequence::MoveToNextLine)
) {
i_inputPosition = s_inputText.length();
emit inputCursorPositionChanged(i_inputPosition);
inputPosition_ = inputText_.length();
emit inputCursorPositionChanged(inputPosition_);
e->accept();
}
else if (e->key()==Qt::Key_Backspace) {
if (i_inputPosition>0) {
if (i_inputPosition>s_inputText.length()) {
i_inputPosition = s_inputText.length();
emit inputCursorPositionChanged(i_inputPosition);
if (inputPosition_>0) {
if (inputPosition_>inputText_.length()) {
inputPosition_ = inputText_.length();
emit inputCursorPositionChanged(inputPosition_);
}
else {
s_inputText.remove(i_inputPosition-1, 1);
i_inputPosition --;
emit inputCursorPositionChanged(i_inputPosition);
emit inputTextChanged(s_inputText);
inputText_.remove(inputPosition_-1, 1);
inputPosition_ --;
emit inputCursorPositionChanged(inputPosition_);
emit inputTextChanged(inputText_);
}
e->accept();
}
}
else if (e->key()==Qt::Key_Delete) {
if (i_inputPosition<s_inputText.length()) {
s_inputText.remove(i_inputPosition, 1);
emit inputCursorPositionChanged(i_inputPosition);
emit inputTextChanged(s_inputText);
if (inputPosition_<inputText_.length()) {
inputText_.remove(inputPosition_, 1);
emit inputCursorPositionChanged(inputPosition_);
emit inputTextChanged(inputText_);
e->accept();
}
}
......@@ -77,54 +86,130 @@ void Plane::keyPressEvent(QKeyEvent *e)
e->accept();
}
else if (!e->text().isEmpty()) {
while (i_inputPosition>s_inputText.length())
s_inputText += " ";
s_inputText.insert(i_inputPosition, e->text());
i_inputPosition += e->text().length();
emit inputTextChanged(s_inputText);
emit inputCursorPositionChanged(i_inputPosition);
while (inputPosition_>inputText_.length())
inputText_ += " ";
inputText_.insert(inputPosition_, e->text());
inputPosition_ += e->text().length();
emit inputTextChanged(inputText_);
emit inputCursorPositionChanged(inputPosition_);
e->accept();
}
}
OneSession * Plane::sessionByPos(const QPoint &pos) const
{
OneSession * result = nullptr;
foreach (OneSession * session, terminal_->sessions_) {
if (sessionRect(session).contains(pos)) {
result = session;
break;
}
}
return result;
}
QRect Plane::sessionRect(const OneSession *session) const
{
QRect result(offset() + QPoint(sessionMargin, 0), QSize(0,0));
foreach (const OneSession * s, terminal_->sessions_) {
result.setSize(s->visibleSize(width()-2*sessionMargin));
if (session==s)
break;
result.translate(0, result.height()+sessionMargin);
}
result.setWidth(qMax(result.width(), width()-2*sessionMargin));
return result;
}
void Plane::mousePressEvent(QMouseEvent *e)
{
setFocus();
e->accept();
selectedSession_ = sessionByPos(e->pos());
mousePressPosition_ = e->pos();
if (e->button()!=Qt::RightButton) {
for (int i=0; i<terminal_->sessions_.size(); i++) {
terminal_->sessions_.at(i)->clearSelection();
}
}
update();
}
void Plane::mouseMoveEvent(QMouseEvent *e)
{
e->accept();
if (selectedSession_) {
const QPoint sessionOffset = sessionRect(selectedSession_).topLeft();
const QPoint fromPos = mousePressPosition_ - sessionOffset;
const QPoint toPos = e->pos() - sessionOffset;
selectedSession_->triggerTextSelection(fromPos, toPos);
update();
}
}
void Plane::mouseReleaseEvent(QMouseEvent *e)
{
e->accept();
}
QPoint Plane::offset() const
{
QPoint result(0,0);
if (m_terminal->sb_horizontal->isEnabled()) {
int valX = m_terminal->sb_horizontal->value();
if (terminal_->sb_horizontal->isEnabled()) {
int valX = terminal_->sb_horizontal->value();
result.setX(-valX);
}
if (m_terminal->sb_vertical->isEnabled()) {
int valY = m_terminal->sb_vertical->value();
if (terminal_->sb_vertical->isEnabled()) {
int valY = terminal_->sb_vertical->value();
result.setY(-valY);
}
return result;
}
void Plane::contextMenuEvent(QContextMenuEvent * event)
{
event->accept();
bool canCopyToClipboard = false;
foreach (const OneSession * s, terminal_->sessions_) {
canCopyToClipboard = canCopyToClipboard || s->hasSelectedText();
}
bool hasAnyAction = canCopyToClipboard;
if (hasAnyAction) {
QMenu * menu = new QMenu(this);
if (canCopyToClipboard)
menu->addAction(actionCopyToClipboard_);
menu->exec(mapToGlobal(event->pos()));
}
}