File indexing completed on 2024-04-28 04:55:38

0001 /*
0002     This file is part of Choqok, the KDE micro-blogging client
0003 
0004     SPDX-FileCopyrightText: 2010-2012 Mehrdad Momeny <mehrdad.momeny@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 */
0008 
0009 #include "twitterapitextedit.h"
0010 
0011 #include <QAbstractItemView>
0012 #include <QKeyEvent>
0013 #include <QScrollBar>
0014 
0015 #include <KIO/Job>
0016 
0017 #include "urlutils.h"
0018 
0019 #include "twitterapiaccount.h"
0020 #include "twitterapidebug.h"
0021 
0022 class TwitterApiTextEdit::Private
0023 {
0024 public:
0025     Private(Choqok::Account *theAccount)
0026         : acc(theAccount), c(nullptr)
0027     {}
0028     Choqok::Account *acc;
0029     QCompleter *c;
0030 };
0031 
0032 TwitterApiTextEdit::TwitterApiTextEdit(Choqok::Account *theAccount, QWidget *parent)
0033     : TextEdit(theAccount->postCharLimit(), parent), d(new Private(theAccount))
0034 {
0035     qCDebug(CHOQOK);
0036     setTabChangesFocus(false);
0037 }
0038 
0039 TwitterApiTextEdit::~TwitterApiTextEdit()
0040 {
0041     delete d;
0042 }
0043 
0044 void TwitterApiTextEdit::setCompleter(QCompleter *completer)
0045 {
0046     if (d->c) {
0047         QObject::disconnect(d->c, nullptr, this, nullptr);
0048     }
0049 
0050     d->c = completer;
0051 
0052     if (!d->c) {
0053         return;
0054     }
0055 
0056     d->c->setWidget(this);
0057     d->c->setCompletionMode(QCompleter::PopupCompletion);
0058     d->c->setCaseSensitivity(Qt::CaseInsensitive);
0059     connect(d->c, (void (QCompleter::*)(const QString&))&QCompleter::activated,
0060                      this, &TwitterApiTextEdit::insertCompletion);
0061 }
0062 
0063 QCompleter *TwitterApiTextEdit::completer() const
0064 {
0065     return d->c;
0066 }
0067 
0068 void TwitterApiTextEdit::insertCompletion(const QString &completion)
0069 {
0070     if (d->c->widget() != this) {
0071         return;
0072     }
0073     QString textToInsert = completion + QLatin1Char(' ');
0074     QTextCursor tc = textCursor();
0075     tc.movePosition(QTextCursor::EndOfWord);
0076     tc.select(QTextCursor::WordUnderCursor);
0077     bool startWithAt = toPlainText()[tc.selectionStart() - 1] != QLatin1Char('@');
0078     if (startWithAt) {
0079         textToInsert.prepend(QLatin1Char('@'));
0080     }
0081     tc.insertText(textToInsert);
0082     setTextCursor(tc);
0083 }
0084 
0085 // QString TwitterApiTextEdit::textUnderCursor() const
0086 // {
0087 //     QTextCursor tc = textCursor();
0088 //     tc.select(QTextCursor::WordUnderCursor);
0089 //     return tc.selectedText();
0090 // }
0091 
0092 void TwitterApiTextEdit::focusInEvent(QFocusEvent *e)
0093 {
0094     if (d->c) {
0095         d->c->setWidget(this);
0096     }
0097     KTextEdit::focusInEvent(e);
0098 }
0099 
0100 void TwitterApiTextEdit::keyPressEvent(QKeyEvent *e)
0101 {
0102     if (d->c && d->c->popup()->isVisible()) {
0103         // The following keys are forwarded by the completer to the widget
0104         switch (e->key()) {
0105         case Qt::Key_Enter:
0106         case Qt::Key_Return:
0107         case Qt::Key_Escape:
0108 //             case Qt::Key_Backtab:
0109             e->ignore();
0110             return; // let the completer do default behavior
0111         default:
0112 //                 Choqok::UI::TextEdit::keyPressEvent(e);
0113             break;
0114         }
0115     } else if (e->text().isEmpty()) {
0116         Choqok::UI::TextEdit::keyPressEvent(e);
0117         return;
0118     }
0119     if (e->key() == Qt::Key_Tab) {
0120         e->ignore();
0121         return;
0122     }
0123 //     bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_Space); // CTRL+E
0124 //     if (!d->c )// || !isShortcut) // don't process the shortcut when we have a completer
0125     Choqok::UI::TextEdit::keyPressEvent(e);
0126 
0127     const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier |
0128                              Qt::MetaModifier);
0129     if (!d->c || (ctrlOrShift && e->text().isEmpty())) {
0130         return;
0131     }
0132 
0133     static QString eow(QLatin1String("~!@#$%^&*()+{}|:\"<>?,./;'[]\\-= ")); // end of word
0134 //     bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift;
0135     //Implemented internally to get the char before selection :D
0136     QTextCursor tc = textCursor();
0137     tc.select(QTextCursor::WordUnderCursor);
0138     QString completionPrefix = tc.selectedText();
0139     QChar charBeforeSelection;
0140     if (completionPrefix.startsWith(QLatin1Char('@'))) {
0141         charBeforeSelection = completionPrefix.at(0);
0142         completionPrefix.remove(0, 1);
0143     } else {
0144         if (!toPlainText().isEmpty() && tc.selectionStart() > 0) {
0145             charBeforeSelection = toPlainText()[tc.selectionStart() - 1];
0146         }
0147     }
0148 
0149     if (!e->text().isEmpty() && (eow.contains(e->text().right(1)) || completionPrefix.length() < 1 ||
0150                                  charBeforeSelection != QLatin1Char('@'))) {
0151         d->c->popup()->hide();
0152         return;
0153     } else if ((e->key() != Qt::Key_Enter) && (e->key() != Qt::Key_Return)) {
0154         if (textCursor().selectedText().length() &&
0155                 textCursor().selectedText() != completionPrefix) {
0156             return;
0157         }
0158 
0159         if (completionPrefix != d->c->completionPrefix()) {
0160             d->c->setCompletionPrefix(completionPrefix);
0161             d->c->popup()->setCurrentIndex(d->c->completionModel()->index(0, 0));
0162         }
0163         QRect cr = cursorRect();
0164         cr.setWidth(d->c->popup()->sizeHintForColumn(0)
0165                     + d->c->popup()->verticalScrollBar()->sizeHint().width());
0166         d->c->complete(cr); // popup it up!
0167     }
0168 }
0169 
0170 #include "moc_twitterapitextedit.cpp"