diff --git a/src/composer-ng/richtextcomposerwidget.cpp b/src/composer-ng/richtextcomposerwidget.cpp index e0686de..1c3229c 100644 --- a/src/composer-ng/richtextcomposerwidget.cpp +++ b/src/composer-ng/richtextcomposerwidget.cpp @@ -1,57 +1,57 @@ /* Copyright (C) 2015-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "richtextcomposerwidget.h" #include #include #include using namespace KPIMTextEdit; class Q_DECL_HIDDEN KPIMTextEdit::RichTextComposerWidgetPrivate { public: RichTextComposerWidgetPrivate() { } KPIMTextEdit::RichTextComposer *richTextComposer = nullptr; }; RichTextComposerWidget::RichTextComposerWidget(QWidget *parent) : QWidget(parent) , d(new KPIMTextEdit::RichTextComposerWidgetPrivate) { QHBoxLayout *layout = new QHBoxLayout(this); - layout->setMargin(0); + layout->setContentsMargins(0, 0, 0, 0); d->richTextComposer = new KPIMTextEdit::RichTextComposer(this); d->richTextComposer->setObjectName(QStringLiteral("richtextcomposer")); RichTextEditorWidget *editorWidget = new RichTextEditorWidget(d->richTextComposer, this); layout->addWidget(editorWidget); } RichTextComposerWidget::~RichTextComposerWidget() { delete d; } KPIMTextEdit::RichTextComposer *RichTextComposerWidget::richTextComposer() const { return d->richTextComposer; } diff --git a/src/insertimagewidget.cpp b/src/insertimagewidget.cpp index 2c34d96..8bd73e3 100644 --- a/src/insertimagewidget.cpp +++ b/src/insertimagewidget.cpp @@ -1,244 +1,244 @@ /* Copyright (c) 2012-2019 Montel Laurent This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "insertimagewidget.h" #include #include #include #include #include #include #include #include #include #include #include namespace KPIMTextEdit { static inline QString resolveAlias(const QString &name) { QMimeDatabase db; const QString str = db.mimeTypeForName(name).name(); return str; } class InsertImageWidgetPrivate { public: InsertImageWidgetPrivate(InsertImageWidget *qq) : q(qq) { QVBoxLayout *lay = new QVBoxLayout(q); - lay->setMargin(0); + lay->setContentsMargins(0, 0, 0, 0); QHBoxLayout *hbox = new QHBoxLayout; QLabel *lab = new QLabel(i18n("Image Location:")); imageUrlRequester = new KUrlRequester; QStringList lstMimeTypes; const QList mimetypes = QImageReader::supportedMimeTypes(); lstMimeTypes.reserve(mimetypes.count()); for (const QByteArray &ba : mimetypes) { const QString resolvedAlias = resolveAlias(QString::fromUtf8(ba)); if (!resolvedAlias.isEmpty()) { lstMimeTypes << resolvedAlias; } } imageUrlRequester->setMimeTypeFilters(lstMimeTypes); imageUrlRequester->setWindowTitle(i18n("Add Image")); imageUrlRequester->setMode(KFile::File); q->connect(imageUrlRequester->lineEdit(), &KLineEdit::textChanged, q, [this](const QString &str) { _k_slotUrlChanged(str); }); hbox->addWidget(lab); hbox->addWidget(imageUrlRequester); lab->setBuddy(imageUrlRequester); lay->addLayout(hbox); keepOriginalSize = new QCheckBox(i18n("Keep Original Size")); q->connect(keepOriginalSize, &QCheckBox::clicked, q, [this](bool b) { _k_slotKeepOriginalSizeClicked(b); }); keepOriginalSize->setChecked(true); lay->addWidget(keepOriginalSize); keepImageRatio = new QCheckBox(i18n("Keep Image Ratio")); keepImageRatio->setChecked(true); keepImageRatio->setEnabled(false); lay->addWidget(keepImageRatio); hbox = new QHBoxLayout; lab = new QLabel(i18n("Width:")); width = new QSpinBox; width->setMinimum(1); width->setMaximum(99999); width->setEnabled(false); width->setSuffix(i18n(" px")); lab->setBuddy(width); q->connect(width, QOverload::of(&QSpinBox::valueChanged), q, [this](int val) { _k_slotImageWidthChanged(val); }); hbox->addWidget(lab); hbox->addWidget(width); lay->addLayout(hbox); hbox = new QHBoxLayout; lab = new QLabel(i18n("Height:")); height = new QSpinBox; height->setMinimum(1); height->setMaximum(99999); height->setEnabled(false); height->setSuffix(i18n(" px")); lab->setBuddy(height); q->connect(height, QOverload::of(&QSpinBox::valueChanged), q, [this](int val) { _k_slotImageHeightChanged(val); }); hbox->addWidget(lab); hbox->addWidget(height); lay->addLayout(hbox); KSeparator *sep = new KSeparator; lay->addWidget(sep); hbox = new QHBoxLayout; lab = new QLabel(i18n("Image Preview:")); hbox->addWidget(lab); preview = new QLabel; preview->setFrameStyle(QFrame::Box); preview->setFixedSize(50, 50); hbox->addWidget(preview); lay->addLayout(hbox); } void _k_slotKeepOriginalSizeClicked(bool); void _k_slotUrlChanged(const QString &); void _k_slotImageWidthChanged(int); void _k_slotImageHeightChanged(int); qreal imageRatio = -1; QCheckBox *keepOriginalSize = nullptr; QCheckBox *keepImageRatio = nullptr; QSpinBox *width = nullptr; QSpinBox *height = nullptr; KUrlRequester *imageUrlRequester = nullptr; QLabel *preview = nullptr; InsertImageWidget *q = nullptr; }; void InsertImageWidgetPrivate::_k_slotKeepOriginalSizeClicked(bool checked) { height->setEnabled(!checked); width->setEnabled(!checked); keepImageRatio->setEnabled(!checked); //Update default size _k_slotUrlChanged(imageUrlRequester->text()); } void InsertImageWidgetPrivate::_k_slotUrlChanged(const QString &text) { QImage image(text); if (!image.isNull()) { height->setValue(image.height()); width->setValue(image.width()); imageRatio = (double)((double)image.height() / (double)image.width()); preview->setPixmap(QPixmap::fromImage(image)); } else { preview->clear(); imageRatio = -1; } Q_EMIT q->enableButtonOk(!text.trimmed().isEmpty()); } void InsertImageWidgetPrivate::_k_slotImageWidthChanged(int value) { if (keepImageRatio->isChecked() && !keepOriginalSize->isChecked()) { if (imageRatio != -1) { height->blockSignals(true); height->setValue(value * imageRatio); height->blockSignals(false); } } } void InsertImageWidgetPrivate::_k_slotImageHeightChanged(int value) { if (keepImageRatio->isChecked() && !keepOriginalSize->isChecked()) { if (imageRatio != -1) { width->blockSignals(true); width->setValue(value / imageRatio); width->blockSignals(false); } } } InsertImageWidget::InsertImageWidget(QWidget *parent) : QWidget(parent) , d(new InsertImageWidgetPrivate(this)) { } InsertImageWidget::~InsertImageWidget() { delete d; } int InsertImageWidget::imageWidth() const { return d->width->value(); } int InsertImageWidget::imageHeight() const { return d->height->value(); } void InsertImageWidget::setImageWidth(int value) { d->width->setValue(value); } void InsertImageWidget::setImageHeight(int value) { d->height->setValue(value); } QUrl InsertImageWidget::imageUrl() const { return d->imageUrlRequester->url(); } void InsertImageWidget::setImageUrl(const QUrl &url) { d->imageUrlRequester->setUrl(url); } bool InsertImageWidget::keepOriginalSize() const { return d->keepOriginalSize->isChecked(); } } #include "moc_insertimagewidget.cpp" diff --git a/src/inserttablewidget.cpp b/src/inserttablewidget.cpp index 1e2c636..afc50f2 100644 --- a/src/inserttablewidget.cpp +++ b/src/inserttablewidget.cpp @@ -1,166 +1,166 @@ /* Copyright (c) 2014-2019 Montel Laurent This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "inserttablewidget.h" #include "kpimtextedit_debug.h" #include #include #include #include #include using namespace KPIMTextEdit; class InsertTableWidget::InsertTableWidgetPrivate { public: InsertTableWidgetPrivate(InsertTableWidget *qq) : q(qq) { mRows = new QSpinBox; mRows->setMinimum(1); mRows->setValue(2); mColumns = new QSpinBox; mColumns->setMinimum(1); mColumns->setValue(2); mBorder = new QSpinBox; mBorder->setMinimum(0); mBorder->setValue(1); mBorder->setSuffix(i18n(" px")); QGridLayout *gridLayout = new QGridLayout; - gridLayout->setMargin(0); + gridLayout->setContentsMargins(0, 0, 0, 0); gridLayout->addWidget(new QLabel(i18n("Rows:")), 0, 0); gridLayout->addWidget(mRows, 0, 1); gridLayout->addWidget(new QLabel(i18n("Columns:")), 1, 0); gridLayout->addWidget(mColumns, 1, 1); gridLayout->addWidget(new QLabel(i18n("Border:")), 2, 0); gridLayout->addWidget(mBorder, 2, 1); mTypeOfLength = new KComboBox; q->connect(mTypeOfLength, QOverload::of(&KComboBox::activated), q, &InsertTableWidget::slotTypeOfLengthChanged); // xgettext: no-c-format mTypeOfLength->addItem(i18n("% of windows"), QTextLength::PercentageLength); mTypeOfLength->addItem(i18n("pixels"), QTextLength::FixedLength); mLength = new QSpinBox; mLength->setMinimum(1); mLength->setMaximum(100); mLength->setValue(100); gridLayout->addWidget(new QLabel(i18n("Width:")), 3, 0); gridLayout->addWidget(mLength, 3, 1); gridLayout->addWidget(mTypeOfLength, 3, 2); q->setLayout(gridLayout); } QSpinBox *mColumns = nullptr; QSpinBox *mRows = nullptr; QSpinBox *mBorder = nullptr; QSpinBox *mLength = nullptr; KComboBox *mTypeOfLength = nullptr; InsertTableWidget *q = nullptr; }; InsertTableWidget::InsertTableWidget(QWidget *parent) : QWidget(parent) , d(new InsertTableWidgetPrivate(this)) { } InsertTableWidget::~InsertTableWidget() { delete d; } void InsertTableWidget::slotTypeOfLengthChanged(int index) { switch (index) { case 0: d->mLength->setMaximum(100); d->mLength->setValue(qMin(d->mLength->value(), 100)); break; case 1: d->mLength->setMaximum(9999); break; default: qCDebug(KPIMTEXTEDIT_LOG) << " index not defined " << index; break; } } QTextLength::Type InsertTableWidget::typeOfLength() const { return static_cast(d->mTypeOfLength->itemData( d->mTypeOfLength->currentIndex()).toInt()); } void InsertTableWidget::setTypeOfLength(QTextLength::Type type) { const int index = d->mTypeOfLength->findData(QVariant(type)); d->mTypeOfLength->setCurrentIndex(index); slotTypeOfLengthChanged(index); } int InsertTableWidget::length() const { return d->mLength->value(); } void InsertTableWidget::setLength(int val) { d->mLength->setValue(val); } void InsertTableWidget::setColumns(int col) { d->mColumns->setValue(col); } void InsertTableWidget::setRows(int rows) { d->mRows->setValue(rows); } void InsertTableWidget::setBorder(int border) { d->mBorder->setValue(border); } int InsertTableWidget::columns() const { return d->mColumns->value(); } int InsertTableWidget::rows() const { return d->mRows->value(); } int InsertTableWidget::border() const { return d->mBorder->value(); } diff --git a/src/tableformatdialog.cpp b/src/tableformatdialog.cpp index 24e23b6..53e2b0d 100644 --- a/src/tableformatdialog.cpp +++ b/src/tableformatdialog.cpp @@ -1,230 +1,230 @@ /* Copyright (c) 2012-2019 Montel Laurent This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tableformatdialog.h" #include "inserttablewidget.h" #include #include #include #include #include #include #include #include #include #include using namespace KPIMTextEdit; class TableFormatDialog::TableFormatDialogPrivate { public: TableFormatDialogPrivate(TableFormatDialog *qq) : q(qq) { q->setWindowTitle(i18n("Table Format")); QVBoxLayout *mainLayout = new QVBoxLayout(q); QWidget *page = new QWidget(q); QVBoxLayout *lay = new QVBoxLayout(page); - lay->setMargin(0); + lay->setContentsMargins(0, 0, 0, 0); tableWidget = new InsertTableWidget; lay->addWidget(tableWidget); KSeparator *sep = new KSeparator; lay->addWidget(sep); QHBoxLayout *hbox = new QHBoxLayout; QLabel *lab = new QLabel(i18n("Spacing:")); hbox->addWidget(lab); spacing = new QSpinBox; spacing->setMinimum(0); hbox->addWidget(spacing); lab = new QLabel(i18n("pixels between cells")); hbox->addWidget(lab); lay->addLayout(hbox); hbox = new QHBoxLayout; lab = new QLabel(i18n("Padding:")); hbox->addWidget(lab); padding = new QSpinBox; padding->setMinimum(0); hbox->addWidget(padding); lab = new QLabel(i18n("pixels between cell border and content")); hbox->addWidget(lab); lay->addLayout(hbox); sep = new KSeparator; lay->addWidget(sep); alignment = new KComboBox; alignment->addItem(i18n("Left"), Qt::AlignLeft); alignment->addItem(i18n("Right"), Qt::AlignRight); alignment->addItem(i18n("Center"), Qt::AlignHCenter); alignment->addItem(i18n("Justify"), Qt::AlignJustify); hbox = new QHBoxLayout; lab = new QLabel(i18n("Table Alignment:")); hbox->addWidget(lab); hbox->addWidget(alignment); lay->addLayout(hbox); sep = new KSeparator; lay->addWidget(sep); hbox = new QHBoxLayout; useBackgroundColor = new QCheckBox(i18n("Background Color:")); hbox->addWidget(useBackgroundColor); backgroundColor = new KColorButton; backgroundColor->setDefaultColor(Qt::white); hbox->addWidget(backgroundColor); lay->addLayout(hbox); sep = new KSeparator; lay->addWidget(sep); backgroundColor->setEnabled(false); q->connect(useBackgroundColor, &QCheckBox::toggled, backgroundColor, &KColorButton::setEnabled); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, q); connect(buttonBox, &QDialogButtonBox::accepted, q, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject); mainLayout->addWidget(page); mainLayout->addWidget(buttonBox); } QCheckBox *useBackgroundColor = nullptr; KColorButton *backgroundColor = nullptr; KComboBox *alignment = nullptr; QSpinBox *spacing = nullptr; QSpinBox *padding = nullptr; KPIMTextEdit::InsertTableWidget *tableWidget = nullptr; TableFormatDialog *q = nullptr; }; TableFormatDialog::TableFormatDialog(QWidget *parent) : QDialog(parent) , d(new TableFormatDialogPrivate(this)) { } TableFormatDialog::~TableFormatDialog() { delete d; } int TableFormatDialog::columns() const { return d->tableWidget->columns(); } int TableFormatDialog::rows() const { return d->tableWidget->rows(); } int TableFormatDialog::border() const { return d->tableWidget->border(); } void TableFormatDialog::setColumns(int col) { d->tableWidget->setColumns(col); } void TableFormatDialog::setRows(int row) { d->tableWidget->setRows(row); } void TableFormatDialog::setBorder(int border) { d->tableWidget->setBorder(border); } int TableFormatDialog::padding() const { return d->padding->value(); } void TableFormatDialog::setPadding(int value) { d->padding->setValue(value); } int TableFormatDialog::spacing() const { return d->spacing->value(); } void TableFormatDialog::setSpacing(int value) { d->spacing->setValue(value); } void TableFormatDialog::setAlignment(Qt::Alignment alignment) { d->alignment->setCurrentIndex(d->alignment->findData(QVariant(alignment))); } Qt::Alignment TableFormatDialog::alignment() const { return static_cast(d->alignment->itemData(d->alignment->currentIndex()).toInt()); } QTextLength::Type TableFormatDialog::typeOfLength() const { return d->tableWidget->typeOfLength(); } int TableFormatDialog::length() const { return d->tableWidget->length(); } void TableFormatDialog::setLength(int val) { d->tableWidget->setLength(val); } void TableFormatDialog::setTypeOfLength(QTextLength::Type type) { d->tableWidget->setTypeOfLength(type); } QColor TableFormatDialog::tableBackgroundColor() const { return d->backgroundColor->color(); } void TableFormatDialog::setTableBackgroundColor(const QColor &col) { d->backgroundColor->setColor(col); d->useBackgroundColor->setChecked(true); } bool TableFormatDialog::useBackgroundColor() const { return d->useBackgroundColor->isChecked(); } diff --git a/src/texteditor/commonwidget/textfindreplacewidget.cpp b/src/texteditor/commonwidget/textfindreplacewidget.cpp index b4b0d9d..11ba5c2 100644 --- a/src/texteditor/commonwidget/textfindreplacewidget.cpp +++ b/src/texteditor/commonwidget/textfindreplacewidget.cpp @@ -1,200 +1,202 @@ /* Copyright (C) 2013-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "textfindreplacewidget.h" #include #include #include #include #include #include #include using namespace KPIMTextEdit; TextReplaceWidget::TextReplaceWidget(QWidget *parent) : QWidget(parent) { QHBoxLayout *lay = new QHBoxLayout(this); QLabel *label = new QLabel(i18nc("Replace text", "Replace:"), this); lay->addWidget(label); - const int marg = lay->margin(); - lay->setContentsMargins(marg, 0, marg, 0); + const int marg1 = lay->contentsMargins().left(); + const int marg2 = lay->contentsMargins().right(); + lay->setContentsMargins(marg1, 0, marg2, 0); mReplace = new QLineEdit(this); mReplace->setClearButtonEnabled(true); lay->addWidget(mReplace); mReplaceBtn = new QPushButton(i18n("Replace"), this); connect(mReplaceBtn, &QPushButton::clicked, this, &TextReplaceWidget::replaceText); lay->addWidget(mReplaceBtn); mReplaceAllBtn = new QPushButton(i18n("Replace All"), this); connect(mReplaceAllBtn, &QPushButton::clicked, this, &TextReplaceWidget::replaceAllText); lay->addWidget(mReplaceAllBtn); } TextReplaceWidget::~TextReplaceWidget() { } QLineEdit *TextReplaceWidget::replaceLineEdit() const { return mReplace; } void TextReplaceWidget::slotSearchStringEmpty(bool isEmpty) { mReplaceBtn->setDisabled(isEmpty); mReplaceAllBtn->setDisabled(isEmpty); } TextFindWidget::TextFindWidget(QWidget *parent) : QWidget(parent) { QHBoxLayout *lay = new QHBoxLayout(this); - const int marg = lay->margin(); - lay->setContentsMargins(marg, 0, marg, 0); + const int marg1 = lay->contentsMargins().left(); + const int marg2 = lay->contentsMargins().right(); + lay->setContentsMargins(marg1, 0, marg2, 0); QLabel *label = new QLabel(i18nc("Find text", "F&ind:"), this); lay->addWidget(label); mSearch = new QLineEdit(this); mSearch->setToolTip(i18n("Text to search for")); mSearch->setClearButtonEnabled(true); label->setBuddy(mSearch); lay->addWidget(mSearch); mFindNextBtn = new QPushButton(QIcon::fromTheme(QStringLiteral("go-down-search")), i18nc("Find and go to the next search match", "Next"), this); mFindNextBtn->setToolTip(i18n("Jump to next match")); lay->addWidget(mFindNextBtn); mFindNextBtn->setEnabled(false); mFindPrevBtn = new QPushButton(QIcon::fromTheme(QStringLiteral("go-up-search")), i18nc("Find and go to the previous search match", "Previous"), this); mFindPrevBtn->setToolTip(i18n("Jump to previous match")); lay->addWidget(mFindPrevBtn); mFindPrevBtn->setEnabled(false); QPushButton *optionsBtn = new QPushButton(this); optionsBtn->setText(i18n("Options")); optionsBtn->setToolTip(i18n("Modify search behavior")); QMenu *optionsMenu = new QMenu(optionsBtn); mCaseSensitiveAct = optionsMenu->addAction(i18n("Case sensitive")); mCaseSensitiveAct->setCheckable(true); mWholeWordAct = optionsMenu->addAction(i18n("Whole word")); mWholeWordAct->setCheckable(true); mRegExpAct = optionsMenu->addAction(i18n("Regular Expression")); mRegExpAct->setCheckable(true); optionsBtn->setMenu(optionsMenu); lay->addWidget(optionsBtn); connect(mFindNextBtn, &QPushButton::clicked, this, &TextFindWidget::findNext); connect(mFindPrevBtn, &QPushButton::clicked, this, &TextFindWidget::findPrev); connect(mCaseSensitiveAct, &QAction::toggled, this, &TextFindWidget::updateSearchOptions); connect(mWholeWordAct, &QAction::toggled, this, &TextFindWidget::updateSearchOptions); connect(mRegExpAct, &QAction::toggled, this, &TextFindWidget::updateSearchOptions); connect(mSearch, &QLineEdit::textChanged, this, &TextFindWidget::slotAutoSearch); } TextFindWidget::~TextFindWidget() { } void TextFindWidget::setFoundMatch(bool match) { #ifndef QT_NO_STYLE_STYLESHEET QString styleSheet; if (!mSearch->text().isEmpty()) { KColorScheme::BackgroundRole bgColorScheme; if (match) { bgColorScheme = KColorScheme::PositiveBackground; } else { bgColorScheme = KColorScheme::NegativeBackground; } KStatefulBrush bgBrush(KColorScheme::View, bgColorScheme); styleSheet = QStringLiteral("QLineEdit{ background-color:%1 }") .arg(bgBrush.brush(mSearch).color().name()); } mSearch->setStyleSheet(styleSheet); #endif } void TextFindWidget::slotAutoSearch(const QString &str) { const bool isNotEmpty = (!str.isEmpty()); mFindPrevBtn->setEnabled(isNotEmpty); mFindNextBtn->setEnabled(isNotEmpty); Q_EMIT searchStringEmpty(!isNotEmpty); Q_EMIT autoSearch(str); if (str.isEmpty()) { Q_EMIT clearSearch(); } } QLineEdit *TextFindWidget::searchLineEdit() const { return mSearch; } bool TextFindWidget::isRegularExpression() const { return mRegExpAct->isChecked(); } QString TextFindWidget::searchText() const { return mSearch->text(); } QRegExp TextFindWidget::searchRegExp() const { QRegExp reg; if (mCaseSensitiveAct->isChecked()) { reg.setCaseSensitivity(Qt::CaseSensitive); } else { reg.setCaseSensitivity(Qt::CaseInsensitive); } QString searchTextString = mSearch->text(); if (mWholeWordAct->isChecked()) { searchTextString = QStringLiteral("\\b") + searchTextString + QStringLiteral("\\b"); } reg.setPattern(searchTextString); return reg; } QTextDocument::FindFlags TextFindWidget::searchOptions() const { QTextDocument::FindFlags opt = nullptr; if (mCaseSensitiveAct->isChecked()) { opt |= QTextDocument::FindCaseSensitively; } if (mWholeWordAct->isChecked()) { opt |= QTextDocument::FindWholeWords; } return opt; } diff --git a/src/texteditor/commonwidget/textgotolinewidget.cpp b/src/texteditor/commonwidget/textgotolinewidget.cpp index 1ac77f5..6f0245a 100644 --- a/src/texteditor/commonwidget/textgotolinewidget.cpp +++ b/src/texteditor/commonwidget/textgotolinewidget.cpp @@ -1,143 +1,143 @@ /* Copyright (C) 2014-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "textgotolinewidget.h" #include #include #include #include #include #include #include #include using namespace KPIMTextEdit; class Q_DECL_HIDDEN KPIMTextEdit::TextGoToLineWidgetPrivate { public: TextGoToLineWidgetPrivate() { } QSpinBox *mSpinbox = nullptr; QPushButton *mGoToLine = nullptr; }; TextGoToLineWidget::TextGoToLineWidget(QWidget *parent) : QWidget(parent) , d(new KPIMTextEdit::TextGoToLineWidgetPrivate) { QHBoxLayout *hbox = new QHBoxLayout(this); - hbox->setMargin(2); + hbox->setContentsMargins(2, 2, 2, 2); QToolButton *closeBtn = new QToolButton(this); closeBtn->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); closeBtn->setIconSize(QSize(16, 16)); closeBtn->setToolTip(i18n("Close")); closeBtn->setObjectName(QStringLiteral("closebutton")); #ifndef QT_NO_ACCESSIBILITY closeBtn->setAccessibleName(i18n("Close")); #endif closeBtn->setAutoRaise(true); connect(closeBtn, &QToolButton::clicked, this, &TextGoToLineWidget::slotCloseBar); hbox->addWidget(closeBtn); QLabel *lab = new QLabel(i18n("Go to Line:")); hbox->addWidget(lab); d->mSpinbox = new QSpinBox; d->mSpinbox->setMinimum(1); d->mSpinbox->setObjectName(QStringLiteral("line")); connect(d->mSpinbox, &QSpinBox::editingFinished, this, &TextGoToLineWidget::slotGoToLine); hbox->addWidget(d->mSpinbox); d->mGoToLine = new QPushButton(QIcon::fromTheme(QStringLiteral("go-jump")), i18n("Go")); d->mGoToLine->setFlat(true); connect(d->mGoToLine, &QPushButton::clicked, this, &TextGoToLineWidget::slotGoToLine); d->mGoToLine->setObjectName(QStringLiteral("gotoline")); hbox->addWidget(d->mGoToLine); hbox->addStretch(); d->mSpinbox->setFocus(); } TextGoToLineWidget::~TextGoToLineWidget() { // mSpinbox can emit signals from its dtor, which are connected to this object // so we need to make sure these connections are removed before we destroy ourselves delete d->mSpinbox; delete d; } void TextGoToLineWidget::setMaximumLineCount(int max) { d->mSpinbox->setMaximum(max); } void TextGoToLineWidget::goToLine() { show(); d->mSpinbox->setFocus(); d->mSpinbox->selectAll(); } void TextGoToLineWidget::slotGoToLine() { Q_EMIT moveToLine(d->mSpinbox->value()); } void TextGoToLineWidget::showEvent(QShowEvent *e) { if (!e->spontaneous()) { d->mSpinbox->setFocus(); } QWidget::showEvent(e); } void TextGoToLineWidget::slotBlockCountChanged(int numberBlockCount) { if (!isHidden()) { setMaximumLineCount(numberBlockCount); } } void TextGoToLineWidget::slotCloseBar() { hide(); Q_EMIT hideGotoLine(); } bool TextGoToLineWidget::event(QEvent *e) { // Close the bar when pressing Escape. // Not using a QShortcut for this because it could conflict with // window-global actions (e.g. Emil Sedgh binds Esc to "close tab"). // With a shortcut override we can catch this before it gets to kactions. const bool shortCutOverride = (e->type() == QEvent::ShortcutOverride); if (shortCutOverride || e->type() == QEvent::KeyPress) { QKeyEvent *kev = static_cast(e); if (kev->key() == Qt::Key_Escape) { e->accept(); slotCloseBar(); return true; } } return QWidget::event(e); } diff --git a/src/texteditor/commonwidget/textmessageindicator.cpp b/src/texteditor/commonwidget/textmessageindicator.cpp index 5e76757..349f164 100644 --- a/src/texteditor/commonwidget/textmessageindicator.cpp +++ b/src/texteditor/commonwidget/textmessageindicator.cpp @@ -1,219 +1,219 @@ /* Copyright (C) 2014-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "textmessageindicator.h" #include #include #include #include #include #include using namespace KPIMTextEdit; TextMessageIndicator::TextMessageIndicator(QWidget *parent) : QWidget(parent) { setObjectName(QStringLiteral("TextMessageIndicator")); setFocusPolicy(Qt::NoFocus); QPalette pal = palette(); pal.setColor(QPalette::Active, QPalette::Window, QApplication::palette().highlight().color()); setPalette(pal); // if the layout is LtR, we can safely place it in the right position if (layoutDirection() == Qt::LeftToRight) { move(10, parentWidget()->height() - 10); } resize(0, 0); hide(); } void TextMessageIndicator::display(const QString &message, const QString &details, Icon icon, int durationMs) { if (message.isEmpty()) { return; } // set text mMessage = message; mDetails = details; // reset vars mLineSpacing = 0; // load icon (if set) mSymbol = QPixmap(); if (icon != None) { switch (icon) { case Error: mSymbol = SmallIcon(QStringLiteral("dialog-error")); break; case Warning: mSymbol = SmallIcon(QStringLiteral("dialog-warning")); break; default: mSymbol = SmallIcon(QStringLiteral("dialog-information")); break; } } computeSizeAndResize(); // show widget and schedule a repaint show(); update(); // close the message window after given mS if (durationMs > 0) { if (!mTimer) { mTimer = new QTimer(this); mTimer->setSingleShot(true); connect(mTimer, &QTimer::timeout, this, &TextMessageIndicator::hide); } mTimer->start(durationMs); } else if (mTimer) { mTimer->stop(); } qobject_cast(parentWidget())->viewport()->installEventFilter(this); } QRect TextMessageIndicator::computeTextRect(const QString &message, int extra_width) const // Return the QRect which embeds the text { int charSize = fontMetrics().averageCharWidth(); /* width of the viewport, minus 20 (~ size removed by further resizing), minus the extra size (usually the icon width), minus (a bit empirical) twice the mean width of a character to ensure that the bounding box is really smaller than the container. */ const int boundingWidth = qobject_cast(parentWidget())->viewport()->width() - 20 - (extra_width > 0 ? 2 + extra_width : 0) - 2 * charSize; QRect textRect = fontMetrics().boundingRect(0, 0, boundingWidth, 0, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, message); textRect.translate(-textRect.left(), -textRect.top()); textRect.adjust(0, 0, 2, 2); return textRect; } void TextMessageIndicator::computeSizeAndResize() { // determine text rectangle const QRect textRect = computeTextRect(mMessage, mSymbol.width()); int width = textRect.width(), height = textRect.height(); if (!mDetails.isEmpty()) { // determine details text rectangle const QRect detailsRect = computeTextRect(mDetails, mSymbol.width()); width = qMax(width, detailsRect.width()); height += detailsRect.height(); // plus add a ~60% line spacing mLineSpacing = static_cast< int >(fontMetrics().height() * 0.6); height += mLineSpacing; } // update geometry with icon information if (!mSymbol.isNull()) { width += 2 + mSymbol.width(); height = qMax(height, mSymbol.height()); } // resize widget resize(QRect(0, 0, width + 10, height + 8).size()); // if the layout is RtL, we can move it to the right place only after we // know how much size it will take int posX = parentWidget()->width() - geometry().width() - 20 - 1; if (layoutDirection() == Qt::RightToLeft) { posX = 10; } move(posX, parentWidget()->height() - geometry().height() - 20); } bool TextMessageIndicator::eventFilter(QObject *obj, QEvent *event) { /* if the parent object (scroll area) resizes, the message should resize as well */ if (event->type() == QEvent::Resize) { QResizeEvent *resizeEvent = static_cast(event); if (resizeEvent->oldSize() != resizeEvent->size()) { computeSizeAndResize(); } } // standard event processing return QObject::eventFilter(obj, event); } void TextMessageIndicator::paintEvent(QPaintEvent * /* e */) { const QRect textRect = computeTextRect(mMessage, mSymbol.width()); QRect detailsRect; if (!mDetails.isEmpty()) { detailsRect = computeTextRect(mDetails, mSymbol.width()); } int textXOffset = 0; // add 2 to account for the reduced drawRoundRect later int textYOffset = (geometry().height() - textRect.height() - detailsRect.height() - mLineSpacing + 2) / 2; int iconXOffset = 0; int iconYOffset = !mSymbol.isNull() ? (geometry().height() - mSymbol.height()) / 2 : 0; int shadowOffset = 1; if (layoutDirection() == Qt::RightToLeft) { iconXOffset = 2 + textRect.width(); } else { textXOffset = 2 + mSymbol.width(); } // draw background QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(Qt::black); painter.setBrush(palette().color(QPalette::Window)); painter.translate(0.5, 0.5); - painter.drawRoundRect(1, 1, width() - 2, height() - 2, 1600 / width(), 1600 / height()); + painter.drawRoundedRect(1, 1, width() - 2, height() - 2, 1600 / width(), 1600 / height(), Qt::RelativeSize); // draw icon if present if (!mSymbol.isNull()) { painter.drawPixmap(5 + iconXOffset, iconYOffset, mSymbol, 0, 0, mSymbol.width(), mSymbol.height()); } const int xStartPoint = 5 + textXOffset; const int yStartPoint = textYOffset; const int textDrawingFlags = Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap; // draw shadow and text painter.setPen(palette().color(QPalette::Window).darker(115)); painter.drawText(xStartPoint + shadowOffset, yStartPoint + shadowOffset, textRect.width(), textRect.height(), textDrawingFlags, mMessage); if (!mDetails.isEmpty()) { painter.drawText(xStartPoint + shadowOffset, yStartPoint + textRect.height() + mLineSpacing + shadowOffset, textRect.width(), detailsRect.height(), textDrawingFlags, mDetails); } painter.setPen(palette().color(QPalette::WindowText)); painter.drawText(xStartPoint, yStartPoint, textRect.width(), textRect.height(), textDrawingFlags, mMessage); if (!mDetails.isEmpty()) { painter.drawText(xStartPoint + shadowOffset, yStartPoint + textRect.height() + mLineSpacing, textRect.width(), detailsRect.height(), textDrawingFlags, mDetails); } } void TextMessageIndicator::mousePressEvent(QMouseEvent * /*e*/) { if (mTimer) { mTimer->stop(); } hide(); } diff --git a/src/texteditor/plaintexteditor/plaintexteditor.cpp b/src/texteditor/plaintexteditor/plaintexteditor.cpp index 51bf15f..5054eda 100644 --- a/src/texteditor/plaintexteditor/plaintexteditor.cpp +++ b/src/texteditor/plaintexteditor/plaintexteditor.cpp @@ -1,892 +1,892 @@ /* Copyright (C) 2013-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "plaintexteditor.h" #include "kpimtextedit_debug.h" #include "texteditor/commonwidget/textmessageindicator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "texttospeech/texttospeech.h" #include #include #include #include #include #include #include #include #include #include #include using namespace KPIMTextEdit; class Q_DECL_HIDDEN PlainTextEditor::PlainTextEditorPrivate { public: PlainTextEditorPrivate(PlainTextEditor *qq) : q(qq) , mTextIndicator(new KPIMTextEdit::TextMessageIndicator(q)) , webshortcutMenuManager(new KIO::KUriFilterSearchProviderActions(q)) { KConfig sonnetKConfig(QStringLiteral("sonnetrc")); KConfigGroup group(&sonnetKConfig, "Spelling"); checkSpellingEnabled = group.readEntry("checkerEnabledByDefault", false); supportFeatures |= PlainTextEditor::Search; supportFeatures |= PlainTextEditor::SpellChecking; supportFeatures |= PlainTextEditor::TextToSpeech; supportFeatures |= PlainTextEditor::AllowWebShortcut; } ~PlainTextEditorPrivate() { delete richTextDecorator; delete speller; } QStringList ignoreSpellCheckingWords; PlainTextEditor *q; KPIMTextEdit::TextMessageIndicator *mTextIndicator = nullptr; KIO::KUriFilterSearchProviderActions *webshortcutMenuManager = nullptr; Sonnet::SpellCheckDecorator *richTextDecorator = nullptr; Sonnet::Speller *speller = nullptr; QString spellCheckingConfigFileName; QString spellCheckingLanguage; QTextDocumentFragment originalDoc; PlainTextEditor::SupportFeatures supportFeatures; int mInitialFontSize = 0; bool customPalette = false; bool activateLanguageMenu = true; bool checkSpellingEnabled = false; }; PlainTextEditor::PlainTextEditor(QWidget *parent) : QPlainTextEdit(parent) , d(new PlainTextEditor::PlainTextEditorPrivate(this)) { KCursor::setAutoHideCursor(this, true, false); setSpellCheckingConfigFileName(QString()); d->mInitialFontSize = font().pointSize(); } PlainTextEditor::~PlainTextEditor() { delete d; } void PlainTextEditor::addIgnoreWords(const QStringList &lst) { d->ignoreSpellCheckingWords = lst; addIgnoreWordsToHighLighter(); } void PlainTextEditor::slotDisplayMessageIndicator(const QString &message) { d->mTextIndicator->display(message); } void PlainTextEditor::contextMenuEvent(QContextMenuEvent *event) { QMenu *popup = createStandardContextMenu(); if (popup) { const bool emptyDocument = document()->isEmpty(); if (!isReadOnly()) { QList actionList = popup->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, ClearAct, SelectAllAct, NCountActs }; QAction *separatorAction = nullptr; const int idx = actionList.indexOf(actionList[SelectAllAct]) + 1; if (idx < actionList.count()) { separatorAction = actionList.at(idx); } if (separatorAction) { if (!emptyDocument) { QAction *clearAllAction = KStandardAction::clear(this, &PlainTextEditor::slotUndoableClear, popup); popup->insertAction(separatorAction, clearAllAction); } } } KIconTheme::assignIconsToContextMenu(isReadOnly() ? KIconTheme::ReadOnlyText : KIconTheme::TextEditor, popup->actions()); if (d->supportFeatures & Search) { popup->addSeparator(); if (!emptyDocument) { popup->addAction(KStandardGuiItem::find().icon(), KStandardGuiItem::find().text(), this, SIGNAL(findText()), Qt::Key_F + Qt::CTRL); popup->addSeparator(); } if (!isReadOnly()) { if (!emptyDocument) { popup->addAction(i18n("Replace..."), this, SIGNAL(replaceText()), Qt::Key_R + Qt::CTRL); popup->addSeparator(); } } } else { popup->addSeparator(); } if (!isReadOnly() && spellCheckingSupport()) { if (!d->speller) { d->speller = new Sonnet::Speller(); } if (!d->speller->availableBackends().isEmpty()) { if (!emptyDocument) { popup->addAction(QIcon::fromTheme(QStringLiteral("tools-check-spelling")), i18n("Check Spelling..."), this, &PlainTextEditor::slotCheckSpelling); popup->addSeparator(); } QAction *autoSpellCheckAction = popup->addAction(i18n("Auto Spell Check"), this, &PlainTextEditor::slotToggleAutoSpellCheck); autoSpellCheckAction->setCheckable(true); autoSpellCheckAction->setChecked(checkSpellingEnabled()); popup->addAction(autoSpellCheckAction); if (checkSpellingEnabled() && d->activateLanguageMenu) { QMenu *languagesMenu = new QMenu(i18n("Spell Checking Language"), popup); QActionGroup *languagesGroup = new QActionGroup(languagesMenu); languagesGroup->setExclusive(true); QString defaultSpellcheckingLanguage = spellCheckingLanguage(); if (defaultSpellcheckingLanguage.isEmpty()) { //TODO fix default value defaultSpellcheckingLanguage = d->speller->defaultLanguage(); } QMapIterator i(d->speller->availableDictionaries()); while (i.hasNext()) { i.next(); QAction *languageAction = languagesMenu->addAction(i.key()); languageAction->setCheckable(true); languageAction->setChecked(defaultSpellcheckingLanguage == i.value()); languageAction->setData(i.value()); languageAction->setActionGroup(languagesGroup); connect(languageAction, &QAction::triggered, this, &PlainTextEditor::slotLanguageSelected); } popup->addMenu(languagesMenu); } popup->addSeparator(); } } if (d->supportFeatures & TextToSpeech) { if (KPIMTextEdit::TextToSpeech::self()->isReady()) { if (!emptyDocument) { QAction *speakAction = popup->addAction(i18n("Speak Text")); speakAction->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-text-to-speech"))); connect(speakAction, &QAction::triggered, this, &PlainTextEditor::slotSpeakText); } } } if (webShortcutSupport() && textCursor().hasSelection()) { popup->addSeparator(); const QString selectedText = textCursor().selectedText(); d->webshortcutMenuManager->setSelectedText(selectedText); d->webshortcutMenuManager->addWebShortcutsToMenu(popup); } addExtraMenuEntry(popup, event->pos()); popup->exec(event->globalPos()); delete popup; } } void PlainTextEditor::addExtraMenuEntry(QMenu *menu, QPoint pos) { Q_UNUSED(menu); Q_UNUSED(pos); } void PlainTextEditor::slotSpeakText() { QString text; if (textCursor().hasSelection()) { text = textCursor().selectedText(); } else { text = toPlainText(); } //qCDebug(KPIMTEXTEDIT_LOG) << " KPIMTextEdit::TextToSpeech::self()->isReady() :" << KPIMTextEdit::TextToSpeech::self()->isReady(); Q_EMIT say(text); } void PlainTextEditor::slotUndoableClear() { QTextCursor cursor = textCursor(); cursor.beginEditBlock(); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.removeSelectedText(); cursor.endEditBlock(); } void PlainTextEditor::setSearchSupport(bool b) { if (b) { d->supportFeatures |= Search; } else { d->supportFeatures = (d->supportFeatures & ~Search); } } bool PlainTextEditor::searchSupport() const { return d->supportFeatures & Search; } void PlainTextEditor::setTextToSpeechSupport(bool b) { if (b) { d->supportFeatures |= TextToSpeech; } else { d->supportFeatures = (d->supportFeatures & ~TextToSpeech); } } bool PlainTextEditor::textToSpeechSupport() const { return d->supportFeatures & TextToSpeech; } bool PlainTextEditor::spellCheckingSupport() const { return d->supportFeatures & SpellChecking; } void PlainTextEditor::setSpellCheckingSupport(bool check) { if (check) { d->supportFeatures |= SpellChecking; } else { d->supportFeatures = (d->supportFeatures & ~SpellChecking); } } void PlainTextEditor::setWebShortcutSupport(bool b) { if (b) { d->supportFeatures |= AllowWebShortcut; } else { d->supportFeatures = (d->supportFeatures & ~AllowWebShortcut); } } bool PlainTextEditor::webShortcutSupport() const { return d->supportFeatures & AllowWebShortcut; } void PlainTextEditor::setReadOnly(bool readOnly) { if (!readOnly && hasFocus() && d->checkSpellingEnabled && !d->richTextDecorator) { createHighlighter(); } if (readOnly == isReadOnly()) { return; } if (readOnly) { clearDecorator(); d->customPalette = testAttribute(Qt::WA_SetPalette); QPalette p = palette(); - QColor color = p.color(QPalette::Disabled, QPalette::Background); + QColor color = p.color(QPalette::Disabled, QPalette::Window); p.setColor(QPalette::Base, color); - p.setColor(QPalette::Background, color); + p.setColor(QPalette::Window, color); setPalette(p); } else { if (d->customPalette && testAttribute(Qt::WA_SetPalette)) { QPalette p = palette(); QColor color = p.color(QPalette::Normal, QPalette::Base); p.setColor(QPalette::Base, color); - p.setColor(QPalette::Background, color); + p.setColor(QPalette::Window, color); setPalette(p); } else { setPalette(QPalette()); } } QPlainTextEdit::setReadOnly(readOnly); } void PlainTextEditor::slotCheckSpelling() { if (document()->isEmpty()) { slotDisplayMessageIndicator(i18n("Nothing to spell check.")); return; } Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker; if (backgroundSpellCheck->speller().availableBackends().isEmpty()) { slotDisplayMessageIndicator(i18n("No backend available for spell checking.")); delete backgroundSpellCheck; return; } if (!d->spellCheckingLanguage.isEmpty()) { backgroundSpellCheck->changeLanguage(d->spellCheckingLanguage); } if (!d->ignoreSpellCheckingWords.isEmpty()) { for (const QString &word : qAsConst(d->ignoreSpellCheckingWords)) { backgroundSpellCheck->speller().addToSession(word); } } Sonnet::Dialog *spellDialog = new Sonnet::Dialog(backgroundSpellCheck, nullptr); backgroundSpellCheck->setParent(spellDialog); spellDialog->setAttribute(Qt::WA_DeleteOnClose, true); connect(spellDialog, &Sonnet::Dialog::replace, this, &PlainTextEditor::slotSpellCheckerCorrected); connect(spellDialog, &Sonnet::Dialog::misspelling, this, &PlainTextEditor::slotSpellCheckerMisspelling); connect(spellDialog, &Sonnet::Dialog::autoCorrect, this, &PlainTextEditor::slotSpellCheckerAutoCorrect); connect(spellDialog, QOverload::of(&Sonnet::Dialog::done), this, &PlainTextEditor::slotSpellCheckerFinished); connect(spellDialog, &Sonnet::Dialog::cancel, this, &PlainTextEditor::slotSpellCheckerCanceled); connect(spellDialog, &Sonnet::Dialog::spellCheckStatus, this, &PlainTextEditor::spellCheckStatus); connect(spellDialog, &Sonnet::Dialog::languageChanged, this, &PlainTextEditor::languageChanged); d->originalDoc = QTextDocumentFragment(document()); spellDialog->setBuffer(toPlainText()); spellDialog->show(); } void PlainTextEditor::slotSpellCheckerCanceled() { QTextDocument *doc = document(); doc->clear(); QTextCursor cursor(doc); cursor.insertFragment(d->originalDoc); slotSpellCheckerFinished(); } void PlainTextEditor::slotSpellCheckerAutoCorrect(const QString ¤tWord, const QString &autoCorrectWord) { Q_EMIT spellCheckerAutoCorrect(currentWord, autoCorrectWord); } void PlainTextEditor::slotSpellCheckerMisspelling(const QString &text, int pos) { highlightWord(text.length(), pos); } void PlainTextEditor::slotSpellCheckerCorrected(const QString &oldWord, int pos, const QString &newWord) { if (oldWord != newWord) { QTextCursor cursor(document()); cursor.setPosition(pos); cursor.setPosition(pos + oldWord.length(), QTextCursor::KeepAnchor); cursor.insertText(newWord); } } void PlainTextEditor::slotSpellCheckerFinished() { QTextCursor cursor(document()); cursor.clearSelection(); setTextCursor(cursor); } void PlainTextEditor::highlightWord(int length, int pos) { QTextCursor cursor(document()); cursor.setPosition(pos); cursor.setPosition(pos + length, QTextCursor::KeepAnchor); setTextCursor(cursor); ensureCursorVisible(); } static void deleteWord(QTextCursor cursor, QTextCursor::MoveOperation op) { cursor.clearSelection(); cursor.movePosition(op, QTextCursor::KeepAnchor); cursor.removeSelectedText(); } void PlainTextEditor::deleteWordBack() { deleteWord(textCursor(), QTextCursor::PreviousWord); } void PlainTextEditor::deleteWordForward() { deleteWord(textCursor(), QTextCursor::WordRight); } bool PlainTextEditor::event(QEvent *ev) { if (ev->type() == QEvent::ShortcutOverride) { QKeyEvent *e = static_cast(ev); if (overrideShortcut(e)) { e->accept(); return true; } } return QPlainTextEdit::event(ev); } bool PlainTextEditor::overrideShortcut(QKeyEvent *event) { const int key = event->key() | event->modifiers(); if (KStandardShortcut::copy().contains(key)) { return true; } else if (KStandardShortcut::paste().contains(key)) { return true; } else if (KStandardShortcut::cut().contains(key)) { return true; } else if (KStandardShortcut::undo().contains(key)) { return true; } else if (KStandardShortcut::redo().contains(key)) { return true; } else if (KStandardShortcut::deleteWordBack().contains(key)) { return true; } else if (KStandardShortcut::deleteWordForward().contains(key)) { return true; } else if (KStandardShortcut::backwardWord().contains(key)) { return true; } else if (KStandardShortcut::forwardWord().contains(key)) { return true; } else if (KStandardShortcut::next().contains(key)) { return true; } else if (KStandardShortcut::prior().contains(key)) { return true; } else if (KStandardShortcut::begin().contains(key)) { return true; } else if (KStandardShortcut::end().contains(key)) { return true; } else if (KStandardShortcut::beginningOfLine().contains(key)) { return true; } else if (KStandardShortcut::endOfLine().contains(key)) { return true; } else if (KStandardShortcut::pasteSelection().contains(key)) { return true; } else if (searchSupport() && KStandardShortcut::find().contains(key)) { return true; } else if (searchSupport() && KStandardShortcut::replace().contains(key)) { return true; } else if (searchSupport() && KStandardShortcut::findNext().contains(key)) { return true; } else if (event->matches(QKeySequence::SelectAll)) { // currently missing in QTextEdit return true; } else if (event == QKeySequence::DeleteEndOfLine) { return true; } return false; } bool PlainTextEditor::handleShortcut(QKeyEvent *event) { const int key = event->key() | event->modifiers(); if (KStandardShortcut::copy().contains(key)) { copy(); return true; } else if (KStandardShortcut::paste().contains(key)) { paste(); return true; } else if (KStandardShortcut::cut().contains(key)) { cut(); return true; } else if (KStandardShortcut::undo().contains(key)) { if (!isReadOnly()) { undo(); } return true; } else if (KStandardShortcut::redo().contains(key)) { if (!isReadOnly()) { redo(); } return true; } else if (KStandardShortcut::deleteWordBack().contains(key)) { if (!isReadOnly()) { deleteWordBack(); } return true; } else if (KStandardShortcut::deleteWordForward().contains(key)) { if (!isReadOnly()) { deleteWordForward(); } return true; } else if (KStandardShortcut::backwardWord().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::PreviousWord); setTextCursor(cursor); return true; } else if (KStandardShortcut::forwardWord().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::NextWord); setTextCursor(cursor); return true; } else if (KStandardShortcut::next().contains(key)) { QTextCursor cursor = textCursor(); bool moved = false; qreal lastY = cursorRect(cursor).bottom(); qreal distance = 0; do { qreal y = cursorRect(cursor).bottom(); distance += qAbs(y - lastY); lastY = y; moved = cursor.movePosition(QTextCursor::Down); } while (moved && distance < viewport()->height()); if (moved) { cursor.movePosition(QTextCursor::Up); verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd); } setTextCursor(cursor); return true; } else if (KStandardShortcut::prior().contains(key)) { QTextCursor cursor = textCursor(); bool moved = false; qreal lastY = cursorRect(cursor).bottom(); qreal distance = 0; do { qreal y = cursorRect(cursor).bottom(); distance += qAbs(y - lastY); lastY = y; moved = cursor.movePosition(QTextCursor::Up); } while (moved && distance < viewport()->height()); if (moved) { cursor.movePosition(QTextCursor::Down); verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub); } setTextCursor(cursor); return true; } else if (KStandardShortcut::begin().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::Start); setTextCursor(cursor); return true; } else if (KStandardShortcut::end().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::End); setTextCursor(cursor); return true; } else if (KStandardShortcut::beginningOfLine().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::StartOfLine); setTextCursor(cursor); return true; } else if (KStandardShortcut::endOfLine().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::EndOfLine); setTextCursor(cursor); return true; } else if (searchSupport() && KStandardShortcut::find().contains(key)) { Q_EMIT findText(); return true; } else if (searchSupport() && KStandardShortcut::replace().contains(key)) { if (!isReadOnly()) { Q_EMIT replaceText(); } return true; } else if (KStandardShortcut::pasteSelection().contains(key)) { QString text = QApplication::clipboard()->text(QClipboard::Selection); if (!text.isEmpty()) { insertPlainText(text); // TODO: check if this is html? (MiB) } return true; } else if (event == QKeySequence::DeleteEndOfLine) { deleteEndOfLine(); return true; } return false; } void PlainTextEditor::deleteEndOfLine() { QTextCursor cursor = textCursor(); QTextBlock block = cursor.block(); if (cursor.position() == block.position() + block.length() - 2) { cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); } else { cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); } cursor.removeSelectedText(); setTextCursor(cursor); } void PlainTextEditor::moveLineUpDown(bool moveUp) { QTextCursor cursor = textCursor(); QTextCursor move = cursor; move.beginEditBlock(); bool hasSelection = cursor.hasSelection(); if (hasSelection) { move.setPosition(cursor.selectionStart()); move.movePosition(QTextCursor::StartOfBlock); move.setPosition(cursor.selectionEnd(), QTextCursor::KeepAnchor); move.movePosition(move.atBlockStart() ? QTextCursor::Left : QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); } else { move.movePosition(QTextCursor::StartOfBlock); move.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); } QString text = move.selectedText(); move.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); move.removeSelectedText(); if (moveUp) { move.movePosition(QTextCursor::PreviousBlock); move.insertBlock(); move.movePosition(QTextCursor::Left); } else { move.movePosition(QTextCursor::EndOfBlock); if (move.atBlockStart()) { // empty block move.movePosition(QTextCursor::NextBlock); move.insertBlock(); move.movePosition(QTextCursor::Left); } else { move.insertBlock(); } } int start = move.position(); move.clearSelection(); move.insertText(text); int end = move.position(); if (hasSelection) { move.setPosition(end); move.setPosition(start, QTextCursor::KeepAnchor); } else { move.setPosition(start); } move.endEditBlock(); setTextCursor(move); } void PlainTextEditor::wheelEvent(QWheelEvent *event) { if (QApplication::keyboardModifiers() & Qt::ControlModifier) { if (event->delta() > 0) { zoomIn(); } else if (event->delta() < 0) { zoomOut(); } event->accept(); return; } QPlainTextEdit::wheelEvent(event); } void PlainTextEditor::keyPressEvent(QKeyEvent *event) { const bool isControlClicked = event->modifiers() & Qt::ControlModifier; const bool isShiftClicked = event->modifiers() & Qt::ShiftModifier; if (handleShortcut(event)) { event->accept(); } else if (event->key() == Qt::Key_Up && isControlClicked && isShiftClicked) { moveLineUpDown(true); event->accept(); } else if (event->key() == Qt::Key_Down && isControlClicked && isShiftClicked) { moveLineUpDown(false); event->accept(); } else { QPlainTextEdit::keyPressEvent(event); } } bool PlainTextEditor::activateLanguageMenu() const { return d->activateLanguageMenu; } void PlainTextEditor::setActivateLanguageMenu(bool activate) { d->activateLanguageMenu = activate; } Sonnet::Highlighter *PlainTextEditor::highlighter() const { if (d->richTextDecorator) { return d->richTextDecorator->highlighter(); } else { return nullptr; } } Sonnet::SpellCheckDecorator *PlainTextEditor::createSpellCheckDecorator() { return new Sonnet::SpellCheckDecorator(this); } void PlainTextEditor::addIgnoreWordsToHighLighter() { if (d->ignoreSpellCheckingWords.isEmpty()) { return; } if (d->richTextDecorator) { Sonnet::Highlighter *_highlighter = d->richTextDecorator->highlighter(); for (const QString &word : qAsConst(d->ignoreSpellCheckingWords)) { _highlighter->ignoreWord(word); } } } void PlainTextEditor::setHighlighter(Sonnet::Highlighter *_highLighter) { Sonnet::SpellCheckDecorator *decorator = createSpellCheckDecorator(); delete decorator->highlighter(); decorator->setHighlighter(_highLighter); //KTextEdit used to take ownership of the highlighter, Sonnet::SpellCheckDecorator does not. //so we reparent the highlighter so it will be deleted when the decorator is destroyed _highLighter->setParent(decorator); d->richTextDecorator = decorator; addIgnoreWordsToHighLighter(); } void PlainTextEditor::focusInEvent(QFocusEvent *event) { if (checkSpellingEnabled() && !isReadOnly() && !d->richTextDecorator && spellCheckingSupport()) { createHighlighter(); } QPlainTextEdit::focusInEvent(event); } bool PlainTextEditor::checkSpellingEnabled() const { return d->checkSpellingEnabled; } void PlainTextEditor::setCheckSpellingEnabled(bool check) { if (check == d->checkSpellingEnabled) { return; } d->checkSpellingEnabled = check; Q_EMIT checkSpellingChanged(check); // From the above statement we know that if we're turning checking // on that we need to create a new highlighter and if we're turning it // off we should remove the old one. if (check) { if (hasFocus()) { if (!d->richTextDecorator) { createHighlighter(); } if (!d->spellCheckingLanguage.isEmpty()) { setSpellCheckingLanguage(spellCheckingLanguage()); } } } else { clearDecorator(); } updateHighLighter(); } void PlainTextEditor::updateHighLighter() { } void PlainTextEditor::clearDecorator() { delete d->richTextDecorator; d->richTextDecorator = nullptr; } void PlainTextEditor::createHighlighter() { Sonnet::Highlighter *highlighter = new Sonnet::Highlighter(this); highlighter->setCurrentLanguage(spellCheckingLanguage()); setHighlighter(highlighter); } void PlainTextEditor::setSpellCheckingConfigFileName(const QString &_fileName) { d->spellCheckingConfigFileName = _fileName; KSharedConfig::Ptr config = KSharedConfig::openConfig(d->spellCheckingConfigFileName); if (config->hasGroup("Spelling")) { KConfigGroup group(config, "Spelling"); d->checkSpellingEnabled = group.readEntry("checkerEnabledByDefault", false); d->spellCheckingLanguage = group.readEntry("Language", QString()); } setCheckSpellingEnabled(checkSpellingEnabled()); if (!d->spellCheckingLanguage.isEmpty() && highlighter()) { highlighter()->setCurrentLanguage(d->spellCheckingLanguage); highlighter()->rehighlight(); } } QString PlainTextEditor::spellCheckingConfigFileName() const { return d->spellCheckingConfigFileName; } void PlainTextEditor::slotLanguageSelected() { QAction *languageAction = static_cast(QObject::sender()); setSpellCheckingLanguage(languageAction->data().toString()); } const QString &PlainTextEditor::spellCheckingLanguage() const { return d->spellCheckingLanguage; } void PlainTextEditor::setSpellCheckingLanguage(const QString &_language) { if (highlighter()) { highlighter()->setCurrentLanguage(_language); highlighter()->rehighlight(); } if (_language != d->spellCheckingLanguage) { d->spellCheckingLanguage = _language; KSharedConfig::Ptr config = KSharedConfig::openConfig(d->spellCheckingConfigFileName); KConfigGroup group(config, "Spelling"); group.writeEntry("Language", d->spellCheckingLanguage); setCheckSpellingEnabled(checkSpellingEnabled()); Q_EMIT languageChanged(_language); } } void PlainTextEditor::slotToggleAutoSpellCheck() { setCheckSpellingEnabled(!checkSpellingEnabled()); KSharedConfig::Ptr config = KSharedConfig::openConfig(d->spellCheckingConfigFileName); KConfigGroup group(config, "Spelling"); group.writeEntry("checkerEnabledByDefault", d->checkSpellingEnabled); } void PlainTextEditor::slotZoomReset() { QFont f = font(); if (d->mInitialFontSize != f.pointSize()) { f.setPointSize(d->mInitialFontSize); setFont(f); } } diff --git a/src/texteditor/plaintexteditor/plaintexteditorwidget.cpp b/src/texteditor/plaintexteditor/plaintexteditorwidget.cpp index a5a7e56..7c09d32 100644 --- a/src/texteditor/plaintexteditor/plaintexteditorwidget.cpp +++ b/src/texteditor/plaintexteditor/plaintexteditorwidget.cpp @@ -1,160 +1,160 @@ /* Copyright (C) 2013-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "plaintexteditorwidget.h" #include "plaintexteditor.h" #include "plaintexteditfindbar.h" #include "texttospeech/texttospeechwidget.h" #include "slidecontainer.h" #include #include using namespace KPIMTextEdit; class KPIMTextEdit::PlainTextEditorWidgetPrivate { public: PlainTextEditorWidgetPrivate() { } KPIMTextEdit::PlainTextEditFindBar *mFindBar = nullptr; PlainTextEditor *mEditor = nullptr; KPIMTextEdit::TextToSpeechWidget *mTextToSpeechWidget = nullptr; KPIMTextEdit::SlideContainer *mSliderContainer = nullptr; }; PlainTextEditorWidget::PlainTextEditorWidget(PlainTextEditor *customEditor, QWidget *parent) : QWidget(parent) , d(new KPIMTextEdit::PlainTextEditorWidgetPrivate) { init(customEditor); } PlainTextEditorWidget::PlainTextEditorWidget(QWidget *parent) : QWidget(parent) , d(new KPIMTextEdit::PlainTextEditorWidgetPrivate) { init(); } PlainTextEditorWidget::~PlainTextEditorWidget() { delete d; } PlainTextEditor *PlainTextEditorWidget::editor() const { return d->mEditor; } void PlainTextEditorWidget::clear() { d->mEditor->clear(); } void PlainTextEditorWidget::setSpellCheckingConfigFileName(const QString &_fileName) { d->mEditor->setSpellCheckingConfigFileName(_fileName); } void PlainTextEditorWidget::setPlainText(const QString &text) { d->mEditor->setPlainText(text); } bool PlainTextEditorWidget::isEmpty() const { return d->mEditor->document()->isEmpty(); } QString PlainTextEditorWidget::toPlainText() const { return d->mEditor->toPlainText(); } void PlainTextEditorWidget::init(PlainTextEditor *customEditor) { QVBoxLayout *lay = new QVBoxLayout(this); - lay->setMargin(0); + lay->setContentsMargins(0, 0, 0, 0); d->mTextToSpeechWidget = new KPIMTextEdit::TextToSpeechWidget(this); lay->addWidget(d->mTextToSpeechWidget); if (customEditor) { d->mEditor = customEditor; } else { d->mEditor = new PlainTextEditor; } lay->addWidget(d->mEditor); connect(d->mEditor, &PlainTextEditor::say, d->mTextToSpeechWidget, &KPIMTextEdit::TextToSpeechWidget::say); d->mSliderContainer = new KPIMTextEdit::SlideContainer(this); d->mFindBar = new KPIMTextEdit::PlainTextEditFindBar(d->mEditor, this); d->mFindBar->setHideWhenClose(false); connect(d->mFindBar, &KPIMTextEdit::PlainTextEditFindBar::displayMessageIndicator, d->mEditor, &PlainTextEditor::slotDisplayMessageIndicator); connect(d->mFindBar, &KPIMTextEdit::PlainTextEditFindBar::hideFindBar, this, &PlainTextEditorWidget::slotHideFindBar); d->mSliderContainer->setContent(d->mFindBar); lay->addWidget(d->mSliderContainer); connect(d->mEditor, &PlainTextEditor::findText, this, &PlainTextEditorWidget::slotFind); connect(d->mEditor, &PlainTextEditor::replaceText, this, &PlainTextEditorWidget::slotReplace); } void PlainTextEditorWidget::slotHideFindBar() { d->mSliderContainer->slideOut(); d->mEditor->setFocus(); } bool PlainTextEditorWidget::isReadOnly() const { return d->mEditor->isReadOnly(); } void PlainTextEditorWidget::setReadOnly(bool readOnly) { d->mEditor->setReadOnly(readOnly); } void PlainTextEditorWidget::slotReplace() { if (d->mEditor->searchSupport()) { if (d->mEditor->textCursor().hasSelection()) { d->mFindBar->setText(d->mEditor->textCursor().selectedText()); } d->mFindBar->showReplace(); d->mSliderContainer->slideIn(); d->mFindBar->focusAndSetCursor(); } } void PlainTextEditorWidget::slotFind() { if (d->mEditor->searchSupport()) { if (d->mEditor->textCursor().hasSelection()) { d->mFindBar->setText(d->mEditor->textCursor().selectedText()); } d->mEditor->moveCursor(QTextCursor::Start); d->mFindBar->showFind(); d->mSliderContainer->slideIn(); d->mFindBar->focusAndSetCursor(); } } diff --git a/src/texteditor/richtexteditor/richtexteditor.cpp b/src/texteditor/richtexteditor/richtexteditor.cpp index 6c6c99e..cdf57a1 100644 --- a/src/texteditor/richtexteditor/richtexteditor.cpp +++ b/src/texteditor/richtexteditor/richtexteditor.cpp @@ -1,996 +1,996 @@ /* Copyright (C) 2013-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "richtexteditor.h" #include "kpimtextedit_debug.h" #include "texteditor/commonwidget/textmessageindicator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KPIMTextEdit; class Q_DECL_HIDDEN RichTextEditor::RichTextEditorPrivate { public: RichTextEditorPrivate(RichTextEditor *qq) : q(qq) , textIndicator(new KPIMTextEdit::TextMessageIndicator(q)) , webshortcutMenuManager(new KIO::KUriFilterSearchProviderActions(q)) { KConfig sonnetKConfig(QStringLiteral("sonnetrc")); KConfigGroup group(&sonnetKConfig, "Spelling"); checkSpellingEnabled = group.readEntry("checkerEnabledByDefault", false); supportFeatures |= RichTextEditor::Search; supportFeatures |= RichTextEditor::SpellChecking; supportFeatures |= RichTextEditor::TextToSpeech; supportFeatures |= RichTextEditor::AllowTab; supportFeatures |= RichTextEditor::AllowWebShortcut; } ~RichTextEditorPrivate() { delete richTextDecorator; delete speller; } QStringList ignoreSpellCheckingWords; RichTextEditor *q = nullptr; KPIMTextEdit::TextMessageIndicator *textIndicator = nullptr; QString spellCheckingConfigFileName; QString spellCheckingLanguage; QTextDocumentFragment originalDoc; Sonnet::SpellCheckDecorator *richTextDecorator = nullptr; Sonnet::Speller *speller = nullptr; KIO::KUriFilterSearchProviderActions *webshortcutMenuManager = nullptr; RichTextEditor::SupportFeatures supportFeatures; int mInitialFontSize; bool customPalette = false; bool checkSpellingEnabled = false; bool activateLanguageMenu = true; bool showAutoCorrectionButton = false; }; RichTextEditor::RichTextEditor(QWidget *parent) : QTextEdit(parent) , d(new RichTextEditorPrivate(this)) { setAcceptRichText(true); KCursor::setAutoHideCursor(this, true, false); setSpellCheckingConfigFileName(QString()); d->mInitialFontSize = font().pointSize(); } RichTextEditor::~RichTextEditor() { delete d; } void RichTextEditor::setDefaultFontSize(int val) { d->mInitialFontSize = val; slotZoomReset(); } void RichTextEditor::slotDisplayMessageIndicator(const QString &message) { d->textIndicator->display(message); } Sonnet::Highlighter *RichTextEditor::highlighter() const { if (d->richTextDecorator) { return d->richTextDecorator->highlighter(); } else { return nullptr; } } bool RichTextEditor::activateLanguageMenu() const { return d->activateLanguageMenu; } void RichTextEditor::setActivateLanguageMenu(bool activate) { d->activateLanguageMenu = activate; } void RichTextEditor::contextMenuEvent(QContextMenuEvent *event) { QMenu *popup = mousePopupMenu(event->pos()); if (popup) { popup->exec(event->globalPos()); delete popup; } } QMenu *RichTextEditor::mousePopupMenu(QPoint pos) { QMenu *popup = createStandardContextMenu(); if (popup) { const bool emptyDocument = document()->isEmpty(); if (!isReadOnly()) { QList actionList = popup->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, ClearAct, SelectAllAct, NCountActs }; QAction *separatorAction = nullptr; const int idx = actionList.indexOf(actionList[SelectAllAct]) + 1; if (idx < actionList.count()) { separatorAction = actionList.at(idx); } if (separatorAction) { QAction *clearAllAction = KStandardAction::clear(this, &RichTextEditor::slotUndoableClear, popup); if (emptyDocument) { clearAllAction->setEnabled(false); } popup->insertAction(separatorAction, clearAllAction); } } KIconTheme::assignIconsToContextMenu(isReadOnly() ? KIconTheme::ReadOnlyText : KIconTheme::TextEditor, popup->actions()); if (searchSupport()) { popup->addSeparator(); QAction *findAct = popup->addAction(KStandardGuiItem::find().icon(), KStandardGuiItem::find().text(), this, SIGNAL(findText()), Qt::Key_F + Qt::CTRL); if (emptyDocument) { findAct->setEnabled(false); } popup->addSeparator(); if (!isReadOnly()) { QAction *act = popup->addAction(i18n("Replace..."), this, SIGNAL(replaceText()), Qt::Key_R + Qt::CTRL); if (emptyDocument) { act->setEnabled(false); } popup->addSeparator(); } } else { popup->addSeparator(); } if (!isReadOnly() && spellCheckingSupport()) { if (!d->speller) { d->speller = new Sonnet::Speller(); } if (!d->speller->availableBackends().isEmpty()) { QAction *spellCheckAction = popup->addAction(QIcon::fromTheme(QStringLiteral("tools-check-spelling")), i18n("Check Spelling..."), this, &RichTextEditor::slotCheckSpelling); if (emptyDocument) { spellCheckAction->setEnabled(false); } popup->addSeparator(); QAction *autoSpellCheckAction = popup->addAction(i18n("Auto Spell Check"), this, &RichTextEditor::slotToggleAutoSpellCheck); autoSpellCheckAction->setCheckable(true); autoSpellCheckAction->setChecked(checkSpellingEnabled()); popup->addAction(autoSpellCheckAction); if (checkSpellingEnabled() && d->activateLanguageMenu) { QMenu *languagesMenu = new QMenu(i18n("Spell Checking Language"), popup); QActionGroup *languagesGroup = new QActionGroup(languagesMenu); languagesGroup->setExclusive(true); QString defaultSpellcheckingLanguage = spellCheckingLanguage(); if (defaultSpellcheckingLanguage.isEmpty()) { defaultSpellcheckingLanguage = d->speller->defaultLanguage(); } QMapIterator i(d->speller->availableDictionaries()); while (i.hasNext()) { i.next(); QAction *languageAction = languagesMenu->addAction(i.key()); languageAction->setCheckable(true); languageAction->setChecked(defaultSpellcheckingLanguage == i.value()); languageAction->setData(i.value()); languageAction->setActionGroup(languagesGroup); connect(languageAction, &QAction::triggered, this, &RichTextEditor::slotLanguageSelected); } popup->addMenu(languagesMenu); } popup->addSeparator(); } } if (allowTabSupport() && !isReadOnly()) { QAction *allowTabAction = popup->addAction(i18n("Allow Tabulations")); allowTabAction->setCheckable(true); allowTabAction->setChecked(!tabChangesFocus()); connect(allowTabAction, &QAction::triggered, this, &RichTextEditor::slotAllowTab); } if (KPIMTextEdit::TextToSpeech::self()->isReady()) { if (!emptyDocument) { QAction *speakAction = popup->addAction(i18n("Speak Text")); speakAction->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-text-to-speech"))); connect(speakAction, &QAction::triggered, this, &RichTextEditor::slotSpeakText); } } if (webShortcutSupport() && textCursor().hasSelection()) { popup->addSeparator(); const QString selectedText = textCursor().selectedText(); d->webshortcutMenuManager->setSelectedText(selectedText); d->webshortcutMenuManager->addWebShortcutsToMenu(popup); } addExtraMenuEntry(popup, pos); return popup; } return nullptr; } void RichTextEditor::slotSpeakText() { QString text; if (textCursor().hasSelection()) { text = textCursor().selectedText(); } else { text = toPlainText(); } Q_EMIT say(text); } void RichTextEditor::setWebShortcutSupport(bool b) { if (b) { d->supportFeatures |= AllowWebShortcut; } else { d->supportFeatures = (d->supportFeatures & ~AllowWebShortcut); } } bool RichTextEditor::webShortcutSupport() const { return d->supportFeatures & AllowWebShortcut; } void RichTextEditor::addIgnoreWords(const QStringList &lst) { d->ignoreSpellCheckingWords = lst; addIgnoreWordsToHighLighter(); } void RichTextEditor::forceAutoCorrection(bool selectedText) { Q_UNUSED(selectedText); //Nothing here } void RichTextEditor::setSearchSupport(bool b) { if (b) { d->supportFeatures |= Search; } else { d->supportFeatures = (d->supportFeatures & ~Search); } } bool RichTextEditor::searchSupport() const { return d->supportFeatures & Search; } void RichTextEditor::setAllowTabSupport(bool b) { if (b) { d->supportFeatures |= AllowTab; } else { d->supportFeatures = (d->supportFeatures & ~AllowTab); } } bool RichTextEditor::allowTabSupport() const { return d->supportFeatures & AllowTab; } void RichTextEditor::setShowAutoCorrectButton(bool b) { d->showAutoCorrectionButton = b; } bool RichTextEditor::showAutoCorrectButton() const { return d->showAutoCorrectionButton; } bool RichTextEditor::spellCheckingSupport() const { return d->supportFeatures & SpellChecking; } void RichTextEditor::setSpellCheckingSupport(bool check) { if (check) { d->supportFeatures |= SpellChecking; } else { d->supportFeatures = (d->supportFeatures & ~SpellChecking); } } void RichTextEditor::setTextToSpeechSupport(bool b) { if (b) { d->supportFeatures |= TextToSpeech; } else { d->supportFeatures = (d->supportFeatures & ~TextToSpeech); } } bool RichTextEditor::textToSpeechSupport() const { return d->supportFeatures & TextToSpeech; } void RichTextEditor::slotAllowTab() { setTabChangesFocus(!tabChangesFocus()); } void RichTextEditor::addExtraMenuEntry(QMenu *menu, QPoint pos) { Q_UNUSED(menu); Q_UNUSED(pos); } void RichTextEditor::slotUndoableClear() { QTextCursor cursor = textCursor(); cursor.beginEditBlock(); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.removeSelectedText(); cursor.endEditBlock(); } void RichTextEditor::setReadOnly(bool readOnly) { if (!readOnly && hasFocus() && checkSpellingEnabled() && !d->richTextDecorator) { createHighlighter(); } if (readOnly == isReadOnly()) { return; } if (readOnly) { clearDecorator(); d->customPalette = testAttribute(Qt::WA_SetPalette); QPalette p = palette(); - QColor color = p.color(QPalette::Disabled, QPalette::Background); + QColor color = p.color(QPalette::Disabled, QPalette::Window); p.setColor(QPalette::Base, color); - p.setColor(QPalette::Background, color); + p.setColor(QPalette::Window, color); setPalette(p); } else { if (d->customPalette && testAttribute(Qt::WA_SetPalette)) { QPalette p = palette(); QColor color = p.color(QPalette::Normal, QPalette::Base); p.setColor(QPalette::Base, color); - p.setColor(QPalette::Background, color); + p.setColor(QPalette::Window, color); setPalette(p); } else { setPalette(QPalette()); } } QTextEdit::setReadOnly(readOnly); } void RichTextEditor::checkSpelling(bool force) { if (document()->isEmpty()) { slotDisplayMessageIndicator(i18n("Nothing to spell check.")); if (force) { Q_EMIT spellCheckingFinished(); } return; } Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker; if (backgroundSpellCheck->speller().availableBackends().isEmpty()) { if (force) { if (KMessageBox::Yes == KMessageBox::questionYesNo(this, i18n("No backend available for spell checking. Do you want to send the email anyways?"))) { Q_EMIT spellCheckingFinished(); } } else { slotDisplayMessageIndicator(i18n("No backend available for spell checking.")); } delete backgroundSpellCheck; return; } if (!d->spellCheckingLanguage.isEmpty()) { backgroundSpellCheck->changeLanguage(d->spellCheckingLanguage); } if (!d->ignoreSpellCheckingWords.isEmpty()) { for (const QString &word : qAsConst(d->ignoreSpellCheckingWords)) { backgroundSpellCheck->speller().addToSession(word); } } Sonnet::Dialog *spellDialog = new Sonnet::Dialog(backgroundSpellCheck, force ? this : nullptr); QDialogButtonBox *buttonBox = spellDialog->findChild(); if (buttonBox) { QPushButton *skipButton = new QPushButton(i18n("Skip")); buttonBox->addButton(skipButton, QDialogButtonBox::ActionRole); connect(skipButton, &QPushButton::clicked, spellDialog, &Sonnet::Dialog::close); if (force) { connect(skipButton, &QPushButton::clicked, this, &RichTextEditor::spellCheckingFinished); } } else { qCWarning(KPIMTEXTEDIT_LOG) << " Impossible to find qdialogbuttonbox"; } backgroundSpellCheck->setParent(spellDialog); spellDialog->setAttribute(Qt::WA_DeleteOnClose, true); spellDialog->activeAutoCorrect(d->showAutoCorrectionButton); connect(spellDialog, &Sonnet::Dialog::replace, this, &RichTextEditor::slotSpellCheckerCorrected); connect(spellDialog, &Sonnet::Dialog::misspelling, this, &RichTextEditor::slotSpellCheckerMisspelling); connect(spellDialog, &Sonnet::Dialog::autoCorrect, this, &RichTextEditor::slotSpellCheckerAutoCorrect); connect(spellDialog, QOverload::of(&Sonnet::Dialog::done), this, &RichTextEditor::slotSpellCheckerFinished); connect(spellDialog, &Sonnet::Dialog::cancel, this, &RichTextEditor::slotSpellCheckerCanceled); connect(spellDialog, &Sonnet::Dialog::spellCheckStatus, this, &RichTextEditor::spellCheckStatus); connect(spellDialog, &Sonnet::Dialog::languageChanged, this, &RichTextEditor::languageChanged); if (force) { connect(spellDialog, SIGNAL(done(QString)), this, SIGNAL(spellCheckingFinished())); //connect(spellDialog, &Sonnet::Dialog::done, this, &RichTextEditor::spellCheckingFinished); connect(spellDialog, &Sonnet::Dialog::cancel, this, &RichTextEditor::spellCheckingCanceled); } d->originalDoc = QTextDocumentFragment(document()); spellDialog->setBuffer(toPlainText()); spellDialog->show(); } void RichTextEditor::slotCheckSpelling() { checkSpelling(false); } void RichTextEditor::forceSpellChecking() { checkSpelling(true); } void RichTextEditor::slotSpellCheckerCanceled() { QTextDocument *doc = document(); doc->clear(); QTextCursor cursor(doc); cursor.insertFragment(d->originalDoc); slotSpellCheckerFinished(); } void RichTextEditor::slotSpellCheckerAutoCorrect(const QString ¤tWord, const QString &autoCorrectWord) { Q_EMIT spellCheckerAutoCorrect(currentWord, autoCorrectWord); } void RichTextEditor::slotSpellCheckerMisspelling(const QString &text, int pos) { highlightWord(text.length(), pos); } void RichTextEditor::slotSpellCheckerCorrected(const QString &oldWord, int pos, const QString &newWord) { if (oldWord != newWord) { QTextCursor cursor(document()); cursor.setPosition(pos); cursor.setPosition(pos + oldWord.length(), QTextCursor::KeepAnchor); cursor.insertText(newWord); } } void RichTextEditor::slotSpellCheckerFinished() { QTextCursor cursor(document()); cursor.clearSelection(); setTextCursor(cursor); if (highlighter()) { highlighter()->rehighlight(); } } void RichTextEditor::highlightWord(int length, int pos) { QTextCursor cursor(document()); cursor.setPosition(pos); cursor.setPosition(pos + length, QTextCursor::KeepAnchor); setTextCursor(cursor); ensureCursorVisible(); } void RichTextEditor::createHighlighter() { Sonnet::Highlighter *highlighter = new Sonnet::Highlighter(this); highlighter->setCurrentLanguage(spellCheckingLanguage()); setHighlighter(highlighter); } Sonnet::SpellCheckDecorator *RichTextEditor::createSpellCheckDecorator() { return new Sonnet::SpellCheckDecorator(this); } void RichTextEditor::addIgnoreWordsToHighLighter() { if (d->ignoreSpellCheckingWords.isEmpty()) { return; } if (d->richTextDecorator) { Sonnet::Highlighter *_highlighter = d->richTextDecorator->highlighter(); for (const QString &word : qAsConst(d->ignoreSpellCheckingWords)) { _highlighter->ignoreWord(word); } } } void RichTextEditor::setHighlighter(Sonnet::Highlighter *_highLighter) { Sonnet::SpellCheckDecorator *decorator = createSpellCheckDecorator(); delete decorator->highlighter(); decorator->setHighlighter(_highLighter); //KTextEdit used to take ownership of the highlighter, Sonnet::SpellCheckDecorator does not. //so we reparent the highlighter so it will be deleted when the decorator is destroyed _highLighter->setParent(decorator); d->richTextDecorator = decorator; addIgnoreWordsToHighLighter(); } void RichTextEditor::focusInEvent(QFocusEvent *event) { if (d->checkSpellingEnabled && !isReadOnly() && !d->richTextDecorator && spellCheckingSupport()) { createHighlighter(); } QTextEdit::focusInEvent(event); } void RichTextEditor::setSpellCheckingConfigFileName(const QString &_fileName) { d->spellCheckingConfigFileName = _fileName; KSharedConfig::Ptr config = KSharedConfig::openConfig(d->spellCheckingConfigFileName); if (config->hasGroup("Spelling")) { KConfigGroup group(config, "Spelling"); d->checkSpellingEnabled = group.readEntry("checkerEnabledByDefault", false); d->spellCheckingLanguage = group.readEntry("Language", QString()); } setCheckSpellingEnabled(checkSpellingEnabled()); if (!d->spellCheckingLanguage.isEmpty() && highlighter()) { highlighter()->setCurrentLanguage(d->spellCheckingLanguage); highlighter()->rehighlight(); } } QString RichTextEditor::spellCheckingConfigFileName() const { return d->spellCheckingConfigFileName; } bool RichTextEditor::checkSpellingEnabled() const { return d->checkSpellingEnabled; } void RichTextEditor::setCheckSpellingEnabled(bool check) { if (check == d->checkSpellingEnabled) { return; } d->checkSpellingEnabled = check; Q_EMIT checkSpellingChanged(check); // From the above statement we know that if we're turning checking // on that we need to create a new highlighter and if we're turning it // off we should remove the old one. if (check) { if (hasFocus()) { if (!d->richTextDecorator) { createHighlighter(); } if (!d->spellCheckingLanguage.isEmpty()) { setSpellCheckingLanguage(spellCheckingLanguage()); } } } else { clearDecorator(); } updateHighLighter(); } void RichTextEditor::updateHighLighter() { } void RichTextEditor::clearDecorator() { delete d->richTextDecorator; d->richTextDecorator = nullptr; } const QString &RichTextEditor::spellCheckingLanguage() const { return d->spellCheckingLanguage; } void RichTextEditor::setSpellCheckingLanguage(const QString &_language) { if (highlighter()) { highlighter()->setCurrentLanguage(_language); } if (_language != d->spellCheckingLanguage) { d->spellCheckingLanguage = _language; KSharedConfig::Ptr config = KSharedConfig::openConfig(d->spellCheckingConfigFileName); KConfigGroup group(config, "Spelling"); group.writeEntry("Language", d->spellCheckingLanguage); Q_EMIT languageChanged(_language); } } void RichTextEditor::slotToggleAutoSpellCheck() { setCheckSpellingEnabled(!checkSpellingEnabled()); KSharedConfig::Ptr config = KSharedConfig::openConfig(d->spellCheckingConfigFileName); KConfigGroup group(config, "Spelling"); group.writeEntry("checkerEnabledByDefault", d->checkSpellingEnabled); } void RichTextEditor::slotLanguageSelected() { QAction *languageAction = static_cast(QObject::sender()); setSpellCheckingLanguage(languageAction->data().toString()); } static void deleteWord(QTextCursor cursor, QTextCursor::MoveOperation op) { cursor.clearSelection(); cursor.movePosition(op, QTextCursor::KeepAnchor); cursor.removeSelectedText(); } void RichTextEditor::deleteWordBack() { deleteWord(textCursor(), QTextCursor::PreviousWord); } void RichTextEditor::deleteWordForward() { deleteWord(textCursor(), QTextCursor::WordRight); } bool RichTextEditor::event(QEvent *ev) { if (ev->type() == QEvent::ShortcutOverride) { QKeyEvent *e = static_cast(ev); if (overrideShortcut(e)) { e->accept(); return true; } } return QTextEdit::event(ev); } void RichTextEditor::wheelEvent(QWheelEvent *event) { if (QApplication::keyboardModifiers() & Qt::ControlModifier) { if (event->delta() > 0) { zoomIn(); } else if (event->delta() < 0) { zoomOut(); } event->accept(); return; } QTextEdit::wheelEvent(event); } bool RichTextEditor::handleShortcut(QKeyEvent *event) { const int key = event->key() | event->modifiers(); if (KStandardShortcut::copy().contains(key)) { copy(); return true; } else if (KStandardShortcut::paste().contains(key)) { paste(); return true; } else if (KStandardShortcut::cut().contains(key)) { cut(); return true; } else if (KStandardShortcut::undo().contains(key)) { if (!isReadOnly()) { undo(); } return true; } else if (KStandardShortcut::redo().contains(key)) { if (!isReadOnly()) { redo(); } return true; } else if (KStandardShortcut::deleteWordBack().contains(key)) { if (!isReadOnly()) { deleteWordBack(); } return true; } else if (KStandardShortcut::deleteWordForward().contains(key)) { if (!isReadOnly()) { deleteWordForward(); } return true; } else if (KStandardShortcut::backwardWord().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::PreviousWord); setTextCursor(cursor); return true; } else if (KStandardShortcut::forwardWord().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::NextWord); setTextCursor(cursor); return true; } else if (KStandardShortcut::next().contains(key)) { QTextCursor cursor = textCursor(); bool moved = false; qreal lastY = cursorRect(cursor).bottom(); qreal distance = 0; do { qreal y = cursorRect(cursor).bottom(); distance += qAbs(y - lastY); lastY = y; moved = cursor.movePosition(QTextCursor::Down); } while (moved && distance < viewport()->height()); if (moved) { cursor.movePosition(QTextCursor::Up); verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd); } setTextCursor(cursor); return true; } else if (KStandardShortcut::prior().contains(key)) { QTextCursor cursor = textCursor(); bool moved = false; qreal lastY = cursorRect(cursor).bottom(); qreal distance = 0; do { qreal y = cursorRect(cursor).bottom(); distance += qAbs(y - lastY); lastY = y; moved = cursor.movePosition(QTextCursor::Up); } while (moved && distance < viewport()->height()); if (moved) { cursor.movePosition(QTextCursor::Down); verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub); } setTextCursor(cursor); return true; } else if (KStandardShortcut::begin().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::Start); setTextCursor(cursor); return true; } else if (KStandardShortcut::end().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::End); setTextCursor(cursor); return true; } else if (KStandardShortcut::beginningOfLine().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::StartOfLine); setTextCursor(cursor); return true; } else if (KStandardShortcut::endOfLine().contains(key)) { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::EndOfLine); setTextCursor(cursor); return true; } else if (searchSupport() && KStandardShortcut::find().contains(key)) { Q_EMIT findText(); return true; } else if (searchSupport() && KStandardShortcut::replace().contains(key)) { if (!isReadOnly()) { Q_EMIT replaceText(); } return true; } else if (KStandardShortcut::pasteSelection().contains(key)) { QString text = QApplication::clipboard()->text(QClipboard::Selection); if (!text.isEmpty()) { insertPlainText(text); // TODO: check if this is html? (MiB) } return true; } else if (event == QKeySequence::DeleteEndOfLine) { QTextCursor cursor = textCursor(); QTextBlock block = cursor.block(); if (cursor.position() == block.position() + block.length() - 2) { cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); } else { cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); } cursor.removeSelectedText(); setTextCursor(cursor); return true; } return false; } bool RichTextEditor::overrideShortcut(QKeyEvent *event) { const int key = event->key() | event->modifiers(); if (KStandardShortcut::copy().contains(key)) { return true; } else if (KStandardShortcut::paste().contains(key)) { return true; } else if (KStandardShortcut::cut().contains(key)) { return true; } else if (KStandardShortcut::undo().contains(key)) { return true; } else if (KStandardShortcut::redo().contains(key)) { return true; } else if (KStandardShortcut::deleteWordBack().contains(key)) { return true; } else if (KStandardShortcut::deleteWordForward().contains(key)) { return true; } else if (KStandardShortcut::backwardWord().contains(key)) { return true; } else if (KStandardShortcut::forwardWord().contains(key)) { return true; } else if (KStandardShortcut::next().contains(key)) { return true; } else if (KStandardShortcut::prior().contains(key)) { return true; } else if (KStandardShortcut::begin().contains(key)) { return true; } else if (KStandardShortcut::end().contains(key)) { return true; } else if (KStandardShortcut::beginningOfLine().contains(key)) { return true; } else if (KStandardShortcut::endOfLine().contains(key)) { return true; } else if (KStandardShortcut::pasteSelection().contains(key)) { return true; } else if (searchSupport() && KStandardShortcut::find().contains(key)) { return true; } else if (searchSupport() && KStandardShortcut::findNext().contains(key)) { return true; } else if (searchSupport() && KStandardShortcut::replace().contains(key)) { return true; } else if (event->matches(QKeySequence::SelectAll)) { // currently missing in QTextEdit return true; } else if (event == QKeySequence::DeleteEndOfLine) { return true; } return false; } void RichTextEditor::keyPressEvent(QKeyEvent *event) { const bool isControlClicked = event->modifiers() & Qt::ControlModifier; const bool isShiftClicked = event->modifiers() & Qt::ShiftModifier; if (handleShortcut(event)) { event->accept(); } else if (event->key() == Qt::Key_Up && isControlClicked && isShiftClicked) { moveLineUpDown(true); event->accept(); } else if (event->key() == Qt::Key_Down && isControlClicked && isShiftClicked) { moveLineUpDown(false); event->accept(); } else { QTextEdit::keyPressEvent(event); } } int RichTextEditor::zoomFactor() const { int pourcentage = 100; QFont f = font(); if (d->mInitialFontSize != f.pointSize()) { pourcentage = (f.pointSize() * 100) / d->mInitialFontSize; } return pourcentage; } void RichTextEditor::slotZoomReset() { QFont f = font(); if (d->mInitialFontSize != f.pointSize()) { f.setPointSize(d->mInitialFontSize); setFont(f); } } void RichTextEditor::moveLineUpDown(bool moveUp) { QTextCursor cursor = textCursor(); QTextCursor move = cursor; move.beginEditBlock(); bool hasSelection = cursor.hasSelection(); if (hasSelection) { move.setPosition(cursor.selectionStart()); move.movePosition(QTextCursor::StartOfBlock); move.setPosition(cursor.selectionEnd(), QTextCursor::KeepAnchor); move.movePosition(move.atBlockStart() ? QTextCursor::Left : QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); } else { move.movePosition(QTextCursor::StartOfBlock); move.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); } QString text = move.selectedText(); move.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); move.removeSelectedText(); if (moveUp) { move.movePosition(QTextCursor::PreviousBlock); move.insertBlock(); move.movePosition(QTextCursor::Left); } else { move.movePosition(QTextCursor::EndOfBlock); if (move.atBlockStart()) { // empty block move.movePosition(QTextCursor::NextBlock); move.insertBlock(); move.movePosition(QTextCursor::Left); } else { move.insertBlock(); } } int start = move.position(); move.clearSelection(); move.insertText(text); int end = move.position(); if (hasSelection) { move.setPosition(end); move.setPosition(start, QTextCursor::KeepAnchor); } else { move.setPosition(start); } move.endEditBlock(); setTextCursor(move); } diff --git a/src/texteditor/richtexteditor/richtexteditorwidget.cpp b/src/texteditor/richtexteditor/richtexteditorwidget.cpp index d659cd2..a11e4ab 100644 --- a/src/texteditor/richtexteditor/richtexteditorwidget.cpp +++ b/src/texteditor/richtexteditor/richtexteditorwidget.cpp @@ -1,193 +1,193 @@ /* Copyright (C) 2013-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "richtexteditorwidget.h" #include "richtexteditor.h" #include "richtexteditfindbar.h" #include #include #include #include "slidecontainer.h" using namespace KPIMTextEdit; class KPIMTextEdit::RichTextEditorWidgetPrivate { public: RichTextEditorWidgetPrivate() { } KPIMTextEdit::RichTextEditFindBar *mFindBar = nullptr; RichTextEditor *mEditor = nullptr; KPIMTextEdit::TextToSpeechWidget *mTextToSpeechWidget = nullptr; KPIMTextEdit::SlideContainer *mSliderContainer = nullptr; }; RichTextEditorWidget::RichTextEditorWidget(RichTextEditor *customEditor, QWidget *parent) : QWidget(parent) , d(new KPIMTextEdit::RichTextEditorWidgetPrivate) { init(customEditor); } RichTextEditorWidget::RichTextEditorWidget(QWidget *parent) : QWidget(parent) , d(new KPIMTextEdit::RichTextEditorWidgetPrivate) { init(); } RichTextEditorWidget::~RichTextEditorWidget() { delete d; } void RichTextEditorWidget::clear() { d->mEditor->clear(); } RichTextEditor *RichTextEditorWidget::editor() const { return d->mEditor; } void RichTextEditorWidget::setAcceptRichText(bool b) { d->mEditor->setAcceptRichText(b); } bool RichTextEditorWidget::acceptRichText() const { return d->mEditor->acceptRichText(); } void RichTextEditorWidget::setSpellCheckingConfigFileName(const QString &_fileName) { d->mEditor->setSpellCheckingConfigFileName(_fileName); } void RichTextEditorWidget::setHtml(const QString &html) { d->mEditor->setHtml(html); } QString RichTextEditorWidget::toHtml() const { return d->mEditor->toHtml(); } void RichTextEditorWidget::setPlainText(const QString &text) { d->mEditor->setPlainText(text); } bool RichTextEditorWidget::isEmpty() const { return d->mEditor->document()->isEmpty(); } QString RichTextEditorWidget::toPlainText() const { return d->mEditor->toPlainText(); } void RichTextEditorWidget::init(RichTextEditor *customEditor) { QVBoxLayout *lay = new QVBoxLayout(this); - lay->setMargin(0); + lay->setContentsMargins(0, 0, 0, 0); d->mTextToSpeechWidget = new KPIMTextEdit::TextToSpeechWidget(this); lay->addWidget(d->mTextToSpeechWidget); if (customEditor) { d->mEditor = customEditor; } else { d->mEditor = new RichTextEditor; } connect(d->mEditor, &RichTextEditor::say, d->mTextToSpeechWidget, &KPIMTextEdit::TextToSpeechWidget::say); lay->addWidget(d->mEditor); d->mSliderContainer = new KPIMTextEdit::SlideContainer(this); d->mFindBar = new KPIMTextEdit::RichTextEditFindBar(d->mEditor, this); d->mFindBar->setHideWhenClose(false); connect(d->mFindBar, &KPIMTextEdit::RichTextEditFindBar::displayMessageIndicator, d->mEditor, &RichTextEditor::slotDisplayMessageIndicator); connect(d->mFindBar, &KPIMTextEdit::RichTextEditFindBar::hideFindBar, this, &RichTextEditorWidget::slotHideFindBar); d->mSliderContainer->setContent(d->mFindBar); lay->addWidget(d->mSliderContainer); connect(d->mEditor, &RichTextEditor::findText, this, &RichTextEditorWidget::slotFind); connect(d->mEditor, &RichTextEditor::replaceText, this, &RichTextEditorWidget::slotReplace); } void RichTextEditorWidget::slotHideFindBar() { d->mSliderContainer->slideOut(); d->mEditor->setFocus(); } bool RichTextEditorWidget::isReadOnly() const { return d->mEditor->isReadOnly(); } void RichTextEditorWidget::setReadOnly(bool readOnly) { d->mEditor->setReadOnly(readOnly); } void RichTextEditorWidget::slotReplace() { if (d->mEditor->searchSupport()) { if (d->mEditor->textCursor().hasSelection()) { d->mFindBar->setText(d->mEditor->textCursor().selectedText()); } d->mFindBar->showReplace(); d->mSliderContainer->slideIn(); d->mFindBar->focusAndSetCursor(); } } void RichTextEditorWidget::slotFindNext() { if (d->mEditor->searchSupport()) { if (d->mFindBar->isVisible()) { d->mFindBar->findNext(); } else { slotFind(); } } } void RichTextEditorWidget::slotFind() { if (d->mEditor->searchSupport()) { if (d->mEditor->textCursor().hasSelection()) { d->mFindBar->setText(d->mEditor->textCursor().selectedText()); } d->mEditor->moveCursor(QTextCursor::Start); d->mFindBar->showFind(); d->mSliderContainer->slideIn(); d->mFindBar->focusAndSetCursor(); } }