summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/texteditor/basetexteditor.cpp93
-rw-r--r--src/plugins/texteditor/basetexteditor.h5
-rw-r--r--src/plugins/texteditor/basetexteditor_p.h1
-rw-r--r--src/plugins/texteditor/circularclipboard.cpp79
-rw-r--r--src/plugins/texteditor/circularclipboard.h63
-rw-r--r--src/plugins/texteditor/texteditor.pro6
-rw-r--r--src/plugins/texteditor/texteditoractionhandler.cpp9
-rw-r--r--src/plugins/texteditor/texteditoractionhandler.h2
-rw-r--r--src/plugins/texteditor/texteditorconstants.h1
9 files changed, 250 insertions, 9 deletions
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp
index 5b41cfea5c..9dd10d0da4 100644
--- a/src/plugins/texteditor/basetexteditor.cpp
+++ b/src/plugins/texteditor/basetexteditor.cpp
@@ -54,6 +54,7 @@
#include "convenience.h"
#include "texteditorsettings.h"
#include "texteditoroverlay.h"
+#include "circularclipboard.h"
#include <aggregation/aggregate.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -99,6 +100,7 @@
#include <QtGui/QInputDialog>
#include <QtGui/QMenu>
#include <QtGui/QMessageBox>
+#include <QtGui/QClipboard>
//#define DO_FOO
@@ -201,6 +203,18 @@ static void convertToPlainText(QString &txt)
}
}
+static bool isModifierKey(int key)
+{
+ return key == Qt::Key_Shift
+ || key == Qt::Key_Control
+ || key == Qt::Key_Alt
+ || key == Qt::Key_Meta;
+}
+
+static const char kTextBlockMimeType[] = "application/vnd.nokia.qtcreator.blocktext";
+static const char kVerticalTextBlockMimeType[] = "application/vnd.nokia.qtcreator.vblocktext";
+
+
BaseTextEditorWidget::BaseTextEditorWidget(QWidget *parent)
: QPlainTextEdit(parent)
{
@@ -1524,6 +1538,11 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
d->m_moveLineUndoHack = false;
d->clearVisibleFoldedBlock();
+ if (d->m_isCirculatingClipboard
+ && !isModifierKey(e->key())) {
+ d->m_isCirculatingClipboard = false;
+ }
+
if (e->key() == Qt::Key_Alt
&& d->m_behaviorSettings.m_keyboardTooltips) {
d->m_maybeFakeTooltipEvent = true;
@@ -2461,6 +2480,7 @@ BaseTextEditorPrivate::BaseTextEditorPrivate()
m_requestMarkEnabled(true),
m_lineSeparatorsAllowed(false),
m_maybeFakeTooltipEvent(false),
+ m_isCirculatingClipboard(false),
m_visibleWrapColumn(0),
m_linkPressed(false),
m_delayedUpdateTimer(0),
@@ -5742,6 +5762,22 @@ void BaseTextEditorWidget::cut()
QPlainTextEdit::cut();
}
+void BaseTextEditorWidget::copy()
+{
+ if (!textCursor().hasSelection())
+ return;
+
+ QPlainTextEdit::copy();
+
+ const QMimeData *mimeData = QApplication::clipboard()->mimeData();
+ if (mimeData) {
+ CircularClipboard *circularClipBoard = CircularClipboard::instance();
+ circularClipBoard->collect(duplicateMimeData(mimeData));
+ // We want the latest copied content to be the first one to appear on circular paste.
+ circularClipBoard->toLastCollect();
+ }
+}
+
void BaseTextEditorWidget::paste()
{
if (d->m_inBlockSelectionMode) {
@@ -5750,12 +5786,36 @@ void BaseTextEditorWidget::paste()
QPlainTextEdit::paste();
}
+void BaseTextEditorWidget::circularPaste()
+{
+ const QMimeData *mimeData = CircularClipboard::instance()->next();
+ if (!mimeData)
+ return;
+
+ QTextCursor cursor = textCursor();
+ if (!d->m_isCirculatingClipboard) {
+ cursor.beginEditBlock();
+ d->m_isCirculatingClipboard = true;
+ } else {
+ cursor.joinPreviousEditBlock();
+ }
+ const int selectionStart = qMin(cursor.position(), cursor.anchor());
+ insertFromMimeData(mimeData);
+ cursor.setPosition(selectionStart, QTextCursor::KeepAnchor);
+ cursor.endEditBlock();
+
+ setTextCursor(flippedCursor(cursor));
+
+ // We want to latest pasted content to replace the system's current clipboard.
+ QPlainTextEdit::copy();
+}
+
QMimeData *BaseTextEditorWidget::createMimeDataFromSelection() const
{
if (d->m_inBlockSelectionMode) {
QMimeData *mimeData = new QMimeData;
QString text = d->copyBlockSelection();
- mimeData->setData(QLatin1String("application/vnd.nokia.qtcreator.vblocktext"), text.toUtf8());
+ mimeData->setData(QLatin1String(kVerticalTextBlockMimeType), text.toUtf8());
mimeData->setText(text); // for exchangeability
return mimeData;
} else if (textCursor().hasSelection()) {
@@ -5829,7 +5889,7 @@ QMimeData *BaseTextEditorWidget::createMimeDataFromSelection() const
cursor.setPosition(selstart.position());
cursor.setPosition(selend.position(), QTextCursor::KeepAnchor);
text = cursor.selectedText();
- mimeData->setData(QLatin1String("application/vnd.nokia.qtcreator.blocktext"), text.toUtf8());
+ mimeData->setData(QLatin1String(kTextBlockMimeType), text.toUtf8());
}
return mimeData;
}
@@ -5846,8 +5906,8 @@ void BaseTextEditorWidget::insertFromMimeData(const QMimeData *source)
if (isReadOnly())
return;
- if (source->hasFormat(QLatin1String("application/vnd.nokia.qtcreator.vblocktext"))) {
- QString text = QString::fromUtf8(source->data(QLatin1String("application/vnd.nokia.qtcreator.vblocktext")));
+ if (source->hasFormat(QLatin1String(kVerticalTextBlockMimeType))) {
+ QString text = QString::fromUtf8(source->data(QLatin1String(kVerticalTextBlockMimeType)));
if (text.isEmpty())
return;
@@ -5923,8 +5983,8 @@ void BaseTextEditorWidget::insertFromMimeData(const QMimeData *source)
bool insertAtBeginningOfLine = ts.cursorIsAtBeginningOfLine(cursor);
if (insertAtBeginningOfLine
- && source->hasFormat(QLatin1String("application/vnd.nokia.qtcreator.blocktext"))) {
- text = QString::fromUtf8(source->data(QLatin1String("application/vnd.nokia.qtcreator.blocktext")));
+ && source->hasFormat(QLatin1String(kTextBlockMimeType))) {
+ text = QString::fromUtf8(source->data(QLatin1String(kTextBlockMimeType)));
if (text.isEmpty())
return;
}
@@ -5964,6 +6024,24 @@ void BaseTextEditorWidget::insertFromMimeData(const QMimeData *source)
setTextCursor(cursor);
}
+QMimeData *BaseTextEditorWidget::duplicateMimeData(const QMimeData *source) const
+{
+ Q_ASSERT(source);
+
+ QMimeData *mimeData = new QMimeData;
+ mimeData->setText(source->text());
+ mimeData->setHtml(source->html());
+ if (source->hasFormat(QLatin1String(kVerticalTextBlockMimeType))) {
+ mimeData->setData(QLatin1String(kVerticalTextBlockMimeType),
+ source->data(QLatin1String(kVerticalTextBlockMimeType)));
+ } else if (source->hasFormat(QLatin1String(kTextBlockMimeType))) {
+ mimeData->setData(QLatin1String(kTextBlockMimeType),
+ source->data(QLatin1String(kTextBlockMimeType)));
+ }
+
+ return mimeData;
+}
+
void BaseTextEditorWidget::appendStandardContextMenuActions(QMenu *menu)
{
menu->addSeparator();
@@ -5978,6 +6056,9 @@ void BaseTextEditorWidget::appendStandardContextMenuActions(QMenu *menu)
a = am->command(Core::Constants::PASTE)->action();
if (a && a->isEnabled())
menu->addAction(a);
+ a = am->command(Constants::CIRCULAR_PASTE)->action();
+ if (a && a->isEnabled())
+ menu->addAction(a);
}
diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h
index 3772da8a8a..4e02b961d2 100644
--- a/src/plugins/texteditor/basetexteditor.h
+++ b/src/plugins/texteditor/basetexteditor.h
@@ -254,9 +254,12 @@ public:
public slots:
void setDisplayName(const QString &title);
+ virtual void copy();
virtual void paste();
virtual void cut();
+ void circularPaste();
+
void zoomIn(int range = 1);
void zoomOut(int range = 1);
void zoomReset();
@@ -334,10 +337,10 @@ protected:
void showEvent(QShowEvent *);
- // reimplemented to support block selection
QMimeData *createMimeDataFromSelection() const;
bool canInsertFromMimeData(const QMimeData *source) const;
void insertFromMimeData(const QMimeData *source);
+ QMimeData *duplicateMimeData(const QMimeData *source) const;
static QString msgTextTooLarge(quint64 size);
diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h
index 1984f63dc0..c4312e559d 100644
--- a/src/plugins/texteditor/basetexteditor_p.h
+++ b/src/plugins/texteditor/basetexteditor_p.h
@@ -246,6 +246,7 @@ public:
uint autoParenthesisOverwriteBackup : 1;
uint surroundWithEnabledOverwriteBackup : 1;
uint m_maybeFakeTooltipEvent : 1;
+ uint m_isCirculatingClipboard: 1;
int m_visibleWrapColumn;
QTextCharFormat m_linkFormat;
diff --git a/src/plugins/texteditor/circularclipboard.cpp b/src/plugins/texteditor/circularclipboard.cpp
new file mode 100644
index 0000000000..1ebdcfce7a
--- /dev/null
+++ b/src/plugins/texteditor/circularclipboard.cpp
@@ -0,0 +1,79 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "circularclipboard.h"
+
+using namespace TextEditor::Internal;
+
+static const int kMaxSize = 10;
+
+CircularClipboard::CircularClipboard()
+ : m_current(-1)
+{}
+
+CircularClipboard::~CircularClipboard()
+{
+ qDeleteAll(m_items);
+}
+
+CircularClipboard *CircularClipboard::instance()
+{
+ static CircularClipboard clipboard;
+ return &clipboard;
+}
+
+void CircularClipboard::collect(const QMimeData *mimeData)
+{
+ if (m_items.size() > kMaxSize) {
+ delete m_items.last();
+ m_items.removeLast();
+ }
+ m_items.prepend(mimeData);
+}
+
+const QMimeData *CircularClipboard::next() const
+{
+ if (m_items.isEmpty())
+ return 0;
+
+ if (m_current == m_items.length() - 1)
+ m_current = 0;
+ else
+ ++m_current;
+
+ return m_items.at(m_current);
+}
+
+void CircularClipboard::toLastCollect()
+{
+ m_current = -1;
+}
diff --git a/src/plugins/texteditor/circularclipboard.h b/src/plugins/texteditor/circularclipboard.h
new file mode 100644
index 0000000000..c1827470be
--- /dev/null
+++ b/src/plugins/texteditor/circularclipboard.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef CIRCULARCLIPBOARD_H
+#define CIRCULARCLIPBOARD_H
+
+#include <QtCore/QList>
+#include <QtCore/QMimeData>
+
+namespace TextEditor {
+namespace Internal {
+
+class CircularClipboard
+{
+public:
+ static CircularClipboard *instance();
+
+ void collect(const QMimeData *mimeData);
+ const QMimeData *next() const;
+ void toLastCollect();
+
+private:
+ CircularClipboard();
+ ~CircularClipboard();
+ CircularClipboard &operator=(const CircularClipboard &);
+
+ mutable int m_current;
+ QList<const QMimeData *> m_items;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // CIRCULARCLIPBOARD_H
diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro
index e1719f899d..00fd2bd8e6 100644
--- a/src/plugins/texteditor/texteditor.pro
+++ b/src/plugins/texteditor/texteditor.pro
@@ -110,7 +110,8 @@ SOURCES += texteditorplugin.cpp \
typingsettings.cpp \
icodestylepreferences.cpp \
codestylepool.cpp \
- codestyleeditor.cpp
+ codestyleeditor.cpp \
+ circularclipboard.cpp
HEADERS += texteditorplugin.h \
textfilewizard.h \
@@ -225,7 +226,8 @@ HEADERS += texteditorplugin.h \
icodestylepreferences.h \
codestylepool.h \
codestyleeditor.h \
- basefilefind_p.h
+ basefilefind_p.h \
+ circularclipboard.h
FORMS += \
displaysettingspage.ui \
diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp
index 457e155ccb..1b387b92bd 100644
--- a/src/plugins/texteditor/texteditoractionhandler.cpp
+++ b/src/plugins/texteditor/texteditoractionhandler.cpp
@@ -64,6 +64,7 @@ TextEditorActionHandler::TextEditorActionHandler(const char *context,
m_copyAction(0),
m_cutAction(0),
m_pasteAction(0),
+ m_circularPasteAction(0),
m_selectAllAction(0),
m_gotoAction(0),
m_printAction(0),
@@ -369,6 +370,13 @@ void TextEditorActionHandler::createActions()
command->setDefaultKeySequence(QKeySequence(tr("Alt+U")));
connect(m_lowerCaseSelectionAction, SIGNAL(triggered()), this, SLOT(lowercaseSelection()));
+ m_circularPasteAction = new QAction(tr("Paste From Circular Clipboard"), this);
+ m_modifyingActions << m_circularPasteAction;
+ command = am->registerAction(m_circularPasteAction, Constants::CIRCULAR_PASTE, m_contextId, true);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+V")));
+ connect(m_circularPasteAction, SIGNAL(triggered()), this, SLOT(circularPasteAction()));
+ medit->addAction(command, Core::Constants::G_EDIT_COPYPASTE);
+
QAction *a = 0;
a = new QAction(tr("Goto Line Start"), this);
command = am->registerAction(a, Constants::GOTO_LINE_START, m_contextId, true);
@@ -568,6 +576,7 @@ FUNCTION2(redoAction, redo)
FUNCTION2(copyAction, copy)
FUNCTION2(cutAction, cut)
FUNCTION2(pasteAction, paste)
+FUNCTION2(circularPasteAction, circularPaste)
FUNCTION2(formatAction, format)
FUNCTION2(rewrapParagraphAction, rewrapParagraph)
FUNCTION2(selectAllAction, selectAll)
diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h
index 7015a792fd..cfe24f0e1d 100644
--- a/src/plugins/texteditor/texteditoractionhandler.h
+++ b/src/plugins/texteditor/texteditoractionhandler.h
@@ -98,6 +98,7 @@ private slots:
void copyAction();
void cutAction();
void pasteAction();
+ void circularPasteAction();
void selectAllAction();
void gotoAction();
void printAction();
@@ -166,6 +167,7 @@ private:
QAction *m_copyAction;
QAction *m_cutAction;
QAction *m_pasteAction;
+ QAction *m_circularPasteAction;
QAction *m_selectAllAction;
QAction *m_gotoAction;
QAction *m_printAction;
diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h
index d1dfbcf063..bc8806aa88 100644
--- a/src/plugins/texteditor/texteditorconstants.h
+++ b/src/plugins/texteditor/texteditorconstants.h
@@ -101,6 +101,7 @@ const char INFO_SYNTAX_DEFINITION[] = "TextEditor.InfoSyntaxDefinition";
const char TASK_DOWNLOAD_DEFINITIONS[] = "TextEditor.Task.Download";
const char TASK_REGISTER_DEFINITIONS[] = "TextEditor.Task.Register";
const char TASK_OPEN_FILE[] = "TextEditor.Task.OpenFile";
+const char CIRCULAR_PASTE[] = "TextEditor.CircularPaste";
// Text color and style categories
const char C_TEXT[] = "Text";