1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
/*
* Copyright (c) 2004 Jason Kivlighn <mizunoami44@users.sourceforge.net>
* Copyright (c) 2005-2007 Christian Loose <christian.loose@kdemail.net>
*
* based on work by Jason Kivlighn (krecipes/src/widgets/kretextedit.cpp)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "logmessageedit.h"
using Cervisia::LogMessageEdit;
#include <QKeyEvent>
#include <KStandardShortcut>
LogMessageEdit::LogMessageEdit(QWidget *parent)
: KTextEdit(parent)
, KCompletionBase()
, m_completing(false)
, m_completionStartPos(0)
, m_checkSpellingEnabledBeforeCompletion(false)
{
setAcceptRichText(false);
// create the completion object
completionObject();
}
void LogMessageEdit::mousePressEvent(QMouseEvent *event)
{
// a mouse click stops the completion process
QTextEdit::mousePressEvent(event);
stopCompletion();
}
void LogMessageEdit::setCompletedText(const QString &match)
{
QTextCursor cursor = this->textCursor();
int pos = cursor.position();
QString text = toPlainText();
// retrieve the part of the match that's missing
int length = pos - m_completionStartPos;
QString word = match.right(match.length() - length);
// insert the match
cursor.insertText(word);
// move cursor back and select the match
cursor.setPosition(pos, QTextCursor::KeepAnchor);
setTextCursor(cursor);
m_completing = true;
m_checkSpellingEnabledBeforeCompletion = checkSpellingEnabled();
// disable spellchecker during completion process. Otherwise we lose the
// text selection.
setCheckSpellingEnabled(false);
}
void LogMessageEdit::setCompletedItems(const QStringList &, bool)
{
}
void LogMessageEdit::keyPressEvent(QKeyEvent *event)
{
// handle normal key
Qt::KeyboardModifiers modifiers = event->modifiers();
bool noModifier = (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier || modifiers == Qt::KeypadModifier);
if (noModifier) {
QString keyCode = event->text();
if (!keyCode.isEmpty() && keyCode.unicode()->isPrint()) {
KTextEdit::keyPressEvent(event);
tryCompletion();
event->accept();
return;
}
}
// get shortcut for text completion key
QList<QKeySequence> shortcut = keyBinding(TextCompletion);
if (shortcut.isEmpty())
shortcut = KStandardShortcut::shortcut(KStandardShortcut::TextCompletion);
int key = event->key() | event->modifiers();
// handle text completion key
if (m_completing && shortcut.contains(key)) {
// accept the suggested completion
QTextCursor cursor = this->textCursor();
cursor.setPosition(cursor.selectionEnd());
setTextCursor(cursor);
stopCompletion();
return;
}
// handle previous match key
shortcut = keyBinding(PrevCompletionMatch);
if (shortcut.isEmpty())
shortcut = KStandardShortcut::shortcut(KStandardShortcut::PrevCompletion);
if (shortcut.contains(key)) {
rotateMatches(PrevCompletionMatch);
return;
}
// handle next match key
shortcut = keyBinding(NextCompletionMatch);
if (shortcut.isEmpty())
shortcut = KStandardShortcut::shortcut(KStandardShortcut::NextCompletion);
if (shortcut.contains(key)) {
rotateMatches(NextCompletionMatch);
return;
}
// any other key (except modifiers) will end the text completion
if (event->key() != Qt::Key_Shift && event->key() != Qt::Key_Control && event->key() != Qt::Key_Alt && event->key() != Qt::Key_Meta) {
stopCompletion();
}
KTextEdit::keyPressEvent(event);
}
void LogMessageEdit::stopCompletion()
{
if (m_completing) {
m_completing = false;
setCheckSpellingEnabled(m_checkSpellingEnabledBeforeCompletion);
}
}
void LogMessageEdit::tryCompletion()
{
int pos = textCursor().position();
QString text = toPlainText();
// space or tab starts completion
if (text.at(pos - 1).isSpace()) {
// if we already did complete this word and the user types another space,
// don't complete again, since the user can otherwise not enter the word
// without the completion. In this case, also remove the previous completion
// which is still selected
if (m_completing) {
textCursor().removeSelectedText();
stopCompletion();
return;
}
if (!m_completing)
m_completionStartPos = text.lastIndexOf(' ', pos - 2) + 1;
// retrieve current word
int length = pos - m_completionStartPos - 1;
QString word = text.mid(m_completionStartPos, length);
// try to complete the word
QString match = compObj()->makeCompletion(word);
if (!match.isEmpty() && match != word) {
// if the matching text is already existing at this cursor position,
// don't insert it again
if (text.mid(pos).startsWith(match.mid(word.length()))) {
stopCompletion();
return;
}
QTextCursor cursor = this->textCursor();
cursor.deletePreviousChar(); // delete the just inserted space
setTextCursor(cursor);
setCompletedText(match);
} else {
stopCompletion();
}
} else {
stopCompletion();
}
}
void LogMessageEdit::rotateMatches(KeyBindingType type)
{
KCompletion *completionObj = compObj();
if (completionObj && m_completing && (type == PrevCompletionMatch || type == NextCompletionMatch)) {
QString match = (type == PrevCompletionMatch) ? completionObj->previousMatch() : completionObj->nextMatch();
int pos = textCursor().position();
QString text = toPlainText();
QString word = text.mid(m_completionStartPos, pos - m_completionStartPos);
if (match.isEmpty() || match == word)
return;
setCompletedText(match);
}
}
|