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 <KStandardGuiItem>
19#include <QActionGroup>
22#if HAVE_KTEXTADDONS_TEXT_TO_SPEECH_SUPPORT
23#include <TextEditTextToSpeech/TextToSpeech>
25#include <Sonnet/Dialog>
26#include <TextEmoticonsWidgets/EmoticonTextEditAction>
27#include <sonnet/backgroundchecker.h>
29#include <KColorScheme>
30#include <QApplication>
35#include <QTextDocumentFragment>
37#include <sonnet/spellcheckdecorator.h>
39#include <sonnet/speller.h>
41#include <Sonnet/Highlighter>
43using namespace TextCustomEditor;
51#if HAVE_KTEXTADDONS_KIO_SUPPORT
52 , webshortcutMenuManager(new
KIO::KUriFilterSearchProviderActions(q))
55 KConfig sonnetKConfig(QStringLiteral(
"sonnetrc"));
57 checkSpellingEnabled = group.readEntry(
"checkerEnabledByDefault",
false);
58 supportFeatures |= PlainTextEditor::Search;
59 supportFeatures |= PlainTextEditor::SpellChecking;
60 supportFeatures |= PlainTextEditor::TextToSpeech;
61#if HAVE_KTEXTADDONS_KIO_SUPPORT
62 supportFeatures |= PlainTextEditor::AllowWebShortcut;
66 ~PlainTextEditorPrivate()
68 delete richTextDecorator;
75#if HAVE_KTEXTADDONS_KIO_SUPPORT
81 QString spellCheckingConfigFileName;
85 QColor mReadOnlyBackgroundColor;
86 int mInitialFontSize = 0;
87 bool customPalette =
false;
88 bool activateLanguageMenu =
true;
89 bool checkSpellingEnabled =
false;
92PlainTextEditor::PlainTextEditor(
QWidget *parent)
97 setSpellCheckingConfigFileName(
QString());
98 d->mInitialFontSize = font().pointSize();
99 regenerateColorScheme();
102PlainTextEditor::~PlainTextEditor() =
default;
104void PlainTextEditor::regenerateColorScheme()
107 updateReadOnlyColor();
110void PlainTextEditor::addIgnoreWords(
const QStringList &lst)
112 d->ignoreSpellCheckingWords = lst;
113 addIgnoreWordsToHighLighter();
116void PlainTextEditor::slotDisplayMessageIndicator(
const QString &message)
118 d->mTextIndicator->display(message);
138 QAction *separatorAction =
nullptr;
139 const int idx = actionList.
indexOf(actionList[SelectAllAct]) + 1;
140 if (idx < actionList.
count()) {
141 separatorAction = actionList.
at(idx);
143 if (separatorAction) {
144 if (!emptyDocument) {
145 QAction *clearAllAction = KStandardActions::clear(
this, &PlainTextEditor::slotUndoableClear, popup);
150 if (d->supportFeatures & Search) {
152 if (!emptyDocument) {
153 QAction *findAction = KStandardActions::find(
this, &PlainTextEditor::findText, popup);
158 if (!emptyDocument) {
159 QAction *replaceAction = KStandardActions::replace(
this, &PlainTextEditor::replaceText, popup);
168 if (!
isReadOnly() && spellCheckingSupport()) {
172 if (!d->speller->availableBackends().isEmpty()) {
173 if (!emptyDocument) {
175 i18n(
"Check Spelling…"),
177 &PlainTextEditor::slotCheckSpelling);
180 QAction *autoSpellCheckAction = popup->
addAction(
i18n(
"Auto Spell Check"),
this, &PlainTextEditor::slotToggleAutoSpellCheck);
182 autoSpellCheckAction->
setChecked(checkSpellingEnabled());
185 if (checkSpellingEnabled() && d->activateLanguageMenu) {
186 auto languagesMenu =
new QMenu(
i18n(
"Spell Checking Language"), popup);
188 languagesGroup->setExclusive(
true);
190 QString defaultSpellcheckingLanguage = spellCheckingLanguage();
191 if (defaultSpellcheckingLanguage.
isEmpty()) {
193 defaultSpellcheckingLanguage = d->speller->defaultLanguage();
197 while (i.hasNext()) {
199 QAction *languageAction = languagesMenu->addAction(i.key());
201 languageAction->
setChecked(defaultSpellcheckingLanguage == i.value());
202 languageAction->
setData(i.value());
211 if (d->supportFeatures & TextToSpeech) {
212#if HAVE_KTEXTADDONS_TEXT_TO_SPEECH_SUPPORT
213 if (!emptyDocument) {
220#if HAVE_KTEXTADDONS_KIO_SUPPORT
221 if (webShortcutSupport() &&
textCursor().hasSelection()) {
224 d->webshortcutMenuManager->setSelectedText(selectedText);
225 d->webshortcutMenuManager->addWebShortcutsToMenu(popup);
228 if (emojiSupport()) {
234 addExtraMenuEntry(popup,
event->pos());
241void PlainTextEditor::slotInsertEmoticon(
const QString &str)
245void PlainTextEditor::setEmojiSupport(
bool b)
248 d->supportFeatures |= Emoji;
250 d->supportFeatures = (d->supportFeatures & ~Emoji);
254bool PlainTextEditor::emojiSupport()
const
256 return d->supportFeatures & Emoji;
259void PlainTextEditor::addExtraMenuEntry(
QMenu *menu,
QPoint pos)
265void PlainTextEditor::slotSpeakText()
277void PlainTextEditor::slotUndoableClear()
283 cursor.removeSelectedText();
287void PlainTextEditor::setSearchSupport(
bool b)
290 d->supportFeatures |= Search;
292 d->supportFeatures = (d->supportFeatures & ~Search);
296bool PlainTextEditor::searchSupport()
const
298 return d->supportFeatures & Search;
301void PlainTextEditor::setTextToSpeechSupport(
bool b)
304 d->supportFeatures |= TextToSpeech;
306 d->supportFeatures = (d->supportFeatures & ~TextToSpeech);
310bool PlainTextEditor::textToSpeechSupport()
const
312 return d->supportFeatures & TextToSpeech;
315bool PlainTextEditor::spellCheckingSupport()
const
317 return d->supportFeatures & SpellChecking;
320void PlainTextEditor::setSpellCheckingSupport(
bool check)
323 d->supportFeatures |= SpellChecking;
325 d->supportFeatures = (d->supportFeatures & ~SpellChecking);
329void PlainTextEditor::setWebShortcutSupport(
bool b)
331#if HAVE_KTEXTADDONS_KIO_SUPPORT
333 d->supportFeatures |= AllowWebShortcut;
335 d->supportFeatures = (d->supportFeatures & ~AllowWebShortcut);
342bool PlainTextEditor::webShortcutSupport()
const
344#if HAVE_KTEXTADDONS_KIO_SUPPORT
345 return d->supportFeatures & AllowWebShortcut;
351void PlainTextEditor::updateReadOnlyColor()
361void PlainTextEditor::setReadOnly(
bool readOnly)
363 if (!
readOnly &&
hasFocus() && d->checkSpellingEnabled && !d->richTextDecorator) {
374 updateReadOnlyColor();
390void PlainTextEditor::slotCheckSpelling()
393 slotDisplayMessageIndicator(
i18n(
"Nothing to spell check."));
397 if (backgroundSpellCheck->speller().availableBackends().isEmpty()) {
398 slotDisplayMessageIndicator(
i18n(
"No backend available for spell checking."));
399 delete backgroundSpellCheck;
402 if (!d->spellCheckingLanguage.isEmpty()) {
403 backgroundSpellCheck->changeLanguage(d->spellCheckingLanguage);
405 if (!d->ignoreSpellCheckingWords.isEmpty()) {
406 for (
const QString &word : std::as_const(d->ignoreSpellCheckingWords)) {
407 backgroundSpellCheck->speller().addToSession(word);
410 auto spellDialog =
new Sonnet::Dialog(backgroundSpellCheck,
nullptr);
411 backgroundSpellCheck->setParent(spellDialog);
413 connect(spellDialog, &Sonnet::Dialog::replace,
this, &PlainTextEditor::slotSpellCheckerCorrected);
414 connect(spellDialog, &Sonnet::Dialog::misspelling,
this, &PlainTextEditor::slotSpellCheckerMisspelling);
415 connect(spellDialog, &Sonnet::Dialog::autoCorrect,
this, &PlainTextEditor::slotSpellCheckerAutoCorrect);
417 connect(spellDialog, &Sonnet::Dialog::cancel,
this, &PlainTextEditor::slotSpellCheckerCanceled);
425void PlainTextEditor::slotSpellCheckerCanceled()
430 cursor.insertFragment(d->originalDoc);
431 slotSpellCheckerFinished();
434void PlainTextEditor::slotSpellCheckerAutoCorrect(
const QString ¤tWord,
const QString &autoCorrectWord)
436 Q_EMIT spellCheckerAutoCorrect(currentWord, autoCorrectWord);
439void PlainTextEditor::slotSpellCheckerMisspelling(
const QString &text,
int pos)
444void PlainTextEditor::slotSpellCheckerCorrected(
const QString &oldWord,
int pos,
const QString &newWord)
446 if (oldWord != newWord) {
450 cursor.insertText(newWord);
454void PlainTextEditor::slotSpellCheckerFinished()
461void PlainTextEditor::highlightWord(
int length,
int pos)
477void PlainTextEditor::deleteWordBack()
482void PlainTextEditor::deleteWordForward()
487bool PlainTextEditor::event(
QEvent *ev)
491 if (overrideShortcut(e)) {
496 regenerateColorScheme();
502bool PlainTextEditor::overrideShortcut(
QKeyEvent *event)
504 const int key =
event->key() |
event->modifiers();
551bool PlainTextEditor::handleShortcut(
QKeyEvent *event)
553 const int key =
event->key() |
event->modifiers();
671void PlainTextEditor::deleteEndOfLine()
680 cursor.removeSelectedText();
684void PlainTextEditor::moveCursorBeginUpDown(
bool moveUp)
696void PlainTextEditor::moveLineUpDown(
bool moveUp)
702 const bool hasSelection =
cursor.hasSelection();
716 move.removeSelectedText();
724 if (
move.atBlockStart()) {
734 move.clearSelection();
735 move.insertText(text);
739 move.setPosition(end);
749void PlainTextEditor::wheelEvent(
QWheelEvent *event)
752 if (
event->angleDelta().y() > 0) {
754 }
else if (
event->angleDelta().y() < 0) {
763void PlainTextEditor::keyPressEvent(
QKeyEvent *event)
767 if (handleShortcut(event)) {
769 }
else if (
event->key() ==
Qt::Key_Up && isControlClicked && isShiftClicked) {
770 moveLineUpDown(
true);
773 moveLineUpDown(
false);
776 moveCursorBeginUpDown(
true);
779 moveCursorBeginUpDown(
false);
786bool PlainTextEditor::activateLanguageMenu()
const
788 return d->activateLanguageMenu;
791void PlainTextEditor::setActivateLanguageMenu(
bool activate)
793 d->activateLanguageMenu = activate;
798 if (d->richTextDecorator) {
799 return d->richTextDecorator->highlighter();
810void PlainTextEditor::addIgnoreWordsToHighLighter()
812 if (d->ignoreSpellCheckingWords.isEmpty()) {
815 if (d->richTextDecorator) {
817 for (
const QString &word : std::as_const(d->ignoreSpellCheckingWords)) {
829 d->richTextDecorator = decorator;
830 addIgnoreWordsToHighLighter();
833void PlainTextEditor::focusInEvent(
QFocusEvent *event)
835 if (checkSpellingEnabled() && !
isReadOnly() && !d->richTextDecorator && spellCheckingSupport()) {
842bool PlainTextEditor::checkSpellingEnabled()
const
844 return d->checkSpellingEnabled;
847void PlainTextEditor::setCheckSpellingEnabled(
bool check)
849 if (check == d->checkSpellingEnabled) {
852 d->checkSpellingEnabled = check;
853 Q_EMIT checkSpellingChanged(check);
859 if (!d->richTextDecorator) {
862 if (!d->spellCheckingLanguage.isEmpty()) {
863 setSpellCheckingLanguage(spellCheckingLanguage());
872void PlainTextEditor::updateHighLighter()
876void PlainTextEditor::clearDecorator()
878 delete d->richTextDecorator;
879 d->richTextDecorator =
nullptr;
882void PlainTextEditor::createHighlighter()
886 setHighlighter(highlighter);
889void PlainTextEditor::setSpellCheckingConfigFileName(
const QString &_fileName)
891 d->spellCheckingConfigFileName = _fileName;
893 if (config->hasGroup(
"Spelling"_L1)) {
895 d->checkSpellingEnabled = group.readEntry(
"checkerEnabledByDefault",
false);
896 d->spellCheckingLanguage = group.readEntry(
"Language",
QString());
898 setCheckSpellingEnabled(checkSpellingEnabled());
900 if (!d->spellCheckingLanguage.isEmpty() && highlighter()) {
906QString PlainTextEditor::spellCheckingConfigFileName()
const
908 return d->spellCheckingConfigFileName;
911void PlainTextEditor::slotLanguageSelected()
914 setSpellCheckingLanguage(languageAction->
data().
toString());
917const QString &PlainTextEditor::spellCheckingLanguage()
const
919 return d->spellCheckingLanguage;
922void PlainTextEditor::setSpellCheckingLanguage(
const QString &_language)
929 if (_language != d->spellCheckingLanguage) {
930 d->spellCheckingLanguage = _language;
933 group.writeEntry(
"Language", d->spellCheckingLanguage);
934 setCheckSpellingEnabled(checkSpellingEnabled());
936 Q_EMIT languageChanged(_language);
940void PlainTextEditor::slotToggleAutoSpellCheck()
942 setCheckSpellingEnabled(!checkSpellingEnabled());
945 group.writeEntry(
"checkerEnabledByDefault", d->checkSpellingEnabled);
948void PlainTextEditor::slotZoomReset()
951 if (d->mInitialFontSize != f.
pointSize()) {
957#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)
virtual bool event(QEvent *e)
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