KTextAddons

texteditorcompleter.cpp
1/*
2 * SPDX-FileCopyrightText: 2015-2024 Laurent Montel <montel@kde.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
7#include "texteditorcompleter.h"
8#include <QAbstractItemView>
9#include <QCompleter>
10#include <QPlainTextEdit>
11#include <QScrollBar>
12#include <QStringListModel>
13#include <QTextEdit>
14
15using namespace TextCustomEditor;
16
17class TextEditorCompleter::TextEditorCompleterPrivate
18{
19public:
20 TextEditorCompleterPrivate(QTextEdit *editor, TextEditorCompleter *qq)
21 : textEdit(editor)
22 , q(qq)
23 {
24 createCompleter();
25 }
26
27 TextEditorCompleterPrivate(QPlainTextEdit *editor, TextEditorCompleter *qq)
28 : plainTextEdit(editor)
29 , q(qq)
30 {
31 createCompleter();
32 }
33
34 void setCompletion(const QString &completion);
35 [[nodiscard]] QString wordUnderCursor() const;
36 void createCompleter();
37 void completeText();
38 QString excludeOfCharacters;
39 QCompleter *completer = nullptr;
40 QPlainTextEdit *plainTextEdit = nullptr;
41 QTextEdit *textEdit = nullptr;
42 TextEditorCompleter *const q;
43};
44
45void TextEditorCompleter::TextEditorCompleterPrivate::createCompleter()
46{
47 if (!completer) {
48 completer = new QCompleter(q);
49 }
50 if (plainTextEdit) {
51 completer->setWidget(plainTextEdit);
52 } else {
53 completer->setWidget(textEdit);
54 }
58 connect(completer, qOverload<const QString &>(&QCompleter::activated), q, &TextEditorCompleter::slotCompletion);
59}
60
61QString TextEditorCompleter::TextEditorCompleterPrivate::wordUnderCursor() const
62{
63 static QString eow = QStringLiteral("~!@#$%^&*()+{}|\"<>,./;'[]\\-= "); // everything without ':', '?' and '_'
64 QTextCursor tc;
65 QTextDocument *document = nullptr;
66 if (plainTextEdit) {
67 tc = plainTextEdit->textCursor();
68 document = plainTextEdit->document();
69 } else {
70 tc = textEdit->textCursor();
71 document = textEdit->document();
72 }
73
74 tc.anchor();
75 const QString eowStr = excludeOfCharacters.isEmpty() ? eow : excludeOfCharacters;
76 while (true) {
77 // vHanda: I don't understand why the cursor seems to give a pos 1 past the last char instead
78 // of just the last char.
79 int pos = tc.position() - 1;
80 if (pos < 0 || eowStr.contains(document->characterAt(pos)) || document->characterAt(pos) == QChar(QChar::LineSeparator)
81 || document->characterAt(pos) == QChar(QChar::ParagraphSeparator)) {
82 break;
83 }
85 }
86 return tc.selectedText();
87}
88
89void TextEditorCompleter::TextEditorCompleterPrivate::setCompletion(const QString &completion)
90{
91 QTextCursor tc;
92 if (plainTextEdit) {
93 tc = plainTextEdit->textCursor();
94 } else {
95 tc = textEdit->textCursor();
96 }
97 const int extra = completion.length() - completer->completionPrefix().length();
100 tc.insertText(completion.right(extra));
101 if (plainTextEdit) {
102 plainTextEdit->setTextCursor(tc);
103 } else {
104 textEdit->setTextCursor(tc);
105 }
106}
107
108void TextEditorCompleter::TextEditorCompleterPrivate::completeText()
109{
110 if (!completer) {
111 return;
112 }
113 const QString text = wordUnderCursor();
114 if (text.length() < 2) { // min 2 char for completion
115 return;
116 }
117
118 completer->setCompletionPrefix(text);
119
120 QRect cr;
121 if (plainTextEdit) {
122 cr = plainTextEdit->cursorRect();
123 } else {
124 cr = textEdit->cursorRect();
125 }
126 cr.setWidth(completer->popup()->sizeHintForColumn(0) + completer->popup()->verticalScrollBar()->sizeHint().width());
127 completer->complete(cr);
128}
129
130TextEditorCompleter::TextEditorCompleter(QTextEdit *editor, QObject *parent)
131 : QObject(parent)
132 , d(new TextEditorCompleter::TextEditorCompleterPrivate(editor, this))
133{
134}
135
136TextEditorCompleter::TextEditorCompleter(QPlainTextEdit *editor, QObject *parent)
137 : QObject(parent)
138 , d(new TextEditorCompleter::TextEditorCompleterPrivate(editor, this))
139{
140}
141
142TextEditorCompleter::~TextEditorCompleter() = default;
143
144QCompleter *TextEditorCompleter::completer() const
145{
146 return d->completer;
147}
148
149void TextEditorCompleter::setCompleterStringList(const QStringList &listWord)
150{
151 d->completer->setModel(new QStringListModel(QStringList() << listWord << QStringLiteral("TESTING"), d->completer));
152}
153
154void TextEditorCompleter::slotCompletion(const QString &completion)
155{
156 d->setCompletion(completion);
157}
158
159void TextEditorCompleter::completeText()
160{
161 d->completeText();
162}
163
164void TextEditorCompleter::setExcludeOfCharacters(const QString &excludes)
165{
166 d->excludeOfCharacters = excludes;
167}
168
169#include "moc_texteditorcompleter.cpp"
The TextEditorCompleter class.
const QList< QKeySequence > & completion()
CaseSensitivelySortedModel
void activated(const QModelIndex &index)
void setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
void setCompletionMode(CompletionMode mode)
void setModelSorting(ModelSorting sorting)
void setWidget(QWidget *widget)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
void setWidth(int width)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
CaseInsensitive
int anchor() const const
void insertText(const QString &text)
bool movePosition(MoveOperation operation, MoveMode mode, int n)
int position() const const
QString selectedText() const const
QChar characterAt(int pos) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:19:49 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.