File indexing completed on 2024-04-21 03:58:28

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2008 Stephen Kelly <steveire@gmail.com>
0004     SPDX-FileCopyrightText: 2008 Thomas McGuire <thomas.mcguire@gmx.net>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #include "krichtextwidget.h"
0010 
0011 #include "krichtextedit_p.h"
0012 
0013 // KDE includes
0014 #include <KColorScheme>
0015 #include <KFontAction>
0016 #include <KFontSizeAction>
0017 #include <KLocalizedString>
0018 #include <ktoggleaction.h>
0019 
0020 // Qt includes
0021 #include <QAction>
0022 #include <QActionGroup>
0023 #include <QColorDialog>
0024 #include <QTextList>
0025 
0026 #include "klinkdialog_p.h"
0027 
0028 // TODO: Add i18n context
0029 
0030 /**
0031   Private class that helps to provide binary compatibility between releases.
0032   @internal
0033 */
0034 //@cond PRIVATE
0035 class KRichTextWidgetPrivate : public KRichTextEditPrivate
0036 {
0037     Q_DECLARE_PUBLIC(KRichTextWidget)
0038 
0039 public:
0040     KRichTextWidgetPrivate(KRichTextWidget *qq)
0041         : KRichTextEditPrivate(qq)
0042     {
0043     }
0044 
0045     QList<QAction *> richTextActionList;
0046     QTextCharFormat painterFormat;
0047 
0048     KRichTextWidget::RichTextSupport richTextSupport;
0049 
0050     bool painterActive = false;
0051 
0052     bool richTextEnabled = false;
0053     KToggleAction *enableRichText = nullptr;
0054 
0055     QAction *action_text_foreground_color = nullptr;
0056     QAction *action_text_background_color = nullptr;
0057 
0058     KToggleAction *action_text_bold = nullptr;
0059     KToggleAction *action_text_italic = nullptr;
0060     KToggleAction *action_text_underline = nullptr;
0061     KToggleAction *action_text_strikeout = nullptr;
0062 
0063     KFontAction *action_font_family = nullptr;
0064     KFontSizeAction *action_font_size = nullptr;
0065 
0066     KSelectAction *action_list_style = nullptr;
0067     QAction *action_list_indent = nullptr;
0068     QAction *action_list_dedent = nullptr;
0069 
0070     QAction *action_manage_link = nullptr;
0071     QAction *action_insert_horizontal_rule = nullptr;
0072     QAction *action_format_painter = nullptr;
0073     QAction *action_to_plain_text = nullptr;
0074 
0075     KToggleAction *action_align_left = nullptr;
0076     KToggleAction *action_align_right = nullptr;
0077     KToggleAction *action_align_center = nullptr;
0078     KToggleAction *action_align_justify = nullptr;
0079 
0080     KToggleAction *action_direction_ltr = nullptr;
0081     KToggleAction *action_direction_rtl = nullptr;
0082 
0083     KToggleAction *action_text_superscript = nullptr;
0084     KToggleAction *action_text_subscript = nullptr;
0085 
0086     KSelectAction *action_heading_level = nullptr;
0087 
0088     //
0089     // Normal functions
0090     //
0091     void init();
0092 
0093     //
0094     // Slots
0095     //
0096 
0097     /**
0098      * @brief Opens a dialog to allow the user to select a foreground color.
0099      */
0100     void _k_setTextForegroundColor();
0101 
0102     /**
0103      * @brief Opens a dialog to allow the user to select a background color.
0104      */
0105     void _k_setTextBackgroundColor();
0106 
0107     /**
0108      * Opens a dialog which lets the user turn the currently selected text into
0109      * a link.
0110      * If no text is selected, the word under the cursor will be taken.
0111      * If the cursor is already over a link, the user can edit that link.
0112      *
0113      */
0114     void _k_manageLink();
0115 
0116     /**
0117      * Activates a format painter to allow the user to copy font/text formatting
0118      * to different parts of the document.
0119      *
0120      */
0121     void _k_formatPainter(bool active);
0122 
0123     /**
0124      * @brief Update actions relating to text format (bold, size etc.).
0125      */
0126     void updateCharFormatActions(const QTextCharFormat &format);
0127 
0128     /**
0129      * Update actions not covered by text formatting, such as alignment,
0130      * list style and level.
0131      */
0132     void updateMiscActions();
0133 
0134     /**
0135      * Change the style of the current list or create a new list with the style given by @a index.
0136      */
0137     void _k_setListStyle(int index);
0138 
0139     /**
0140      * Change the heading level of a current line to a level given by @a level
0141      */
0142     void _k_setHeadingLevel(int level);
0143 };
0144 //@endcond
0145 
0146 void KRichTextWidgetPrivate::init()
0147 {
0148     Q_Q(KRichTextWidget);
0149 
0150     q->setRichTextSupport(KRichTextWidget::FullSupport);
0151 }
0152 
0153 KRichTextWidget::KRichTextWidget(QWidget *parent)
0154     : KRichTextEdit(*new KRichTextWidgetPrivate(this), parent)
0155 {
0156     Q_D(KRichTextWidget);
0157 
0158     d->init();
0159 }
0160 
0161 KRichTextWidget::KRichTextWidget(const QString &text, QWidget *parent)
0162     : KRichTextEdit(*new KRichTextWidgetPrivate(this), text, parent)
0163 {
0164     Q_D(KRichTextWidget);
0165 
0166     d->init();
0167 }
0168 
0169 KRichTextWidget::~KRichTextWidget() = default;
0170 
0171 KRichTextWidget::RichTextSupport KRichTextWidget::richTextSupport() const
0172 {
0173     Q_D(const KRichTextWidget);
0174 
0175     return d->richTextSupport;
0176 }
0177 
0178 void KRichTextWidget::setRichTextSupport(const KRichTextWidget::RichTextSupport &support)
0179 {
0180     Q_D(KRichTextWidget);
0181 
0182     d->richTextSupport = support;
0183 }
0184 
0185 QList<QAction *> KRichTextWidget::createActions()
0186 {
0187     Q_D(KRichTextWidget);
0188 
0189     // Note to maintainers: If adding new functionality here, make sure to disconnect
0190     // and delete actions which should not be supported.
0191     //
0192     // New Actions need to be added to the following places:
0193     // - possibly the RichTextSupportValues enum
0194     // - the API documentation for createActions()
0195     // - this function
0196     // - the action needs to be added to the private class as a member
0197     // - the constructor of the private class
0198     // - depending on the action, some slot that changes the toggle state when
0199     //   appropriate, such as updateCharFormatActions or updateMiscActions.
0200 
0201     // The list of actions currently supported is also stored internally.
0202     // This is used to disable all actions at once in setActionsEnabled.
0203     d->richTextActionList.clear();
0204 
0205     if (d->richTextSupport & SupportTextForegroundColor) {
0206         // Foreground Color
0207         d->action_text_foreground_color = new QAction(QIcon::fromTheme(QStringLiteral("format-stroke-color")), i18nc("@action", "Text &Color..."), this);
0208         d->action_text_foreground_color->setIconText(i18nc("@label stroke color", "Color"));
0209         d->richTextActionList.append((d->action_text_foreground_color));
0210         d->action_text_foreground_color->setObjectName(QStringLiteral("format_text_foreground_color"));
0211         connect(d->action_text_foreground_color, &QAction::triggered, this, [this]() {
0212             Q_D(KRichTextWidget);
0213             d->_k_setTextForegroundColor();
0214         });
0215     } else {
0216         d->action_text_foreground_color = nullptr;
0217     }
0218 
0219     if (d->richTextSupport & SupportTextBackgroundColor) {
0220         // Background Color
0221         d->action_text_background_color = new QAction(QIcon::fromTheme(QStringLiteral("format-fill-color")), i18nc("@action", "Text &Highlight..."), this);
0222         d->richTextActionList.append((d->action_text_background_color));
0223         d->action_text_background_color->setObjectName(QStringLiteral("format_text_background_color"));
0224         connect(d->action_text_background_color, &QAction::triggered, this, [this]() {
0225             Q_D(KRichTextWidget);
0226             d->_k_setTextBackgroundColor();
0227         });
0228     } else {
0229         d->action_text_background_color = nullptr;
0230     }
0231 
0232     if (d->richTextSupport & SupportFontFamily) {
0233         // Font Family
0234         d->action_font_family = new KFontAction(i18nc("@action", "&Font"), this);
0235         d->richTextActionList.append((d->action_font_family));
0236         d->action_font_family->setObjectName(QStringLiteral("format_font_family"));
0237         connect(d->action_font_family, &KSelectAction::textTriggered, this, &KRichTextWidget::setFontFamily);
0238     } else {
0239         d->action_font_family = nullptr;
0240     }
0241 
0242     if (d->richTextSupport & SupportFontSize) {
0243         // Font Size
0244         d->action_font_size = new KFontSizeAction(i18nc("@action", "Font &Size"), this);
0245         d->richTextActionList.append((d->action_font_size));
0246         d->action_font_size->setObjectName(QStringLiteral("format_font_size"));
0247         connect(d->action_font_size, &KFontSizeAction::fontSizeChanged, this, &KRichTextEdit::setFontSize);
0248     } else {
0249         d->action_font_size = nullptr;
0250     }
0251 
0252     if (d->richTextSupport & SupportBold) {
0253         d->action_text_bold = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-text-bold")), i18nc("@action boldify selected text", "&Bold"), this);
0254         QFont bold;
0255         bold.setBold(true);
0256         d->action_text_bold->setFont(bold);
0257         d->richTextActionList.append((d->action_text_bold));
0258         d->action_text_bold->setObjectName(QStringLiteral("format_text_bold"));
0259         d->action_text_bold->setShortcut(Qt::CTRL | Qt::Key_B);
0260         connect(d->action_text_bold, &QAction::triggered, this, &KRichTextEdit::setTextBold);
0261     } else {
0262         d->action_text_bold = nullptr;
0263     }
0264 
0265     if (d->richTextSupport & SupportItalic) {
0266         d->action_text_italic =
0267             new KToggleAction(QIcon::fromTheme(QStringLiteral("format-text-italic")), i18nc("@action italicize selected text", "&Italic"), this);
0268         QFont italic;
0269         italic.setItalic(true);
0270         d->action_text_italic->setFont(italic);
0271         d->richTextActionList.append((d->action_text_italic));
0272         d->action_text_italic->setObjectName(QStringLiteral("format_text_italic"));
0273         d->action_text_italic->setShortcut(Qt::CTRL | Qt::Key_I);
0274         connect(d->action_text_italic, &QAction::triggered, this, &KRichTextEdit::setTextItalic);
0275     } else {
0276         d->action_text_italic = nullptr;
0277     }
0278 
0279     if (d->richTextSupport & SupportUnderline) {
0280         d->action_text_underline =
0281             new KToggleAction(QIcon::fromTheme(QStringLiteral("format-text-underline")), i18nc("@action underline selected text", "&Underline"), this);
0282         QFont underline;
0283         underline.setUnderline(true);
0284         d->action_text_underline->setFont(underline);
0285         d->richTextActionList.append((d->action_text_underline));
0286         d->action_text_underline->setObjectName(QStringLiteral("format_text_underline"));
0287         d->action_text_underline->setShortcut(Qt::CTRL | Qt::Key_U);
0288         connect(d->action_text_underline, &QAction::triggered, this, &KRichTextEdit::setTextUnderline);
0289     } else {
0290         d->action_text_underline = nullptr;
0291     }
0292 
0293     if (d->richTextSupport & SupportStrikeOut) {
0294         d->action_text_strikeout = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-text-strikethrough")), i18nc("@action", "&Strike Out"), this);
0295         QFont strikeout;
0296         strikeout.setStrikeOut(true);
0297         d->action_text_strikeout->setFont(strikeout);
0298         d->richTextActionList.append((d->action_text_strikeout));
0299         d->action_text_strikeout->setObjectName(QStringLiteral("format_text_strikeout"));
0300         d->action_text_strikeout->setShortcut(Qt::CTRL | Qt::Key_L);
0301         connect(d->action_text_strikeout, &QAction::triggered, this, &KRichTextEdit::setTextStrikeOut);
0302     } else {
0303         d->action_text_strikeout = nullptr;
0304     }
0305 
0306     if (d->richTextSupport & SupportAlignment) {
0307         // Alignment
0308         d->action_align_left = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-justify-left")), i18nc("@action", "Align &Left"), this);
0309         d->action_align_left->setIconText(i18nc("@label left justify", "Left"));
0310         d->richTextActionList.append((d->action_align_left));
0311         d->action_align_left->setObjectName(QStringLiteral("format_align_left"));
0312         connect(d->action_align_left, &QAction::triggered, this, &KRichTextEdit::alignLeft);
0313 
0314         d->action_align_center = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-justify-center")), i18nc("@action", "Align &Center"), this);
0315         d->action_align_center->setIconText(i18nc("@label center justify", "Center"));
0316         d->richTextActionList.append((d->action_align_center));
0317         d->action_align_center->setObjectName(QStringLiteral("format_align_center"));
0318         connect(d->action_align_center, &QAction::triggered, this, &KRichTextEdit::alignCenter);
0319 
0320         d->action_align_right = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-justify-right")), i18nc("@action", "Align &Right"), this);
0321         d->action_align_right->setIconText(i18nc("@label right justify", "Right"));
0322         d->richTextActionList.append((d->action_align_right));
0323         d->action_align_right->setObjectName(QStringLiteral("format_align_right"));
0324         connect(d->action_align_right, &QAction::triggered, this, &KRichTextEdit::alignRight);
0325 
0326         d->action_align_justify = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-justify-fill")), i18nc("@action", "&Justify"), this);
0327         d->action_align_justify->setIconText(i18nc("@label justify fill", "Justify"));
0328         d->richTextActionList.append((d->action_align_justify));
0329         d->action_align_justify->setObjectName(QStringLiteral("format_align_justify"));
0330         connect(d->action_align_justify, &QAction::triggered, this, &KRichTextEdit::alignJustify);
0331 
0332         QActionGroup *alignmentGroup = new QActionGroup(this);
0333         alignmentGroup->addAction(d->action_align_left);
0334         alignmentGroup->addAction(d->action_align_center);
0335         alignmentGroup->addAction(d->action_align_right);
0336         alignmentGroup->addAction(d->action_align_justify);
0337     } else {
0338         d->action_align_left = nullptr;
0339         d->action_align_center = nullptr;
0340         d->action_align_right = nullptr;
0341         d->action_align_justify = nullptr;
0342     }
0343 
0344     if (d->richTextSupport & SupportDirection) {
0345         d->action_direction_ltr = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-text-direction-ltr")), i18nc("@action", "Left-to-Right"), this);
0346         d->action_direction_ltr->setIconText(i18nc("@label left-to-right", "Left-to-Right"));
0347         d->richTextActionList.append(d->action_direction_ltr);
0348         d->action_direction_ltr->setObjectName(QStringLiteral("direction_ltr"));
0349         connect(d->action_direction_ltr, &QAction::triggered, this, &KRichTextEdit::makeLeftToRight);
0350 
0351         d->action_direction_rtl = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-text-direction-rtl")), i18nc("@action", "Right-to-Left"), this);
0352         d->action_direction_rtl->setIconText(i18nc("@label right-to-left", "Right-to-Left"));
0353         d->richTextActionList.append(d->action_direction_rtl);
0354         d->action_direction_rtl->setObjectName(QStringLiteral("direction_rtl"));
0355         connect(d->action_direction_rtl, &QAction::triggered, this, &KRichTextEdit::makeRightToLeft);
0356 
0357         QActionGroup *directionGroup = new QActionGroup(this);
0358         directionGroup->addAction(d->action_direction_ltr);
0359         directionGroup->addAction(d->action_direction_rtl);
0360     } else {
0361         d->action_direction_ltr = nullptr;
0362         d->action_direction_rtl = nullptr;
0363     }
0364 
0365     if (d->richTextSupport & SupportChangeListStyle) {
0366         d->action_list_style = new KSelectAction(QIcon::fromTheme(QStringLiteral("format-list-unordered")), i18nc("@title:menu", "List Style"), this);
0367         QStringList listStyles;
0368         /* clang-format off */
0369         listStyles << i18nc("@item:inmenu no list style", "None")
0370                    << i18nc("@item:inmenu disc list style", "Disc")
0371                    << i18nc("@item:inmenu circle list style", "Circle")
0372                    << i18nc("@item:inmenu square list style", "Square")
0373                    << i18nc("@item:inmenu numbered lists", "123")
0374                    << i18nc("@item:inmenu lowercase abc lists", "abc")
0375                    << i18nc("@item:inmenu uppercase abc lists", "ABC")
0376                    << i18nc("@item:inmenu lower case roman numerals", "i ii iii")
0377                    << i18nc("@item:inmenu upper case roman numerals", "I II III");
0378         /* clang-format on */
0379 
0380         d->action_list_style->setItems(listStyles);
0381         d->action_list_style->setCurrentItem(0);
0382         d->richTextActionList.append((d->action_list_style));
0383         d->action_list_style->setObjectName(QStringLiteral("format_list_style"));
0384 
0385         connect(d->action_list_style, &KSelectAction::indexTriggered, this, [this](int style) {
0386             Q_D(KRichTextWidget);
0387             d->_k_setListStyle(style);
0388         });
0389         connect(d->action_list_style, &QAction::triggered, this, [d]() {
0390             d->updateMiscActions();
0391         });
0392     } else {
0393         d->action_list_style = nullptr;
0394     }
0395 
0396     if (d->richTextSupport & SupportIndentLists) {
0397         d->action_list_indent = new QAction(QIcon::fromTheme(QStringLiteral("format-indent-more")), i18nc("@action", "Increase Indent"), this);
0398         d->richTextActionList.append((d->action_list_indent));
0399         d->action_list_indent->setObjectName(QStringLiteral("format_list_indent_more"));
0400         connect(d->action_list_indent, &QAction::triggered, this, &KRichTextEdit::indentListMore);
0401         connect(d->action_list_indent, &QAction::triggered, this, [d]() {
0402             d->updateMiscActions();
0403         });
0404     } else {
0405         d->action_list_indent = nullptr;
0406     }
0407 
0408     if (d->richTextSupport & SupportDedentLists) {
0409         d->action_list_dedent = new QAction(QIcon::fromTheme(QStringLiteral("format-indent-less")), i18nc("@action", "Decrease Indent"), this);
0410         d->richTextActionList.append((d->action_list_dedent));
0411         d->action_list_dedent->setObjectName(QStringLiteral("format_list_indent_less"));
0412         connect(d->action_list_dedent, &QAction::triggered, this, &KRichTextEdit::indentListLess);
0413         connect(d->action_list_dedent, &QAction::triggered, this, [d]() {
0414             d->updateMiscActions();
0415         });
0416     } else {
0417         d->action_list_dedent = nullptr;
0418     }
0419 
0420     if (d->richTextSupport & SupportRuleLine) {
0421         d->action_insert_horizontal_rule = new QAction(QIcon::fromTheme(QStringLiteral("insert-horizontal-rule")), i18nc("@action", "Insert Rule Line"), this);
0422         d->richTextActionList.append((d->action_insert_horizontal_rule));
0423         d->action_insert_horizontal_rule->setObjectName(QStringLiteral("insert_horizontal_rule"));
0424         connect(d->action_insert_horizontal_rule, &QAction::triggered, this, &KRichTextEdit::insertHorizontalRule);
0425     } else {
0426         d->action_insert_horizontal_rule = nullptr;
0427     }
0428 
0429     if (d->richTextSupport & SupportHyperlinks) {
0430         d->action_manage_link = new QAction(QIcon::fromTheme(QStringLiteral("insert-link")), i18nc("@action", "Link"), this);
0431         d->richTextActionList.append((d->action_manage_link));
0432         d->action_manage_link->setObjectName(QStringLiteral("manage_link"));
0433         connect(d->action_manage_link, &QAction::triggered, this, [this]() {
0434             Q_D(KRichTextWidget);
0435             d->_k_manageLink();
0436         });
0437     } else {
0438         d->action_manage_link = nullptr;
0439     }
0440 
0441     if (d->richTextSupport & SupportFormatPainting) {
0442         d->action_format_painter = new KToggleAction(QIcon::fromTheme(QStringLiteral("draw-brush")), i18nc("@action", "Format Painter"), this);
0443         d->richTextActionList.append((d->action_format_painter));
0444         d->action_format_painter->setObjectName(QStringLiteral("format_painter"));
0445         connect(d->action_format_painter, &QAction::toggled, this, [this](bool state) {
0446             Q_D(KRichTextWidget);
0447             d->_k_formatPainter(state);
0448         });
0449     } else {
0450         d->action_format_painter = nullptr;
0451     }
0452 
0453     if (d->richTextSupport & SupportToPlainText) {
0454         d->action_to_plain_text = new KToggleAction(i18nc("@action", "To Plain Text"), this);
0455         d->richTextActionList.append((d->action_to_plain_text));
0456         d->action_to_plain_text->setObjectName(QStringLiteral("action_to_plain_text"));
0457         connect(d->action_to_plain_text, &QAction::triggered, this, &KRichTextEdit::switchToPlainText);
0458     } else {
0459         d->action_to_plain_text = nullptr;
0460     }
0461 
0462     if (d->richTextSupport & SupportSuperScriptAndSubScript) {
0463         d->action_text_subscript = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-text-subscript")), i18nc("@action", "Subscript"), this);
0464         d->richTextActionList.append((d->action_text_subscript));
0465         d->action_text_subscript->setObjectName(QStringLiteral("format_text_subscript"));
0466         connect(d->action_text_subscript, &QAction::triggered, this, &KRichTextEdit::setTextSubScript);
0467 
0468         d->action_text_superscript = new KToggleAction(QIcon::fromTheme(QStringLiteral("format-text-superscript")), i18nc("@action", "Superscript"), this);
0469         d->richTextActionList.append((d->action_text_superscript));
0470         d->action_text_superscript->setObjectName(QStringLiteral("format_text_superscript"));
0471         connect(d->action_text_superscript, &QAction::triggered, this, &KRichTextEdit::setTextSuperScript);
0472     } else {
0473         d->action_text_subscript = nullptr;
0474 
0475         d->action_text_superscript = nullptr;
0476     }
0477 
0478     if (d->richTextSupport & SupportHeading) {
0479         // TODO: an icon maybe?
0480         d->action_heading_level = new KSelectAction(i18nc("@title:menu", "Heading Level"), this);
0481         const QStringList headingLevels = {i18nc("@item:inmenu no heading", "Basic text"),
0482                                            i18nc("@item:inmenu heading level 1 (largest)", "Title"),
0483                                            i18nc("@item:inmenu heading level 2", "Subtitle"),
0484                                            i18nc("@item:inmenu heading level 3", "Section"),
0485                                            i18nc("@item:inmenu heading level 4", "Subsection"),
0486                                            i18nc("@item:inmenu heading level 5", "Paragraph"),
0487                                            i18nc("@item:inmenu heading level 6 (smallest)", "Subparagraph")};
0488 
0489         d->action_heading_level->setItems(headingLevels);
0490         d->action_heading_level->setCurrentItem(0);
0491         d->richTextActionList.append(d->action_heading_level);
0492         d->action_heading_level->setObjectName(QStringLiteral("format_heading_level"));
0493         connect(d->action_heading_level, &KSelectAction::indexTriggered, this, [this](int level) {
0494             Q_D(KRichTextWidget);
0495             d->_k_setHeadingLevel(level);
0496         });
0497     } else {
0498         d->action_heading_level = nullptr;
0499     }
0500 
0501     disconnect(this, &QTextEdit::currentCharFormatChanged, this, nullptr);
0502     disconnect(this, &QTextEdit::cursorPositionChanged, this, nullptr);
0503     connect(this, &QTextEdit::currentCharFormatChanged, this, [d](const QTextCharFormat &format) {
0504         d->updateCharFormatActions(format);
0505     });
0506     connect(this, &QTextEdit::cursorPositionChanged, this, [d]() {
0507         d->updateMiscActions();
0508     });
0509 
0510     d->updateMiscActions();
0511     d->updateCharFormatActions(currentCharFormat());
0512 
0513     return d->richTextActionList;
0514 }
0515 
0516 void KRichTextWidget::setActionsEnabled(bool enabled)
0517 {
0518     Q_D(KRichTextWidget);
0519 
0520     for (QAction *action : std::as_const(d->richTextActionList)) {
0521         action->setEnabled(enabled);
0522     }
0523     d->richTextEnabled = enabled;
0524 }
0525 
0526 void KRichTextWidgetPrivate::_k_setListStyle(int index)
0527 {
0528     Q_Q(KRichTextWidget);
0529 
0530     q->setListStyle(index);
0531     updateMiscActions();
0532 }
0533 
0534 void KRichTextWidgetPrivate::_k_setHeadingLevel(int level)
0535 {
0536     Q_Q(KRichTextWidget);
0537 
0538     q->setHeadingLevel(level);
0539     updateMiscActions();
0540 }
0541 
0542 void KRichTextWidgetPrivate::updateCharFormatActions(const QTextCharFormat &format)
0543 {
0544     Q_Q(KRichTextWidget);
0545 
0546     QFont f = format.font();
0547 
0548     if (richTextSupport & KRichTextWidget::SupportFontFamily) {
0549         action_font_family->setFont(f.family());
0550     }
0551     if (richTextSupport & KRichTextWidget::SupportFontSize) {
0552         if (f.pointSize() > 0) {
0553             action_font_size->setFontSize(f.pointSize());
0554         }
0555     }
0556 
0557     if (richTextSupport & KRichTextWidget::SupportBold) {
0558         action_text_bold->setChecked(f.bold());
0559     }
0560 
0561     if (richTextSupport & KRichTextWidget::SupportItalic) {
0562         action_text_italic->setChecked(f.italic());
0563     }
0564 
0565     if (richTextSupport & KRichTextWidget::SupportUnderline) {
0566         action_text_underline->setChecked(f.underline());
0567     }
0568 
0569     if (richTextSupport & KRichTextWidget::SupportStrikeOut) {
0570         action_text_strikeout->setChecked(f.strikeOut());
0571     }
0572 
0573     if (richTextSupport & KRichTextWidget::SupportSuperScriptAndSubScript) {
0574         QTextCharFormat::VerticalAlignment vAlign = format.verticalAlignment();
0575         action_text_superscript->setChecked(vAlign == QTextCharFormat::AlignSuperScript);
0576         action_text_subscript->setChecked(vAlign == QTextCharFormat::AlignSubScript);
0577     }
0578 }
0579 
0580 void KRichTextWidgetPrivate::updateMiscActions()
0581 {
0582     Q_Q(KRichTextWidget);
0583 
0584     if (richTextSupport & KRichTextWidget::SupportAlignment) {
0585         Qt::Alignment a = q->alignment();
0586         if (a & Qt::AlignLeft) {
0587             action_align_left->setChecked(true);
0588         } else if (a & Qt::AlignHCenter) {
0589             action_align_center->setChecked(true);
0590         } else if (a & Qt::AlignRight) {
0591             action_align_right->setChecked(true);
0592         } else if (a & Qt::AlignJustify) {
0593             action_align_justify->setChecked(true);
0594         }
0595     }
0596 
0597     if (richTextSupport & KRichTextWidget::SupportChangeListStyle) {
0598         if (q->textCursor().currentList()) {
0599             action_list_style->setCurrentItem(-q->textCursor().currentList()->format().style());
0600         } else {
0601             action_list_style->setCurrentItem(0);
0602         }
0603     }
0604 
0605     if (richTextSupport & KRichTextWidget::SupportIndentLists) {
0606         if (richTextEnabled) {
0607             action_list_indent->setEnabled(q->canIndentList());
0608         } else {
0609             action_list_indent->setEnabled(false);
0610         }
0611     }
0612 
0613     if (richTextSupport & KRichTextWidget::SupportDedentLists) {
0614         if (richTextEnabled) {
0615             action_list_dedent->setEnabled(q->canDedentList());
0616         } else {
0617             action_list_dedent->setEnabled(false);
0618         }
0619     }
0620 
0621     if (richTextSupport & KRichTextWidget::SupportDirection) {
0622         const Qt::LayoutDirection direction = q->textCursor().blockFormat().layoutDirection();
0623         action_direction_ltr->setChecked(direction == Qt::LeftToRight);
0624         action_direction_rtl->setChecked(direction == Qt::RightToLeft);
0625     }
0626 
0627     if (richTextSupport & KRichTextWidget::SupportHeading) {
0628         action_heading_level->setCurrentItem(q->textCursor().blockFormat().headingLevel());
0629     }
0630 }
0631 
0632 void KRichTextWidgetPrivate::_k_setTextForegroundColor()
0633 {
0634     Q_Q(KRichTextWidget);
0635 
0636     const QColor currentColor = q->textColor();
0637     const QColor defaultColor = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
0638 
0639     const QColor selectedColor = QColorDialog::getColor(currentColor.isValid() ? currentColor : defaultColor, q);
0640 
0641     if (!selectedColor.isValid() && !currentColor.isValid()) {
0642         q->setTextForegroundColor(defaultColor);
0643     } else if (selectedColor.isValid()) {
0644         q->setTextForegroundColor(selectedColor);
0645     }
0646 }
0647 
0648 void KRichTextWidgetPrivate::_k_setTextBackgroundColor()
0649 {
0650     Q_Q(KRichTextWidget);
0651 
0652     QTextCharFormat fmt = q->textCursor().charFormat();
0653     const QColor currentColor = fmt.background().color();
0654     const QColor defaultColor = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
0655 
0656     const QColor selectedColor = QColorDialog::getColor(currentColor.isValid() ? currentColor : defaultColor, q);
0657 
0658     if (!selectedColor.isValid() && !currentColor.isValid()) {
0659         q->setTextBackgroundColor(defaultColor);
0660     } else if (selectedColor.isValid()) {
0661         q->setTextBackgroundColor(selectedColor);
0662     }
0663 }
0664 
0665 void KRichTextWidgetPrivate::_k_manageLink()
0666 {
0667     Q_Q(KRichTextWidget);
0668 
0669     q->selectLinkText();
0670     KLinkDialog *linkDialog = new KLinkDialog(q);
0671     linkDialog->setLinkText(q->currentLinkText());
0672     linkDialog->setLinkUrl(q->currentLinkUrl());
0673     linkDialog->setAttribute(Qt::WA_DeleteOnClose);
0674 
0675     QObject::connect(linkDialog, &QDialog::accepted, linkDialog, [linkDialog, this]() {
0676         Q_Q(KRichTextWidget);
0677         q->updateLink(linkDialog->linkUrl(), linkDialog->linkText());
0678     });
0679 
0680     linkDialog->show();
0681 }
0682 
0683 void KRichTextWidget::mouseReleaseEvent(QMouseEvent *event)
0684 {
0685     Q_D(KRichTextWidget);
0686 
0687     if (d->painterActive) {
0688         // If the painter is active, paint the selection with the
0689         // correct format.
0690         if (textCursor().hasSelection()) {
0691             QTextCursor c = textCursor();
0692             c.setCharFormat(d->painterFormat);
0693             setTextCursor(c);
0694         }
0695         d->painterActive = false;
0696         d->action_format_painter->setChecked(false);
0697     }
0698     KRichTextEdit::mouseReleaseEvent(event);
0699 }
0700 
0701 void KRichTextWidgetPrivate::_k_formatPainter(bool active)
0702 {
0703     Q_Q(KRichTextWidget);
0704 
0705     if (active) {
0706         painterFormat = q->currentCharFormat();
0707         painterActive = true;
0708         q->viewport()->setCursor(QCursor(QIcon::fromTheme(QStringLiteral("draw-brush")).pixmap(32, 32), 0, 32));
0709     } else {
0710         painterFormat = QTextCharFormat();
0711         painterActive = false;
0712         q->viewport()->setCursor(Qt::IBeamCursor);
0713     }
0714 }
0715 
0716 void KRichTextWidget::updateActionStates()
0717 {
0718     Q_D(KRichTextWidget);
0719 
0720     d->updateMiscActions();
0721     d->updateCharFormatActions(currentCharFormat());
0722 }
0723 
0724 #include "moc_krichtextwidget.cpp"