forked from qt-creator/qt-creator
FancyLineEdit: Add camel case navigation
Use it for search and replace functions as well as for Locator. The camel case navigation can be switched on / off with the existing menu Options > Text Editor > Behavior > Enable Build-in camel case navigation. Fixes: QTCREATORBUG-21140 Change-Id: I3f2dcafff231366b3c8f08c14514dd8940cca2a0 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
committed by
André Hartmann
parent
71e9e3832a
commit
839f45faa9
@@ -24,6 +24,7 @@ add_qtc_library(Utils
|
|||||||
basetreeview.cpp basetreeview.h
|
basetreeview.cpp basetreeview.h
|
||||||
benchmarker.cpp benchmarker.h
|
benchmarker.cpp benchmarker.h
|
||||||
buildablehelperlibrary.cpp buildablehelperlibrary.h
|
buildablehelperlibrary.cpp buildablehelperlibrary.h
|
||||||
|
camelcasecursor.cpp camelcasecursor.h
|
||||||
categorysortfiltermodel.cpp categorysortfiltermodel.h
|
categorysortfiltermodel.cpp categorysortfiltermodel.h
|
||||||
changeset.cpp changeset.h
|
changeset.cpp changeset.h
|
||||||
checkablemessagebox.cpp checkablemessagebox.h
|
checkablemessagebox.cpp checkablemessagebox.h
|
||||||
|
341
src/libs/utils/camelcasecursor.cpp
Normal file
341
src/libs/utils/camelcasecursor.cpp
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Copyright (C) 2019 Andre Hartmann <aha_1980@gmx.de>
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "camelcasecursor.h"
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
|
||||||
|
template<typename C, typename E>
|
||||||
|
bool moveCursor(C *cursor, E *edit, QTextCursor::MoveOperation direction, QTextCursor::MoveMode mode);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool moveCursor(QTextCursor *cursor, QPlainTextEdit *, QTextCursor::MoveOperation direction,
|
||||||
|
QTextCursor::MoveMode mode)
|
||||||
|
{
|
||||||
|
return cursor->movePosition(direction, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
bool moveCursor(C *, QLineEdit *edit, QTextCursor::MoveOperation direction, QTextCursor::MoveMode mode)
|
||||||
|
{
|
||||||
|
bool mark = (mode == QTextCursor::KeepAnchor);
|
||||||
|
switch (direction) {
|
||||||
|
case QTextCursor::Left:
|
||||||
|
edit->cursorBackward(mark);
|
||||||
|
break;
|
||||||
|
case QTextCursor::WordLeft:
|
||||||
|
edit->cursorWordBackward(mark);
|
||||||
|
break;
|
||||||
|
case QTextCursor::Right:
|
||||||
|
edit->cursorForward(mark);
|
||||||
|
break;
|
||||||
|
case QTextCursor::WordRight:
|
||||||
|
edit->cursorWordForward(mark);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return edit->cursorPosition() > 0 && edit->cursorPosition() < edit->text().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C, typename E>
|
||||||
|
QChar charUnderCursor(C *cursor, E *edit);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
QChar charUnderCursor(QTextCursor *cursor, QPlainTextEdit *edit)
|
||||||
|
{
|
||||||
|
return edit->document()->characterAt(cursor->position());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
QChar charUnderCursor(C *, QLineEdit *edit)
|
||||||
|
{
|
||||||
|
const int pos = edit->cursorPosition();
|
||||||
|
if (pos < 0 || pos >= edit->text().length())
|
||||||
|
return QChar::Null;
|
||||||
|
|
||||||
|
return edit->text().at(pos);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename C, typename E>
|
||||||
|
int position(C *cursor, E *edit);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
int position(QTextCursor *cursor, QPlainTextEdit *)
|
||||||
|
{
|
||||||
|
return cursor->position();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
int position(C *, QLineEdit *edit)
|
||||||
|
{
|
||||||
|
return edit->cursorPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Input {
|
||||||
|
Upper,
|
||||||
|
Lower,
|
||||||
|
Underscore,
|
||||||
|
Space,
|
||||||
|
Other
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename C, typename E>
|
||||||
|
bool camelCaseLeft(C *cursor, E *edit, QTextCursor::MoveMode mode)
|
||||||
|
{
|
||||||
|
int state = 0;
|
||||||
|
|
||||||
|
if (!moveCursor(cursor, edit, QTextCursor::Left, mode))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
QChar c = charUnderCursor(cursor, edit);
|
||||||
|
Input input = Input::Other;
|
||||||
|
if (c.isUpper())
|
||||||
|
input = Input::Upper;
|
||||||
|
else if (c.isLower() || c.isDigit())
|
||||||
|
input = Input::Lower;
|
||||||
|
else if (c == '_')
|
||||||
|
input = Input::Underscore;
|
||||||
|
else if (c.isSpace() && c != QChar::ParagraphSeparator)
|
||||||
|
input = Input::Space;
|
||||||
|
else
|
||||||
|
input = Input::Other;
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case 0:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Upper:
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
case Input::Lower:
|
||||||
|
state = 2;
|
||||||
|
break;
|
||||||
|
case Input::Underscore:
|
||||||
|
state = 3;
|
||||||
|
break;
|
||||||
|
case Input::Space:
|
||||||
|
state = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
moveCursor(cursor, edit, QTextCursor::Right, mode);
|
||||||
|
return moveCursor(cursor, edit, QTextCursor::WordLeft, mode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Upper:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return moveCursor(cursor, edit, QTextCursor::Right, mode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Upper:
|
||||||
|
return true;
|
||||||
|
case Input::Lower:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return moveCursor(cursor, edit, QTextCursor::Right, mode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Underscore:
|
||||||
|
break;
|
||||||
|
case Input::Upper:
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
case Input::Lower:
|
||||||
|
state = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
moveCursor(cursor, edit, QTextCursor::Right, mode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Space:
|
||||||
|
break;
|
||||||
|
case Input::Upper:
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
case Input::Lower:
|
||||||
|
state = 2;
|
||||||
|
break;
|
||||||
|
case Input::Underscore:
|
||||||
|
state = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return moveCursor(cursor, edit, QTextCursor::Right, mode);
|
||||||
|
if (position(cursor, edit) == 0)
|
||||||
|
return true;
|
||||||
|
return moveCursor(cursor, edit, QTextCursor::WordLeft, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moveCursor(cursor, edit, QTextCursor::Left, mode))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C, typename E>
|
||||||
|
bool camelCaseRight(C *cursor, E *edit, QTextCursor::MoveMode mark)
|
||||||
|
{
|
||||||
|
int state = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
QChar c = charUnderCursor(cursor, edit);
|
||||||
|
Input input = Input::Other;
|
||||||
|
if (c.isUpper())
|
||||||
|
input = Input::Upper;
|
||||||
|
else if (c.isLower() || c.isDigit())
|
||||||
|
input = Input::Lower;
|
||||||
|
else if (c == '_')
|
||||||
|
input = Input::Underscore;
|
||||||
|
else if (c.isSpace() && c != QChar::ParagraphSeparator)
|
||||||
|
input = Input::Space;
|
||||||
|
else
|
||||||
|
input = Input::Other;
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case 0:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Upper:
|
||||||
|
state = 4;
|
||||||
|
break;
|
||||||
|
case Input::Lower:
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
case Input::Underscore:
|
||||||
|
state = 6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return moveCursor(cursor, edit, QTextCursor::WordRight, mark);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Upper:
|
||||||
|
return true;
|
||||||
|
case Input::Lower:
|
||||||
|
break;
|
||||||
|
case Input::Underscore:
|
||||||
|
state = 6;
|
||||||
|
break;
|
||||||
|
case Input::Space:
|
||||||
|
state = 7;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Upper:
|
||||||
|
break;
|
||||||
|
case Input::Lower:
|
||||||
|
moveCursor(cursor, edit, QTextCursor::Left, mark);
|
||||||
|
return true;
|
||||||
|
case Input::Underscore:
|
||||||
|
state = 6;
|
||||||
|
break;
|
||||||
|
case Input::Space:
|
||||||
|
state = 7;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Upper:
|
||||||
|
state = 2;
|
||||||
|
break;
|
||||||
|
case Input::Lower:
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
case Input::Underscore:
|
||||||
|
state = 6;
|
||||||
|
break;
|
||||||
|
case Input::Space:
|
||||||
|
state = 7;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Underscore:
|
||||||
|
break;
|
||||||
|
case Input::Space:
|
||||||
|
state = 7;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
switch (input) {
|
||||||
|
case Input::Space:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!moveCursor(cursor, edit, QTextCursor::Right, mark))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CamelCaseCursor::left(QTextCursor *cursor, QPlainTextEdit *edit, QTextCursor::MoveMode mode)
|
||||||
|
{
|
||||||
|
return camelCaseLeft(cursor, edit, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CamelCaseCursor::left(QLineEdit *edit, QTextCursor::MoveMode mode)
|
||||||
|
{
|
||||||
|
QTextCursor temp;
|
||||||
|
return camelCaseLeft(&temp, edit, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CamelCaseCursor::right(QTextCursor *cursor, QPlainTextEdit *edit, QTextCursor::MoveMode mode)
|
||||||
|
{
|
||||||
|
return camelCaseRight(cursor, edit, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CamelCaseCursor::right(QLineEdit *edit, QTextCursor::MoveMode mode)
|
||||||
|
{
|
||||||
|
QTextCursor temp;
|
||||||
|
return camelCaseRight(&temp, edit, mode);
|
||||||
|
}
|
45
src/libs/utils/camelcasecursor.h
Normal file
45
src/libs/utils/camelcasecursor.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Copyright (C) 2019 Andre Hartmann <aha_1980@gmx.de>
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils_global.h"
|
||||||
|
|
||||||
|
#include <QTextCursor>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QLineEdit;
|
||||||
|
class QPlainTextEdit;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class QTCREATOR_UTILS_EXPORT CamelCaseCursor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool left(QTextCursor *cursor, QPlainTextEdit *edit, QTextCursor::MoveMode mode);
|
||||||
|
static bool left(QLineEdit *edit, QTextCursor::MoveMode mode);
|
||||||
|
static bool right(QTextCursor *cursor, QPlainTextEdit *edit, QTextCursor::MoveMode mode);
|
||||||
|
static bool right(QLineEdit *edit, QTextCursor::MoveMode mode);
|
||||||
|
};
|
@@ -23,6 +23,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "camelcasecursor.h"
|
||||||
#include "execmenu.h"
|
#include "execmenu.h"
|
||||||
#include "fancylineedit.h"
|
#include "fancylineedit.h"
|
||||||
#include "historycompleter.h"
|
#include "historycompleter.h"
|
||||||
@@ -80,6 +81,8 @@ enum { margin = 6 };
|
|||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
|
static bool camelCaseNavigation = false;
|
||||||
|
|
||||||
// --------- FancyLineEditPrivate
|
// --------- FancyLineEditPrivate
|
||||||
class FancyLineEditPrivate : public QObject
|
class FancyLineEditPrivate : public QObject
|
||||||
{
|
{
|
||||||
@@ -328,6 +331,24 @@ void FancyLineEdit::onEditingFinished()
|
|||||||
d->m_historyCompleter->addEntry(text());
|
d->m_historyCompleter->addEntry(text());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FancyLineEdit::keyPressEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
const QTextCursor::MoveMode mode = (event->modifiers() & Qt::ShiftModifier)
|
||||||
|
? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor;
|
||||||
|
|
||||||
|
if (camelCaseNavigation && event == QKeySequence::MoveToPreviousWord)
|
||||||
|
CamelCaseCursor::left(this, mode);
|
||||||
|
else if (camelCaseNavigation && event == QKeySequence::MoveToNextWord)
|
||||||
|
CamelCaseCursor::right(this, mode);
|
||||||
|
else
|
||||||
|
QLineEdit::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FancyLineEdit::setCamelCaseNavigationEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
camelCaseNavigation = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
void FancyLineEdit::setSpecialCompleter(QCompleter *completer)
|
void FancyLineEdit::setSpecialCompleter(QCompleter *completer)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!d->m_historyCompleter, return);
|
QTC_ASSERT(!d->m_historyCompleter, return);
|
||||||
|
@@ -141,9 +141,12 @@ public:
|
|||||||
void validate();
|
void validate();
|
||||||
void onEditingFinished();
|
void onEditingFinished();
|
||||||
|
|
||||||
|
static void setCamelCaseNavigationEnabled(bool enabled);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Custom behaviour can be added here.
|
// Custom behaviour can be added here.
|
||||||
virtual void handleChanged(const QString &) {}
|
virtual void handleChanged(const QString &) {}
|
||||||
|
void keyPressEvent(QKeyEvent *event);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void buttonClicked(Utils::FancyLineEdit::Side side);
|
void buttonClicked(Utils::FancyLineEdit::Side side);
|
||||||
@@ -170,6 +173,8 @@ private:
|
|||||||
|
|
||||||
void updateMargins();
|
void updateMargins();
|
||||||
void updateButtonPositions();
|
void updateButtonPositions();
|
||||||
|
bool camelCaseBackward(bool mark);
|
||||||
|
bool camelCaseForward(bool mark);
|
||||||
friend class FancyLineEditPrivate;
|
friend class FancyLineEditPrivate;
|
||||||
|
|
||||||
FancyLineEditPrivate *d;
|
FancyLineEditPrivate *d;
|
||||||
|
@@ -130,7 +130,8 @@ SOURCES += \
|
|||||||
$$PWD/removefiledialog.cpp \
|
$$PWD/removefiledialog.cpp \
|
||||||
$$PWD/differ.cpp \
|
$$PWD/differ.cpp \
|
||||||
$$PWD/jsontreeitem.cpp \
|
$$PWD/jsontreeitem.cpp \
|
||||||
$$PWD/namevaluevalidator.cpp
|
$$PWD/namevaluevalidator.cpp \
|
||||||
|
$$PWD/camelcasecursor.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/environmentfwd.h \
|
$$PWD/environmentfwd.h \
|
||||||
@@ -275,7 +276,8 @@ HEADERS += \
|
|||||||
$$PWD/cpplanguage_details.h \
|
$$PWD/cpplanguage_details.h \
|
||||||
$$PWD/jsontreeitem.h \
|
$$PWD/jsontreeitem.h \
|
||||||
$$PWD/listmodel.h \
|
$$PWD/listmodel.h \
|
||||||
$$PWD/namevaluevalidator.h
|
$$PWD/namevaluevalidator.h \
|
||||||
|
$$PWD/camelcasecursor.h
|
||||||
|
|
||||||
FORMS += $$PWD/filewizardpage.ui \
|
FORMS += $$PWD/filewizardpage.ui \
|
||||||
$$PWD/newclasswidget.ui \
|
$$PWD/newclasswidget.ui \
|
||||||
|
@@ -50,6 +50,8 @@ Project {
|
|||||||
"benchmarker.h",
|
"benchmarker.h",
|
||||||
"buildablehelperlibrary.cpp",
|
"buildablehelperlibrary.cpp",
|
||||||
"buildablehelperlibrary.h",
|
"buildablehelperlibrary.h",
|
||||||
|
"camelcasecursor.cpp",
|
||||||
|
"camelcasecursor.h",
|
||||||
"categorysortfiltermodel.cpp",
|
"categorysortfiltermodel.cpp",
|
||||||
"categorysortfiltermodel.h",
|
"categorysortfiltermodel.h",
|
||||||
"changeset.cpp",
|
"changeset.cpp",
|
||||||
|
@@ -71,6 +71,7 @@
|
|||||||
#include <coreplugin/find/highlightscrollbarcontroller.h>
|
#include <coreplugin/find/highlightscrollbarcontroller.h>
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/textutils.h>
|
#include <utils/textutils.h>
|
||||||
|
#include <utils/camelcasecursor.h>
|
||||||
#include <utils/fixedsizeclicklabel.h>
|
#include <utils/fixedsizeclicklabel.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/dropsupport.h>
|
#include <utils/dropsupport.h>
|
||||||
@@ -559,8 +560,6 @@ public:
|
|||||||
void universalHelper(); // test function for development
|
void universalHelper(); // test function for development
|
||||||
|
|
||||||
bool cursorMoveKeyEvent(QKeyEvent *e);
|
bool cursorMoveKeyEvent(QKeyEvent *e);
|
||||||
bool camelCaseRight(QTextCursor &cursor, QTextCursor::MoveMode mode);
|
|
||||||
bool camelCaseLeft(QTextCursor &cursor, QTextCursor::MoveMode mode);
|
|
||||||
|
|
||||||
void processTooltipRequest(const QTextCursor &c);
|
void processTooltipRequest(const QTextCursor &c);
|
||||||
bool processAnnotaionTooltipRequest(const QTextBlock &block, const QPoint &pos) const;
|
bool processAnnotaionTooltipRequest(const QTextBlock &block, const QPoint &pos) const;
|
||||||
@@ -1628,28 +1627,28 @@ void TextEditorWidget::gotoNextWordWithSelection()
|
|||||||
void TextEditorWidget::gotoPreviousWordCamelCase()
|
void TextEditorWidget::gotoPreviousWordCamelCase()
|
||||||
{
|
{
|
||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
d->camelCaseLeft(c, QTextCursor::MoveAnchor);
|
CamelCaseCursor::left(&c, this, QTextCursor::MoveAnchor);
|
||||||
setTextCursor(c);
|
setTextCursor(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditorWidget::gotoPreviousWordCamelCaseWithSelection()
|
void TextEditorWidget::gotoPreviousWordCamelCaseWithSelection()
|
||||||
{
|
{
|
||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
d->camelCaseLeft(c, QTextCursor::KeepAnchor);
|
CamelCaseCursor::left(&c, this, QTextCursor::KeepAnchor);
|
||||||
setTextCursor(c);
|
setTextCursor(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditorWidget::gotoNextWordCamelCase()
|
void TextEditorWidget::gotoNextWordCamelCase()
|
||||||
{
|
{
|
||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
d->camelCaseRight(c, QTextCursor::MoveAnchor);
|
CamelCaseCursor::right(&c, this, QTextCursor::MoveAnchor);
|
||||||
setTextCursor(c);
|
setTextCursor(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditorWidget::gotoNextWordCamelCaseWithSelection()
|
void TextEditorWidget::gotoNextWordCamelCaseWithSelection()
|
||||||
{
|
{
|
||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
d->camelCaseRight(c, QTextCursor::KeepAnchor);
|
CamelCaseCursor::right(&c, this, QTextCursor::KeepAnchor);
|
||||||
setTextCursor(c);
|
setTextCursor(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2061,232 +2060,6 @@ static QTextLine currentTextLine(const QTextCursor &cursor)
|
|||||||
return layout->lineForTextPosition(relativePos);
|
return layout->lineForTextPosition(relativePos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextEditorWidgetPrivate::camelCaseLeft(QTextCursor &cursor, QTextCursor::MoveMode mode)
|
|
||||||
{
|
|
||||||
int state = 0;
|
|
||||||
enum Input {
|
|
||||||
Input_U,
|
|
||||||
Input_l,
|
|
||||||
Input_underscore,
|
|
||||||
Input_space,
|
|
||||||
Input_other
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!cursor.movePosition(QTextCursor::Left, mode))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
forever {
|
|
||||||
QChar c = q->document()->characterAt(cursor.position());
|
|
||||||
Input input = Input_other;
|
|
||||||
if (c.isUpper())
|
|
||||||
input = Input_U;
|
|
||||||
else if (c.isLower() || c.isDigit())
|
|
||||||
input = Input_l;
|
|
||||||
else if (c == QLatin1Char('_'))
|
|
||||||
input = Input_underscore;
|
|
||||||
else if (c.isSpace() && c != QChar::ParagraphSeparator)
|
|
||||||
input = Input_space;
|
|
||||||
else
|
|
||||||
input = Input_other;
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case 0:
|
|
||||||
switch (input) {
|
|
||||||
case Input_U:
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case Input_l:
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
case Input_underscore:
|
|
||||||
state = 3;
|
|
||||||
break;
|
|
||||||
case Input_space:
|
|
||||||
state = 4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cursor.movePosition(QTextCursor::Right, mode);
|
|
||||||
return cursor.movePosition(QTextCursor::WordLeft, mode);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
switch (input) {
|
|
||||||
case Input_U:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cursor.movePosition(QTextCursor::Right, mode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
switch (input) {
|
|
||||||
case Input_U:
|
|
||||||
return true;
|
|
||||||
case Input_l:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cursor.movePosition(QTextCursor::Right, mode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
switch (input) {
|
|
||||||
case Input_underscore:
|
|
||||||
break;
|
|
||||||
case Input_U:
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case Input_l:
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cursor.movePosition(QTextCursor::Right, mode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
switch (input) {
|
|
||||||
case Input_space:
|
|
||||||
break;
|
|
||||||
case Input_U:
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case Input_l:
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
case Input_underscore:
|
|
||||||
state = 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cursor.movePosition(QTextCursor::Right, mode);
|
|
||||||
if (cursor.positionInBlock() == 0)
|
|
||||||
return true;
|
|
||||||
return cursor.movePosition(QTextCursor::WordLeft, mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cursor.movePosition(QTextCursor::Left, mode))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextEditorWidgetPrivate::camelCaseRight(QTextCursor &cursor, QTextCursor::MoveMode mode)
|
|
||||||
{
|
|
||||||
int state = 0;
|
|
||||||
enum Input {
|
|
||||||
Input_U,
|
|
||||||
Input_l,
|
|
||||||
Input_underscore,
|
|
||||||
Input_space,
|
|
||||||
Input_other
|
|
||||||
};
|
|
||||||
|
|
||||||
forever {
|
|
||||||
QChar c = q->document()->characterAt(cursor.position());
|
|
||||||
Input input = Input_other;
|
|
||||||
if (c.isUpper())
|
|
||||||
input = Input_U;
|
|
||||||
else if (c.isLower() || c.isDigit())
|
|
||||||
input = Input_l;
|
|
||||||
else if (c == QLatin1Char('_'))
|
|
||||||
input = Input_underscore;
|
|
||||||
else if (c.isSpace() && c != QChar::ParagraphSeparator)
|
|
||||||
input = Input_space;
|
|
||||||
else
|
|
||||||
input = Input_other;
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case 0:
|
|
||||||
switch (input) {
|
|
||||||
case Input_U:
|
|
||||||
state = 4;
|
|
||||||
break;
|
|
||||||
case Input_l:
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case Input_underscore:
|
|
||||||
state = 6;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return cursor.movePosition(QTextCursor::WordRight, mode);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
switch (input) {
|
|
||||||
case Input_U:
|
|
||||||
return true;
|
|
||||||
case Input_l:
|
|
||||||
break;
|
|
||||||
case Input_underscore:
|
|
||||||
state = 6;
|
|
||||||
break;
|
|
||||||
case Input_space:
|
|
||||||
state = 7;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
switch (input) {
|
|
||||||
case Input_U:
|
|
||||||
break;
|
|
||||||
case Input_l:
|
|
||||||
cursor.movePosition(QTextCursor::Left, mode);
|
|
||||||
return true;
|
|
||||||
case Input_underscore:
|
|
||||||
state = 6;
|
|
||||||
break;
|
|
||||||
case Input_space:
|
|
||||||
state = 7;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
switch (input) {
|
|
||||||
case Input_U:
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
case Input_l:
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case Input_underscore:
|
|
||||||
state = 6;
|
|
||||||
break;
|
|
||||||
case Input_space:
|
|
||||||
state = 7;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
switch (input) {
|
|
||||||
case Input_underscore:
|
|
||||||
break;
|
|
||||||
case Input_space:
|
|
||||||
state = 7;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
switch (input) {
|
|
||||||
case Input_space:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cursor.movePosition(QTextCursor::Right, mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextEditorWidgetPrivate::cursorMoveKeyEvent(QKeyEvent *e)
|
bool TextEditorWidgetPrivate::cursorMoveKeyEvent(QKeyEvent *e)
|
||||||
{
|
{
|
||||||
QTextCursor cursor = q->textCursor();
|
QTextCursor cursor = q->textCursor();
|
||||||
@@ -2381,9 +2154,9 @@ bool TextEditorWidgetPrivate::cursorMoveKeyEvent(QKeyEvent *e)
|
|||||||
cursor.setVisualNavigation(true);
|
cursor.setVisualNavigation(true);
|
||||||
|
|
||||||
if (q->camelCaseNavigationEnabled() && op == QTextCursor::WordRight)
|
if (q->camelCaseNavigationEnabled() && op == QTextCursor::WordRight)
|
||||||
camelCaseRight(cursor, mode);
|
CamelCaseCursor::right(&cursor, q, mode);
|
||||||
else if (q->camelCaseNavigationEnabled() && op == QTextCursor::WordLeft)
|
else if (q->camelCaseNavigationEnabled() && op == QTextCursor::WordLeft)
|
||||||
camelCaseLeft(cursor, mode);
|
CamelCaseCursor::left(&cursor, q, mode);
|
||||||
else if (!cursor.movePosition(op, mode) && mode == QTextCursor::MoveAnchor)
|
else if (!cursor.movePosition(op, mode) && mode == QTextCursor::MoveAnchor)
|
||||||
cursor.clearSelection();
|
cursor.clearSelection();
|
||||||
cursor.setVisualNavigation(visualNavigation);
|
cursor.setVisualNavigation(visualNavigation);
|
||||||
@@ -2586,7 +2359,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
|||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
int pos = c.position();
|
int pos = c.position();
|
||||||
if (camelCaseNavigationEnabled())
|
if (camelCaseNavigationEnabled())
|
||||||
d->camelCaseLeft(c, QTextCursor::MoveAnchor);
|
CamelCaseCursor::left(&c, this, QTextCursor::MoveAnchor);
|
||||||
else
|
else
|
||||||
c.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
|
c.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
|
||||||
int targetpos = c.position();
|
int targetpos = c.position();
|
||||||
@@ -2602,7 +2375,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
|||||||
e->accept();
|
e->accept();
|
||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
if (camelCaseNavigationEnabled())
|
if (camelCaseNavigationEnabled())
|
||||||
d->camelCaseLeft(c, QTextCursor::KeepAnchor);
|
CamelCaseCursor::left(&c, this, QTextCursor::KeepAnchor);
|
||||||
else
|
else
|
||||||
c.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
|
c.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
|
||||||
c.removeSelectedText();
|
c.removeSelectedText();
|
||||||
@@ -2611,7 +2384,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
|||||||
e->accept();
|
e->accept();
|
||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
if (camelCaseNavigationEnabled())
|
if (camelCaseNavigationEnabled())
|
||||||
d->camelCaseRight(c, QTextCursor::KeepAnchor);
|
CamelCaseCursor::right(&c, this, QTextCursor::KeepAnchor);
|
||||||
else
|
else
|
||||||
c.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
c.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||||
c.removeSelectedText();
|
c.removeSelectedText();
|
||||||
@@ -7111,7 +6884,7 @@ void TextEditorWidget::deleteEndOfWord()
|
|||||||
void TextEditorWidget::deleteEndOfWordCamelCase()
|
void TextEditorWidget::deleteEndOfWordCamelCase()
|
||||||
{
|
{
|
||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
d->camelCaseRight(c, QTextCursor::KeepAnchor);
|
CamelCaseCursor::right(&c, this, QTextCursor::KeepAnchor);
|
||||||
c.removeSelectedText();
|
c.removeSelectedText();
|
||||||
setTextCursor(c);
|
setTextCursor(c);
|
||||||
}
|
}
|
||||||
@@ -7133,7 +6906,7 @@ void TextEditorWidget::deleteStartOfWord()
|
|||||||
void TextEditorWidget::deleteStartOfWordCamelCase()
|
void TextEditorWidget::deleteStartOfWordCamelCase()
|
||||||
{
|
{
|
||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
d->camelCaseLeft(c, QTextCursor::KeepAnchor);
|
CamelCaseCursor::left(&c, this, QTextCursor::KeepAnchor);
|
||||||
c.removeSelectedText();
|
c.removeSelectedText();
|
||||||
setTextCursor(c);
|
setTextCursor(c);
|
||||||
}
|
}
|
||||||
|
@@ -48,6 +48,7 @@
|
|||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
|
#include <utils/fancylineedit.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -399,6 +400,13 @@ TextEditorSettings::TextEditorSettings()
|
|||||||
this, &TextEditorSettings::completionSettingsChanged);
|
this, &TextEditorSettings::completionSettingsChanged);
|
||||||
connect(d->m_completionSettingsPage, &CompletionSettingsPage::commentsSettingsChanged,
|
connect(d->m_completionSettingsPage, &CompletionSettingsPage::commentsSettingsChanged,
|
||||||
this, &TextEditorSettings::commentsSettingsChanged);
|
this, &TextEditorSettings::commentsSettingsChanged);
|
||||||
|
|
||||||
|
auto updateCamelCaseNavigation = [] {
|
||||||
|
Utils::FancyLineEdit::setCamelCaseNavigationEnabled(behaviorSettings().m_camelCaseNavigation);
|
||||||
|
};
|
||||||
|
connect(d->m_behaviorSettingsPage, &BehaviorSettingsPage::behaviorSettingsChanged,
|
||||||
|
this, updateCamelCaseNavigation);
|
||||||
|
updateCamelCaseNavigation();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditorSettings::~TextEditorSettings()
|
TextEditorSettings::~TextEditorSettings()
|
||||||
|
Reference in New Issue
Block a user