6#include "plaintexteditor.h"
7#include "config-textcustomeditor.h"
8#include "widgets/textmessageindicator.h"
10#include <KConfigGroup>
12#if HAVE_KTEXTADDONS_KIO_SUPPORT
13#include <KIO/KUriFilterSearchProviderActions>
15#include <KLocalizedString>
16#include <KSharedConfig>
17#include <KStandardActions>
18#include <QActionGroup>
21#if HAVE_KTEXTADDONS_TEXT_TO_SPEECH_SUPPORT
22#include <TextEditTextToSpeech/TextToSpeech>
24#include <Sonnet/Dialog>
25#include <TextEmoticonsWidgets/EmoticonTextEditAction>
26#include <sonnet/backgroundchecker.h>
28#include <KColorScheme>
29#include <QApplication>
34#include <QTextDocumentFragment>
36#include <sonnet/spellcheckdecorator.h>
38#include <sonnet/speller.h>
40#include <Sonnet/Highlighter>
42using namespace TextCustomEditor;
50#if HAVE_KTEXTADDONS_KIO_SUPPORT
51 , webshortcutMenuManager(new
KIO::KUriFilterSearchProviderActions(q))
54 KConfig sonnetKConfig(QStringLiteral(
"sonnetrc"));
56 checkSpellingEnabled = group.readEntry(
"checkerEnabledByDefault",
false);
57 supportFeatures |= PlainTextEditor::Search;
58 supportFeatures |= PlainTextEditor::SpellChecking;
59 supportFeatures |= PlainTextEditor::TextToSpeech;
60#if HAVE_KTEXTADDONS_KIO_SUPPORT
61 supportFeatures |= PlainTextEditor::AllowWebShortcut;
65 ~PlainTextEditorPrivate()
67 delete richTextDecorator;
74#if HAVE_KTEXTADDONS_KIO_SUPPORT
80 QString spellCheckingConfigFileName;
84 QColor mReadOnlyBackgroundColor;
85 int mInitialFontSize = 0;
86 bool customPalette =
false;
87 bool activateLanguageMenu =
true;
88 bool checkSpellingEnabled =
false;
91PlainTextEditor::PlainTextEditor(
QWidget *parent)
96 setSpellCheckingConfigFileName(
QString());
97 d->mInitialFontSize = font().pointSize();
98 regenerateColorScheme();
101PlainTextEditor::~PlainTextEditor() =
default;
103void PlainTextEditor::regenerateColorScheme()
106 updateReadOnlyColor();
109void PlainTextEditor::addIgnoreWords(
const QStringList &lst)
111 d->ignoreSpellCheckingWords = lst;
112 addIgnoreWordsToHighLighter();
115void PlainTextEditor::slotDisplayMessageIndicator(
const QString &message)
117 d->mTextIndicator->display(message);
137 QAction *separatorAction =
nullptr;
138 const int idx = actionList.
indexOf(actionList[SelectAllAct]) + 1;
139 if (idx < actionList.
count()) {
140 separatorAction = actionList.
at(idx);
142 if (separatorAction) {
143 if (!emptyDocument) {
144 QAction *clearAllAction = KStandardActions::clear(
this, &PlainTextEditor::slotUndoableClear, popup);
149 if (d->supportFeatures & Search) {
151 if (!emptyDocument) {
152 QAction *findAction = KStandardActions::find(
this, &PlainTextEditor::findText, popup);
157 if (!emptyDocument) {
158 QAction *replaceAction = KStandardActions::replace(
this, &PlainTextEditor::replaceText, popup);
167 if (!
isReadOnly() && spellCheckingSupport()) {
171 if (!d->speller->availableBackends().isEmpty()) {
172 if (!emptyDocument) {
174 i18n(
"Check Spelling…"),
176 &PlainTextEditor::slotCheckSpelling);
179 QAction *autoSpellCheckAction = popup->
addAction(
i18n(
"Auto Spell Check"),
this, &PlainTextEditor::slotToggleAutoSpellCheck);
181 autoSpellCheckAction->
setChecked(checkSpellingEnabled());
184 if (checkSpellingEnabled() && d->activateLanguageMenu) {
185 auto languagesMenu =
new QMenu(
i18n(
"Spell Checking Language"), popup);
187 languagesGroup->setExclusive(
true);
189 QString defaultSpellcheckingLanguage = spellCheckingLanguage();
190 if (defaultSpellcheckingLanguage.
isEmpty()) {
192 defaultSpellcheckingLanguage = d->speller->defaultLanguage();
196 while (i.hasNext()) {
198 QAction *languageAction = languagesMenu->addAction(i.key());
200 languageAction->
setChecked(defaultSpellcheckingLanguage == i.value());
201 languageAction->
setData(i.value());
210 if (d->supportFeatures & TextToSpeech) {
211#if HAVE_KTEXTADDONS_TEXT_TO_SPEECH_SUPPORT
212 if (!emptyDocument) {
219#if HAVE_KTEXTADDONS_KIO_SUPPORT
220 if (webShortcutSupport() &&
textCursor().hasSelection()) {
223 d->webshortcutMenuManager->setSelectedText(selectedText);
224 d->webshortcutMenuManager->addWebShortcutsToMenu(popup);
227 if (emojiSupport()) {
233 addExtraMenuEntry(popup,
event->pos());
240void PlainTextEditor::slotInsertEmoticon(
const QString &str)
244void PlainTextEditor::setEmojiSupport(
bool b)
247 d->supportFeatures |= Emoji;
249 d->supportFeatures = (d->supportFeatures & ~Emoji);
253bool PlainTextEditor::emojiSupport()
const
255 return d->supportFeatures & Emoji;
258void PlainTextEditor::addExtraMenuEntry(
QMenu *menu,
QPoint pos)
264void PlainTextEditor::slotSpeakText()
276void PlainTextEditor::slotUndoableClear()
282 cursor.removeSelectedText();
286void PlainTextEditor::setSearchSupport(
bool b)
289 d->supportFeatures |= Search;
291 d->supportFeatures = (d->supportFeatures & ~Search);
295bool PlainTextEditor::searchSupport()
const
297 return d->supportFeatures & Search;
300void PlainTextEditor::setTextToSpeechSupport(
bool b)
303 d->supportFeatures |= TextToSpeech;
305 d->supportFeatures = (d->supportFeatures & ~TextToSpeech);
309bool PlainTextEditor::textToSpeechSupport()
const
311 return d->supportFeatures & TextToSpeech;
314bool PlainTextEditor::spellCheckingSupport()
const
316 return d->supportFeatures & SpellChecking;
319void PlainTextEditor::setSpellCheckingSupport(
bool check)
322 d->supportFeatures |= SpellChecking;
324 d->supportFeatures = (d->supportFeatures & ~SpellChecking);
328void PlainTextEditor::setWebShortcutSupport(
bool b)
330#if HAVE_KTEXTADDONS_KIO_SUPPORT
332 d->supportFeatures |= AllowWebShortcut;
334 d->supportFeatures = (d->supportFeatures & ~AllowWebShortcut);
341bool PlainTextEditor::webShortcutSupport()
const
343#if HAVE_KTEXTADDONS_KIO_SUPPORT
344 return d->supportFeatures & AllowWebShortcut;
350void PlainTextEditor::updateReadOnlyColor()
360void PlainTextEditor::setReadOnly(
bool readOnly)
362 if (!
readOnly &&
hasFocus() && d->checkSpellingEnabled && !d->richTextDecorator) {
373 updateReadOnlyColor();
389void PlainTextEditor::slotCheckSpelling()
392 slotDisplayMessageIndicator(
i18n(
"Nothing to spell check."));
396 if (backgroundSpellCheck->speller().availableBackends().isEmpty()) {
397 slotDisplayMessageIndicator(
i18n(
"No backend available for spell checking."));
398 delete backgroundSpellCheck;
401 if (!d->spellCheckingLanguage.isEmpty()) {
402 backgroundSpellCheck->changeLanguage(d->spellCheckingLanguage);
404 if (!d->ignoreSpellCheckingWords.isEmpty()) {
405 for (
const QString &word : std::as_const(d->ignoreSpellCheckingWords)) {
406 backgroundSpellCheck->speller().addToSession(word);
409 auto spellDialog =
new Sonnet::Dialog(backgroundSpellCheck,
nullptr);
410 backgroundSpellCheck->setParent(spellDialog);
412 connect(spellDialog, &Sonnet::Dialog::replace,
this, &PlainTextEditor::slotSpellCheckerCorrected);
413 connect(spellDialog, &Sonnet::Dialog::misspelling,
this, &PlainTextEditor::slotSpellCheckerMisspelling);
414 connect(spellDialog, &Sonnet::Dialog::autoCorrect,
this, &PlainTextEditor::slotSpellCheckerAutoCorrect);
416 connect(spellDialog, &Sonnet::Dialog::cancel,
this, &PlainTextEditor::slotSpellCheckerCanceled);
424void PlainTextEditor::slotSpellCheckerCanceled()
429 cursor.insertFragment(d->originalDoc);
430 slotSpellCheckerFinished();
433void PlainTextEditor::slotSpellCheckerAutoCorrect(
const QString ¤tWord,
const QString &autoCorrectWord)
435 Q_EMIT spellCheckerAutoCorrect(currentWord, autoCorrectWord);
438void PlainTextEditor::slotSpellCheckerMisspelling(
const QString &text,
int pos)
443void PlainTextEditor::slotSpellCheckerCorrected(
const QString &oldWord,
int pos,
const QString &newWord)
445 if (oldWord != newWord) {
449 cursor.insertText(newWord);
453void PlainTextEditor::slotSpellCheckerFinished()
460void PlainTextEditor::highlightWord(
int length,
int pos)
476void PlainTextEditor::deleteWordBack()
481void PlainTextEditor::deleteWordForward()
486bool PlainTextEditor::event(
QEvent *ev)
490 if (overrideShortcut(e)) {
495 regenerateColorScheme();
501bool PlainTextEditor::overrideShortcut(
QKeyEvent *event)
503 const int key =
event->key() |
event->modifiers();
550bool PlainTextEditor::handleShortcut(
QKeyEvent *event)
552 const int key =
event->key() |
event->modifiers();
670void PlainTextEditor::deleteEndOfLine()
679 cursor.removeSelectedText();
683void PlainTextEditor::moveCursorBeginUpDown(
bool moveUp)
695void PlainTextEditor::moveLineUpDown(
bool moveUp)
701 const bool hasSelection =
cursor.hasSelection();
715 move.removeSelectedText();
723 if (
move.atBlockStart()) {
733 move.clearSelection();
734 move.insertText(text);
738 move.setPosition(end);
748void PlainTextEditor::wheelEvent(
QWheelEvent *event)
751 if (
event->angleDelta().y() > 0) {
753 }
else if (
event->angleDelta().y() < 0) {
762void PlainTextEditor::keyPressEvent(
QKeyEvent *event)
766 if (handleShortcut(event)) {
768 }
else if (
event->key() ==
Qt::Key_Up && isControlClicked && isShiftClicked) {
769 moveLineUpDown(
true);
772 moveLineUpDown(
false);
775 moveCursorBeginUpDown(
true);
778 moveCursorBeginUpDown(
false);
785bool PlainTextEditor::activateLanguageMenu()
const
787 return d->activateLanguageMenu;
790void PlainTextEditor::setActivateLanguageMenu(
bool activate)
792 d->activateLanguageMenu = activate;
797 if (d->richTextDecorator) {
798 return d->richTextDecorator->highlighter();
809void PlainTextEditor::addIgnoreWordsToHighLighter()
811 if (d->ignoreSpellCheckingWords.isEmpty()) {
814 if (d->richTextDecorator) {
816 for (
const QString &word : std::as_const(d->ignoreSpellCheckingWords)) {
828 d->richTextDecorator = decorator;
829 addIgnoreWordsToHighLighter();
832void PlainTextEditor::focusInEvent(
QFocusEvent *event)
834 if (checkSpellingEnabled() && !
isReadOnly() && !d->richTextDecorator && spellCheckingSupport()) {
841bool PlainTextEditor::checkSpellingEnabled()
const
843 return d->checkSpellingEnabled;
846void PlainTextEditor::setCheckSpellingEnabled(
bool check)
848 if (check == d->checkSpellingEnabled) {
851 d->checkSpellingEnabled = check;
852 Q_EMIT checkSpellingChanged(check);
858 if (!d->richTextDecorator) {
861 if (!d->spellCheckingLanguage.isEmpty()) {
862 setSpellCheckingLanguage(spellCheckingLanguage());
871void PlainTextEditor::updateHighLighter()
875void PlainTextEditor::clearDecorator()
877 delete d->richTextDecorator;
878 d->richTextDecorator =
nullptr;
881void PlainTextEditor::createHighlighter()
885 setHighlighter(highlighter);
888void PlainTextEditor::setSpellCheckingConfigFileName(
const QString &_fileName)
890 d->spellCheckingConfigFileName = _fileName;
892 if (config->hasGroup(
"Spelling"_L1)) {
894 d->checkSpellingEnabled = group.readEntry(
"checkerEnabledByDefault",
false);
895 d->spellCheckingLanguage = group.readEntry(
"Language",
QString());
897 setCheckSpellingEnabled(checkSpellingEnabled());
899 if (!d->spellCheckingLanguage.isEmpty() && highlighter()) {
905QString PlainTextEditor::spellCheckingConfigFileName()
const
907 return d->spellCheckingConfigFileName;
910void PlainTextEditor::slotLanguageSelected()
913 setSpellCheckingLanguage(languageAction->
data().
toString());
916const QString &PlainTextEditor::spellCheckingLanguage()
const
918 return d->spellCheckingLanguage;
921void PlainTextEditor::setSpellCheckingLanguage(
const QString &_language)
928 if (_language != d->spellCheckingLanguage) {
929 d->spellCheckingLanguage = _language;
932 group.writeEntry(
"Language", d->spellCheckingLanguage);
933 setCheckSpellingEnabled(checkSpellingEnabled());
935 Q_EMIT languageChanged(_language);
939void PlainTextEditor::slotToggleAutoSpellCheck()
941 setCheckSpellingEnabled(!checkSpellingEnabled());
944 group.writeEntry(
"checkerEnabledByDefault", d->checkSpellingEnabled);
947void PlainTextEditor::slotZoomReset()
950 if (d->mInitialFontSize != f.
pointSize()) {
956#include "moc_plaintexteditor.cpp"
QBrush background(BackgroundRole=NormalBackground) const
static void setAutoHideCursor(QWidget *w, bool enable, bool customEventFilter=false)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void spellCheckDone(const QString &newBuffer)
void spellCheckStatus(const QString &)
void languageChanged(const QString &language)
void ignoreWord(const QString &word)
void setCurrentLanguage(const QString &language)
Highlighter * highlighter() const
void setHighlighter(Highlighter *highlighter)
The PlainTextEditor class.
A widget that displays messages in the top-left corner.
The TextEmoticonsWidgets::EmoticonTextEditAction class.
void insertEmoticon(const QString &)
This signal is emitted each time the user selects an emoji.
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
const QList< QKeySequence > & beginningOfLine()
const QList< QKeySequence > & begin()
const QList< QKeySequence > & cut()
const QList< QKeySequence > & undo()
const QList< QKeySequence > & next()
const QList< QKeySequence > & deleteWordBack()
const QList< QKeySequence > & find()
const QList< QKeySequence > & paste()
const QList< QKeySequence > & end()
const QList< QKeySequence > & copy()
const QList< QKeySequence > & backwardWord()
const QList< QKeySequence > & endOfLine()
const QList< QKeySequence > & forwardWord()
const QList< QKeySequence > & deleteWordForward()
const QList< QKeySequence > & findNext()
const QList< QKeySequence > & prior()
const QList< QKeySequence > & replace()
const QList< QKeySequence > & pasteSelection()
const QList< QKeySequence > & redo()
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
void triggerAction(SliderAction action)
QVariant data() const const
void setIcon(const QIcon &icon)
void setActionGroup(QActionGroup *group)
void setData(const QVariant &data)
void triggered(bool checked)
const QColor & color() const const
QString text(Mode mode) const const
int pointSize() const const
void setPointSize(int pointSize)
Qt::KeyboardModifiers keyboardModifiers()
QIcon fromTheme(const QString &name)
const_reference at(qsizetype i) const const
qsizetype count() const const
qsizetype indexOf(const AT &value, qsizetype from) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * sender() const const
const QColor & color(ColorGroup group, ColorRole role) const const
void setColor(ColorGroup group, ColorRole role, const QColor &color)
QMenu * createStandardContextMenu()
QRect cursorRect() const const
QTextDocument * document() const const
void ensureCursorVisible()
virtual void focusInEvent(QFocusEvent *e) override
void insertPlainText(const QString &text)
virtual void keyPressEvent(QKeyEvent *e) override
bool isReadOnly() const const
void setTextCursor(const QTextCursor &cursor)
QTextCursor textCursor() const const
QString toPlainText() const const
virtual void wheelEvent(QWheelEvent *e) override
bool isEmpty() const const
qsizetype length() const const
int position() const const
bool movePosition(MoveOperation operation, MoveMode mode, int n)
void removeSelectedText()
QString selectedText() const const
bool isEmpty() const const
QString toString() const const