Warning, file /sdk/cervisia/logmessageedit.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * Copyright (c) 2004 Jason Kivlighn <mizunoami44@users.sourceforge.net>
0003  * Copyright (c) 2005-2007 Christian Loose <christian.loose@kdemail.net>
0004  *
0005  * based on work by Jason Kivlighn (krecipes/src/widgets/kretextedit.cpp)
0006  *
0007  * This program is free software; you can redistribute it and/or modify
0008  * it under the terms of the GNU General Public License as published by
0009  * the Free Software Foundation; either version 2 of the License, or
0010  * (at your option) any later version.
0011  *
0012  * This program is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015  * GNU General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU General Public License
0018  * along with this program; if not, write to the Free Software
0019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0020  */
0021 
0022 #include "logmessageedit.h"
0023 using Cervisia::LogMessageEdit;
0024 
0025 #include <QKeyEvent>
0026 
0027 #include <KStandardShortcut>
0028 
0029 LogMessageEdit::LogMessageEdit(QWidget *parent)
0030     : KTextEdit(parent)
0031     , KCompletionBase()
0032     , m_completing(false)
0033     , m_completionStartPos(0)
0034     , m_checkSpellingEnabledBeforeCompletion(false)
0035 {
0036     setAcceptRichText(false);
0037 
0038     // create the completion object
0039     completionObject();
0040 }
0041 
0042 void LogMessageEdit::mousePressEvent(QMouseEvent *event)
0043 {
0044     // a mouse click stops the completion process
0045     QTextEdit::mousePressEvent(event);
0046     stopCompletion();
0047 }
0048 
0049 void LogMessageEdit::setCompletedText(const QString &match)
0050 {
0051     QTextCursor cursor = this->textCursor();
0052 
0053     int pos = cursor.position();
0054     QString text = toPlainText();
0055 
0056     // retrieve the part of the match that's missing
0057     int length = pos - m_completionStartPos;
0058     QString word = match.right(match.length() - length);
0059 
0060     // insert the match
0061     cursor.insertText(word);
0062 
0063     // move cursor back and select the match
0064     cursor.setPosition(pos, QTextCursor::KeepAnchor);
0065     setTextCursor(cursor);
0066 
0067     m_completing = true;
0068 
0069     m_checkSpellingEnabledBeforeCompletion = checkSpellingEnabled();
0070     // disable spellchecker during completion process. Otherwise we lose the
0071     // text selection.
0072     setCheckSpellingEnabled(false);
0073 }
0074 
0075 void LogMessageEdit::setCompletedItems(const QStringList &, bool)
0076 {
0077 }
0078 
0079 void LogMessageEdit::keyPressEvent(QKeyEvent *event)
0080 {
0081     // handle normal key
0082     Qt::KeyboardModifiers modifiers = event->modifiers();
0083     bool noModifier = (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier || modifiers == Qt::KeypadModifier);
0084 
0085     if (noModifier) {
0086         QString keyCode = event->text();
0087         if (!keyCode.isEmpty() && keyCode.unicode()->isPrint()) {
0088             KTextEdit::keyPressEvent(event);
0089             tryCompletion();
0090             event->accept();
0091             return;
0092         }
0093     }
0094 
0095     // get shortcut for text completion key
0096     QList<QKeySequence> shortcut = keyBinding(TextCompletion);
0097     if (shortcut.isEmpty())
0098         shortcut = KStandardShortcut::shortcut(KStandardShortcut::TextCompletion);
0099 
0100     int key = event->key() | event->modifiers();
0101 
0102     // handle text completion key
0103     if (m_completing && shortcut.contains(key)) {
0104         // accept the suggested completion
0105         QTextCursor cursor = this->textCursor();
0106         cursor.setPosition(cursor.selectionEnd());
0107         setTextCursor(cursor);
0108 
0109         stopCompletion();
0110 
0111         return;
0112     }
0113 
0114     // handle previous match key
0115     shortcut = keyBinding(PrevCompletionMatch);
0116     if (shortcut.isEmpty())
0117         shortcut = KStandardShortcut::shortcut(KStandardShortcut::PrevCompletion);
0118 
0119     if (shortcut.contains(key)) {
0120         rotateMatches(PrevCompletionMatch);
0121         return;
0122     }
0123 
0124     // handle next match key
0125     shortcut = keyBinding(NextCompletionMatch);
0126     if (shortcut.isEmpty())
0127         shortcut = KStandardShortcut::shortcut(KStandardShortcut::NextCompletion);
0128 
0129     if (shortcut.contains(key)) {
0130         rotateMatches(NextCompletionMatch);
0131         return;
0132     }
0133 
0134     // any other key (except modifiers) will end the text completion
0135     if (event->key() != Qt::Key_Shift && event->key() != Qt::Key_Control && event->key() != Qt::Key_Alt && event->key() != Qt::Key_Meta) {
0136         stopCompletion();
0137     }
0138 
0139     KTextEdit::keyPressEvent(event);
0140 }
0141 
0142 void LogMessageEdit::stopCompletion()
0143 {
0144     if (m_completing) {
0145         m_completing = false;
0146         setCheckSpellingEnabled(m_checkSpellingEnabledBeforeCompletion);
0147     }
0148 }
0149 
0150 void LogMessageEdit::tryCompletion()
0151 {
0152     int pos = textCursor().position();
0153     QString text = toPlainText();
0154 
0155     // space or tab starts completion
0156     if (text.at(pos - 1).isSpace()) {
0157         // if we already did complete this word and the user types another space,
0158         // don't complete again, since the user can otherwise not enter the word
0159         // without the completion. In this case, also remove the previous completion
0160         // which is still selected
0161         if (m_completing) {
0162             textCursor().removeSelectedText();
0163             stopCompletion();
0164             return;
0165         }
0166 
0167         if (!m_completing)
0168             m_completionStartPos = text.lastIndexOf(' ', pos - 2) + 1;
0169 
0170         // retrieve current word
0171         int length = pos - m_completionStartPos - 1;
0172         QString word = text.mid(m_completionStartPos, length);
0173 
0174         // try to complete the word
0175         QString match = compObj()->makeCompletion(word);
0176         if (!match.isEmpty() && match != word) {
0177             // if the matching text is already existing at this cursor position,
0178             // don't insert it again
0179             if (text.mid(pos).startsWith(match.mid(word.length()))) {
0180                 stopCompletion();
0181                 return;
0182             }
0183 
0184             QTextCursor cursor = this->textCursor();
0185             cursor.deletePreviousChar(); // delete the just inserted space
0186             setTextCursor(cursor);
0187 
0188             setCompletedText(match);
0189         } else {
0190             stopCompletion();
0191         }
0192     } else {
0193         stopCompletion();
0194     }
0195 }
0196 
0197 void LogMessageEdit::rotateMatches(KeyBindingType type)
0198 {
0199     KCompletion *completionObj = compObj();
0200     if (completionObj && m_completing && (type == PrevCompletionMatch || type == NextCompletionMatch)) {
0201         QString match = (type == PrevCompletionMatch) ? completionObj->previousMatch() : completionObj->nextMatch();
0202 
0203         int pos = textCursor().position();
0204         QString text = toPlainText();
0205 
0206         QString word = text.mid(m_completionStartPos, pos - m_completionStartPos);
0207 
0208         if (match.isEmpty() || match == word)
0209             return;
0210 
0211         setCompletedText(match);
0212     }
0213 }