From 40cba847c1af988dd2a381320d06e3b052a87c45 Mon Sep 17 00:00:00 2001 From: bruneton Date: Thu, 4 Apr 2013 14:43:53 +0000 Subject: [PATCH] PyConsole: fix multi-line pasting. Code on several lines can now be pasted properly (including with indentation). --- src/PyConsole/PyConsole_Editor.cxx | 5 ++ src/PyConsole/PyConsole_EnhEditor.cxx | 92 +++++++++++++++++++++++++-- src/PyConsole/PyConsole_EnhEditor.h | 13 +++- 3 files changed, 103 insertions(+), 7 deletions(-) diff --git a/src/PyConsole/PyConsole_Editor.cxx b/src/PyConsole/PyConsole_Editor.cxx index aac8a4d4b..cee79f245 100644 --- a/src/PyConsole/PyConsole_Editor.cxx +++ b/src/PyConsole/PyConsole_Editor.cxx @@ -315,6 +315,8 @@ void PyConsole_Editor::addText( const QString& str, \brief Convenient method for executing a Python command, as if the user typed it manually. \param command python command to be executed + + !!! WARNING: doesn't work properly with multi-line commands. !!! */ void PyConsole_Editor::exec( const QString& command ) { @@ -395,6 +397,9 @@ void PyConsole_Editor::execAndWait( const QString& command ) */ void PyConsole_Editor::handleReturn() { + // Position cursor at the end + textCursor().movePosition(QTextCursor::End); + // get last line QTextBlock par = document()->end().previous(); if ( !par.isValid() ) return; diff --git a/src/PyConsole/PyConsole_EnhEditor.cxx b/src/PyConsole/PyConsole_EnhEditor.cxx index aaec2b1d8..de089a805 100644 --- a/src/PyConsole/PyConsole_EnhEditor.cxx +++ b/src/PyConsole/PyConsole_EnhEditor.cxx @@ -46,7 +46,9 @@ const std::vector PyConsole_EnhEditor::SEPARATORS = \ PyConsole_EnhEditor::PyConsole_EnhEditor(PyConsole_EnhInterp * interp, QWidget * parent) : PyConsole_Editor(interp, parent), _tab_mode(false), - _cursor_pos(-1) + _cursor_pos(-1), + _multi_line_paste(false), + _multi_line_content() { document()->setUndoRedoEnabled(true); } @@ -318,9 +320,14 @@ void PyConsole_EnhEditor::customEvent( QEvent* event ) _tab_mode = false; _cursor_pos = -1; break; -// case PyEnhInterp_Event::ES_MULTI_PASTE: -// multilinePaste(); -// break; + case PyInterp_Event::ES_OK: + case PyInterp_Event::ES_ERROR: + case PyInterp_Event::ES_INCOMPLETE: + // Before everything else, call super() + PyConsole_Editor::customEvent(event); + // If we are in multi_paste_mode, process the next item: + multiLineProcessNextLine(); + break; default: PyConsole_Editor::customEvent( event ); break; @@ -388,3 +395,80 @@ QString PyConsole_EnhEditor::formatDocHTML(const QString & doc) const rest = rest.replace("\n", " "); return templ.arg(fst).arg(rest); } + +/** + * Handle properly multi-line pasting. Qt4 doc recommends overriding this function. + * If the pasted text doesn't contain a line return, no special treatment is done. + * @param source + */ +void PyConsole_EnhEditor::insertFromMimeData(const QMimeData * source) +{ + if (_multi_line_paste) + return; + + if (source->hasText()) + { + QString s = source->text(); + if (s.contains("\n")) + multilinePaste(s); + else + PyConsole_Editor::insertFromMimeData(source); + } + else + { + PyConsole_Editor::insertFromMimeData(source); + } +} + + +void PyConsole_EnhEditor::multilinePaste(const QString & s) +{ + // Turn on multi line pasting mode + _multi_line_paste = true; + + // Split the string: + QString s2 = s; + s2.replace("\r", ""); // Windows string format converted to Unix style + + QStringList lst = s2.split(QChar('\n'), QString::KeepEmptyParts); + + // Perform the proper paste operation for the first line to handle the case where + // sth was already there: + QMimeData source; + source.setText(lst[0]); + PyConsole_Editor::insertFromMimeData(&source); + + // Prepare what will have to be executed after the first line: + _multi_line_content = std::queue(); + for (int i = 1; i < lst.size(); ++i) + _multi_line_content.push(lst[i]); + + // Trigger the execution of the first (mixed) line + handleReturn(); + + // See customEvent() and multiLineProcessNext() for the rest of the handling. +} + +/** + * Process the next line in the queue of a multiple copy/paste: + */ +void PyConsole_EnhEditor::multiLineProcessNextLine() +{ + if (!_multi_line_paste) + return; + + QString line(_multi_line_content.front()); + _multi_line_content.pop(); + if (!_multi_line_content.size()) + { + // last line in the queue, just paste it + addText(line, false, false); + _multi_line_paste = false; + } + else + { + // paste the line and simulate a key stroke + addText(line, false, false); + handleReturn(); + } +} diff --git a/src/PyConsole/PyConsole_EnhEditor.h b/src/PyConsole/PyConsole_EnhEditor.h index 2500fc9e9..f52dc8256 100644 --- a/src/PyConsole/PyConsole_EnhEditor.h +++ b/src/PyConsole/PyConsole_EnhEditor.h @@ -26,6 +26,7 @@ #include "PyConsole_Editor.h" #include +#include class PyConsole_EnhInterp; @@ -66,13 +67,17 @@ protected: /** Cursor position when is hit */ int _cursor_pos; -// std::stack _multi_line_content; + /** Are we currently pasting several lines */ + bool _multi_line_paste; + + /** Queue of lines being pasted */ + std::queue _multi_line_content; // Overrides: virtual void keyPressEvent ( QKeyEvent* event); virtual void customEvent( QEvent* event); virtual void mousePressEvent( QMouseEvent* event ); -// virtual void insertFromMimeData(const QMimeData * source); + virtual void insertFromMimeData(const QMimeData * source); virtual PyInterp_Request* createTabRequest( const QString& input ); virtual void handleTab(); @@ -80,7 +85,9 @@ protected: virtual void clearCompletion(); virtual void formatCompletion(const std::vector & matches, QString & result) const; virtual QString formatDocHTML(const QString & doc) const; -// virtual void multilinePaste(); + + virtual void multilinePaste(const QString & s); + virtual void multiLineProcessNextLine(); private: void extractCommon(const std::vector & matches, QString & result) const; -- 2.39.2