| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the demonstration applications of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:BSD$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** BSD License Usage |
| 18 | ** Alternatively, you may use this file under the terms of the BSD license |
| 19 | ** as follows: |
| 20 | ** |
| 21 | ** "Redistribution and use in source and binary forms, with or without |
| 22 | ** modification, are permitted provided that the following conditions are |
| 23 | ** met: |
| 24 | ** * Redistributions of source code must retain the above copyright |
| 25 | ** notice, this list of conditions and the following disclaimer. |
| 26 | ** * Redistributions in binary form must reproduce the above copyright |
| 27 | ** notice, this list of conditions and the following disclaimer in |
| 28 | ** the documentation and/or other materials provided with the |
| 29 | ** distribution. |
| 30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
| 31 | ** contributors may be used to endorse or promote products derived |
| 32 | ** from this software without specific prior written permission. |
| 33 | ** |
| 34 | ** |
| 35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| 46 | ** |
| 47 | ** $QT_END_LICENSE$ |
| 48 | ** |
| 49 | ****************************************************************************/ |
| 50 | |
| 51 | #include <QAction> |
| 52 | #include <QApplication> |
| 53 | #include <QClipboard> |
| 54 | #include <QColorDialog> |
| 55 | #include <QComboBox> |
| 56 | #include <QFontComboBox> |
| 57 | #include <QFile> |
| 58 | #include <QFileDialog> |
| 59 | #include <QFileInfo> |
| 60 | #include <QFontDatabase> |
| 61 | #include <QMenu> |
| 62 | #include <QMenuBar> |
| 63 | #include <QTextCodec> |
| 64 | #include <QTextEdit> |
| 65 | #include <QStatusBar> |
| 66 | #include <QToolBar> |
| 67 | #include <QTextCursor> |
| 68 | #include <QTextDocumentWriter> |
| 69 | #include <QTextList> |
| 70 | #include <QtDebug> |
| 71 | #include <QCloseEvent> |
| 72 | #include <QMessageBox> |
| 73 | #include <QMimeData> |
| 74 | #include <QMimeDatabase> |
| 75 | #if defined(QT_PRINTSUPPORT_LIB) |
| 76 | #include <QtPrintSupport/qtprintsupportglobal.h> |
| 77 | #if QT_CONFIG(printer) |
| 78 | #if QT_CONFIG(printdialog) |
| 79 | #include <QPrintDialog> |
| 80 | #endif |
| 81 | #include <QPrinter> |
| 82 | #if QT_CONFIG(printpreviewdialog) |
| 83 | #include <QPrintPreviewDialog> |
| 84 | #endif |
| 85 | #endif |
| 86 | #endif |
| 87 | |
| 88 | #include "textedit.h" |
| 89 | |
| 90 | #ifdef Q_OS_MAC |
| 91 | const QString rsrcPath = ":/images/mac" ; |
| 92 | #else |
| 93 | const QString rsrcPath = ":/images/win" ; |
| 94 | #endif |
| 95 | |
| 96 | TextEdit::TextEdit(QWidget *parent) |
| 97 | : QMainWindow(parent) |
| 98 | { |
| 99 | #ifdef Q_OS_MACOS |
| 100 | setUnifiedTitleAndToolBarOnMac(true); |
| 101 | #endif |
| 102 | setWindowTitle(QCoreApplication::applicationName()); |
| 103 | |
| 104 | textEdit = new QTextEdit(this); |
| 105 | connect(sender: textEdit, signal: &QTextEdit::currentCharFormatChanged, |
| 106 | receiver: this, slot: &TextEdit::currentCharFormatChanged); |
| 107 | connect(sender: textEdit, signal: &QTextEdit::cursorPositionChanged, |
| 108 | receiver: this, slot: &TextEdit::cursorPositionChanged); |
| 109 | setCentralWidget(textEdit); |
| 110 | |
| 111 | setToolButtonStyle(Qt::ToolButtonFollowStyle); |
| 112 | setupFileActions(); |
| 113 | setupEditActions(); |
| 114 | setupTextActions(); |
| 115 | |
| 116 | { |
| 117 | QMenu * = menuBar()->addMenu(title: tr(s: "Help" )); |
| 118 | helpMenu->addAction(text: tr(s: "About" ), object: this, slot: &TextEdit::about); |
| 119 | helpMenu->addAction(text: tr(s: "About &Qt" ), qApp, slot: &QApplication::aboutQt); |
| 120 | } |
| 121 | |
| 122 | QFont textFont("Helvetica" ); |
| 123 | textFont.setStyleHint(QFont::SansSerif); |
| 124 | textEdit->setFont(textFont); |
| 125 | fontChanged(f: textEdit->font()); |
| 126 | colorChanged(c: textEdit->textColor()); |
| 127 | alignmentChanged(a: textEdit->alignment()); |
| 128 | |
| 129 | connect(sender: textEdit->document(), signal: &QTextDocument::modificationChanged, |
| 130 | receiver: actionSave, slot: &QAction::setEnabled); |
| 131 | connect(sender: textEdit->document(), signal: &QTextDocument::modificationChanged, |
| 132 | receiver: this, slot: &QWidget::setWindowModified); |
| 133 | connect(sender: textEdit->document(), signal: &QTextDocument::undoAvailable, |
| 134 | receiver: actionUndo, slot: &QAction::setEnabled); |
| 135 | connect(sender: textEdit->document(), signal: &QTextDocument::redoAvailable, |
| 136 | receiver: actionRedo, slot: &QAction::setEnabled); |
| 137 | |
| 138 | setWindowModified(textEdit->document()->isModified()); |
| 139 | actionSave->setEnabled(textEdit->document()->isModified()); |
| 140 | actionUndo->setEnabled(textEdit->document()->isUndoAvailable()); |
| 141 | actionRedo->setEnabled(textEdit->document()->isRedoAvailable()); |
| 142 | |
| 143 | #ifndef QT_NO_CLIPBOARD |
| 144 | actionCut->setEnabled(false); |
| 145 | connect(sender: textEdit, signal: &QTextEdit::copyAvailable, receiver: actionCut, slot: &QAction::setEnabled); |
| 146 | actionCopy->setEnabled(false); |
| 147 | connect(sender: textEdit, signal: &QTextEdit::copyAvailable, receiver: actionCopy, slot: &QAction::setEnabled); |
| 148 | |
| 149 | connect(sender: QApplication::clipboard(), signal: &QClipboard::dataChanged, receiver: this, slot: &TextEdit::clipboardDataChanged); |
| 150 | #endif |
| 151 | |
| 152 | textEdit->setFocus(); |
| 153 | setCurrentFileName(QString()); |
| 154 | |
| 155 | #ifdef Q_OS_MACOS |
| 156 | // Use dark text on light background on macOS, also in dark mode. |
| 157 | QPalette pal = textEdit->palette(); |
| 158 | pal.setColor(QPalette::Base, QColor(Qt::white)); |
| 159 | pal.setColor(QPalette::Text, QColor(Qt::black)); |
| 160 | textEdit->setPalette(pal); |
| 161 | #endif |
| 162 | } |
| 163 | |
| 164 | void TextEdit::closeEvent(QCloseEvent *e) |
| 165 | { |
| 166 | if (maybeSave()) |
| 167 | e->accept(); |
| 168 | else |
| 169 | e->ignore(); |
| 170 | } |
| 171 | |
| 172 | void TextEdit::setupFileActions() |
| 173 | { |
| 174 | QToolBar *tb = addToolBar(title: tr(s: "File Actions" )); |
| 175 | QMenu * = menuBar()->addMenu(title: tr(s: "&File" )); |
| 176 | |
| 177 | const QIcon newIcon = QIcon::fromTheme(name: "document-new" , fallback: QIcon(rsrcPath + "/filenew.png" )); |
| 178 | QAction *a = menu->addAction(actionIcon: newIcon, text: tr(s: "&New" ), object: this, slot: &TextEdit::fileNew); |
| 179 | tb->addAction(action: a); |
| 180 | a->setPriority(QAction::LowPriority); |
| 181 | a->setShortcut(QKeySequence::New); |
| 182 | |
| 183 | const QIcon openIcon = QIcon::fromTheme(name: "document-open" , fallback: QIcon(rsrcPath + "/fileopen.png" )); |
| 184 | a = menu->addAction(actionIcon: openIcon, text: tr(s: "&Open..." ), object: this, slot: &TextEdit::fileOpen); |
| 185 | a->setShortcut(QKeySequence::Open); |
| 186 | tb->addAction(action: a); |
| 187 | |
| 188 | menu->addSeparator(); |
| 189 | |
| 190 | const QIcon saveIcon = QIcon::fromTheme(name: "document-save" , fallback: QIcon(rsrcPath + "/filesave.png" )); |
| 191 | actionSave = menu->addAction(actionIcon: saveIcon, text: tr(s: "&Save" ), object: this, slot: &TextEdit::fileSave); |
| 192 | actionSave->setShortcut(QKeySequence::Save); |
| 193 | actionSave->setEnabled(false); |
| 194 | tb->addAction(action: actionSave); |
| 195 | |
| 196 | a = menu->addAction(text: tr(s: "Save &As..." ), object: this, slot: &TextEdit::fileSaveAs); |
| 197 | a->setPriority(QAction::LowPriority); |
| 198 | menu->addSeparator(); |
| 199 | |
| 200 | #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) |
| 201 | const QIcon printIcon = QIcon::fromTheme(name: "document-print" , fallback: QIcon(rsrcPath + "/fileprint.png" )); |
| 202 | a = menu->addAction(actionIcon: printIcon, text: tr(s: "&Print..." ), object: this, slot: &TextEdit::filePrint); |
| 203 | a->setPriority(QAction::LowPriority); |
| 204 | a->setShortcut(QKeySequence::Print); |
| 205 | tb->addAction(action: a); |
| 206 | |
| 207 | const QIcon filePrintIcon = QIcon::fromTheme(name: "fileprint" , fallback: QIcon(rsrcPath + "/fileprint.png" )); |
| 208 | menu->addAction(actionIcon: filePrintIcon, text: tr(s: "Print Preview..." ), object: this, slot: &TextEdit::filePrintPreview); |
| 209 | |
| 210 | const QIcon exportPdfIcon = QIcon::fromTheme(name: "exportpdf" , fallback: QIcon(rsrcPath + "/exportpdf.png" )); |
| 211 | a = menu->addAction(actionIcon: exportPdfIcon, text: tr(s: "&Export PDF..." ), object: this, slot: &TextEdit::filePrintPdf); |
| 212 | a->setPriority(QAction::LowPriority); |
| 213 | a->setShortcut(Qt::CTRL + Qt::Key_D); |
| 214 | tb->addAction(action: a); |
| 215 | |
| 216 | menu->addSeparator(); |
| 217 | #endif |
| 218 | |
| 219 | a = menu->addAction(text: tr(s: "&Quit" ), object: this, slot: &QWidget::close); |
| 220 | a->setShortcut(Qt::CTRL + Qt::Key_Q); |
| 221 | } |
| 222 | |
| 223 | void TextEdit::setupEditActions() |
| 224 | { |
| 225 | QToolBar *tb = addToolBar(title: tr(s: "Edit Actions" )); |
| 226 | QMenu * = menuBar()->addMenu(title: tr(s: "&Edit" )); |
| 227 | |
| 228 | const QIcon undoIcon = QIcon::fromTheme(name: "edit-undo" , fallback: QIcon(rsrcPath + "/editundo.png" )); |
| 229 | actionUndo = menu->addAction(actionIcon: undoIcon, text: tr(s: "&Undo" ), object: textEdit, slot: &QTextEdit::undo); |
| 230 | actionUndo->setShortcut(QKeySequence::Undo); |
| 231 | tb->addAction(action: actionUndo); |
| 232 | |
| 233 | const QIcon redoIcon = QIcon::fromTheme(name: "edit-redo" , fallback: QIcon(rsrcPath + "/editredo.png" )); |
| 234 | actionRedo = menu->addAction(actionIcon: redoIcon, text: tr(s: "&Redo" ), object: textEdit, slot: &QTextEdit::redo); |
| 235 | actionRedo->setPriority(QAction::LowPriority); |
| 236 | actionRedo->setShortcut(QKeySequence::Redo); |
| 237 | tb->addAction(action: actionRedo); |
| 238 | menu->addSeparator(); |
| 239 | |
| 240 | #ifndef QT_NO_CLIPBOARD |
| 241 | const QIcon cutIcon = QIcon::fromTheme(name: "edit-cut" , fallback: QIcon(rsrcPath + "/editcut.png" )); |
| 242 | actionCut = menu->addAction(actionIcon: cutIcon, text: tr(s: "Cu&t" ), object: textEdit, slot: &QTextEdit::cut); |
| 243 | actionCut->setPriority(QAction::LowPriority); |
| 244 | actionCut->setShortcut(QKeySequence::Cut); |
| 245 | tb->addAction(action: actionCut); |
| 246 | |
| 247 | const QIcon copyIcon = QIcon::fromTheme(name: "edit-copy" , fallback: QIcon(rsrcPath + "/editcopy.png" )); |
| 248 | actionCopy = menu->addAction(actionIcon: copyIcon, text: tr(s: "&Copy" ), object: textEdit, slot: &QTextEdit::copy); |
| 249 | actionCopy->setPriority(QAction::LowPriority); |
| 250 | actionCopy->setShortcut(QKeySequence::Copy); |
| 251 | tb->addAction(action: actionCopy); |
| 252 | |
| 253 | const QIcon pasteIcon = QIcon::fromTheme(name: "edit-paste" , fallback: QIcon(rsrcPath + "/editpaste.png" )); |
| 254 | actionPaste = menu->addAction(actionIcon: pasteIcon, text: tr(s: "&Paste" ), object: textEdit, slot: &QTextEdit::paste); |
| 255 | actionPaste->setPriority(QAction::LowPriority); |
| 256 | actionPaste->setShortcut(QKeySequence::Paste); |
| 257 | tb->addAction(action: actionPaste); |
| 258 | if (const QMimeData *md = QApplication::clipboard()->mimeData()) |
| 259 | actionPaste->setEnabled(md->hasText()); |
| 260 | #endif |
| 261 | } |
| 262 | |
| 263 | void TextEdit::setupTextActions() |
| 264 | { |
| 265 | QToolBar *tb = addToolBar(title: tr(s: "Format Actions" )); |
| 266 | QMenu * = menuBar()->addMenu(title: tr(s: "F&ormat" )); |
| 267 | |
| 268 | const QIcon boldIcon = QIcon::fromTheme(name: "format-text-bold" , fallback: QIcon(rsrcPath + "/textbold.png" )); |
| 269 | actionTextBold = menu->addAction(actionIcon: boldIcon, text: tr(s: "&Bold" ), object: this, slot: &TextEdit::textBold); |
| 270 | actionTextBold->setShortcut(Qt::CTRL + Qt::Key_B); |
| 271 | actionTextBold->setPriority(QAction::LowPriority); |
| 272 | QFont bold; |
| 273 | bold.setBold(true); |
| 274 | actionTextBold->setFont(bold); |
| 275 | tb->addAction(action: actionTextBold); |
| 276 | actionTextBold->setCheckable(true); |
| 277 | |
| 278 | const QIcon italicIcon = QIcon::fromTheme(name: "format-text-italic" , fallback: QIcon(rsrcPath + "/textitalic.png" )); |
| 279 | actionTextItalic = menu->addAction(actionIcon: italicIcon, text: tr(s: "&Italic" ), object: this, slot: &TextEdit::textItalic); |
| 280 | actionTextItalic->setPriority(QAction::LowPriority); |
| 281 | actionTextItalic->setShortcut(Qt::CTRL + Qt::Key_I); |
| 282 | QFont italic; |
| 283 | italic.setItalic(true); |
| 284 | actionTextItalic->setFont(italic); |
| 285 | tb->addAction(action: actionTextItalic); |
| 286 | actionTextItalic->setCheckable(true); |
| 287 | |
| 288 | const QIcon underlineIcon = QIcon::fromTheme(name: "format-text-underline" , fallback: QIcon(rsrcPath + "/textunder.png" )); |
| 289 | actionTextUnderline = menu->addAction(actionIcon: underlineIcon, text: tr(s: "&Underline" ), object: this, slot: &TextEdit::textUnderline); |
| 290 | actionTextUnderline->setShortcut(Qt::CTRL + Qt::Key_U); |
| 291 | actionTextUnderline->setPriority(QAction::LowPriority); |
| 292 | QFont underline; |
| 293 | underline.setUnderline(true); |
| 294 | actionTextUnderline->setFont(underline); |
| 295 | tb->addAction(action: actionTextUnderline); |
| 296 | actionTextUnderline->setCheckable(true); |
| 297 | |
| 298 | menu->addSeparator(); |
| 299 | |
| 300 | const QIcon leftIcon = QIcon::fromTheme(name: "format-justify-left" , fallback: QIcon(rsrcPath + "/textleft.png" )); |
| 301 | actionAlignLeft = new QAction(leftIcon, tr(s: "&Left" ), this); |
| 302 | actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L); |
| 303 | actionAlignLeft->setCheckable(true); |
| 304 | actionAlignLeft->setPriority(QAction::LowPriority); |
| 305 | const QIcon centerIcon = QIcon::fromTheme(name: "format-justify-center" , fallback: QIcon(rsrcPath + "/textcenter.png" )); |
| 306 | actionAlignCenter = new QAction(centerIcon, tr(s: "C&enter" ), this); |
| 307 | actionAlignCenter->setShortcut(Qt::CTRL + Qt::Key_E); |
| 308 | actionAlignCenter->setCheckable(true); |
| 309 | actionAlignCenter->setPriority(QAction::LowPriority); |
| 310 | const QIcon rightIcon = QIcon::fromTheme(name: "format-justify-right" , fallback: QIcon(rsrcPath + "/textright.png" )); |
| 311 | actionAlignRight = new QAction(rightIcon, tr(s: "&Right" ), this); |
| 312 | actionAlignRight->setShortcut(Qt::CTRL + Qt::Key_R); |
| 313 | actionAlignRight->setCheckable(true); |
| 314 | actionAlignRight->setPriority(QAction::LowPriority); |
| 315 | const QIcon fillIcon = QIcon::fromTheme(name: "format-justify-fill" , fallback: QIcon(rsrcPath + "/textjustify.png" )); |
| 316 | actionAlignJustify = new QAction(fillIcon, tr(s: "&Justify" ), this); |
| 317 | actionAlignJustify->setShortcut(Qt::CTRL + Qt::Key_J); |
| 318 | actionAlignJustify->setCheckable(true); |
| 319 | actionAlignJustify->setPriority(QAction::LowPriority); |
| 320 | const QIcon indentMoreIcon = QIcon::fromTheme(name: "format-indent-more" , fallback: QIcon(rsrcPath + "/format-indent-more.png" )); |
| 321 | actionIndentMore = menu->addAction(actionIcon: indentMoreIcon, text: tr(s: "&Indent" ), object: this, slot: &TextEdit::indent); |
| 322 | actionIndentMore->setShortcut(Qt::CTRL + Qt::Key_BracketRight); |
| 323 | actionIndentMore->setPriority(QAction::LowPriority); |
| 324 | const QIcon indentLessIcon = QIcon::fromTheme(name: "format-indent-less" , fallback: QIcon(rsrcPath + "/format-indent-less.png" )); |
| 325 | actionIndentLess = menu->addAction(actionIcon: indentLessIcon, text: tr(s: "&Unindent" ), object: this, slot: &TextEdit::unindent); |
| 326 | actionIndentLess->setShortcut(Qt::CTRL + Qt::Key_BracketLeft); |
| 327 | actionIndentLess->setPriority(QAction::LowPriority); |
| 328 | |
| 329 | // Make sure the alignLeft is always left of the alignRight |
| 330 | QActionGroup *alignGroup = new QActionGroup(this); |
| 331 | connect(sender: alignGroup, signal: &QActionGroup::triggered, receiver: this, slot: &TextEdit::textAlign); |
| 332 | |
| 333 | if (QApplication::isLeftToRight()) { |
| 334 | alignGroup->addAction(a: actionAlignLeft); |
| 335 | alignGroup->addAction(a: actionAlignCenter); |
| 336 | alignGroup->addAction(a: actionAlignRight); |
| 337 | } else { |
| 338 | alignGroup->addAction(a: actionAlignRight); |
| 339 | alignGroup->addAction(a: actionAlignCenter); |
| 340 | alignGroup->addAction(a: actionAlignLeft); |
| 341 | } |
| 342 | alignGroup->addAction(a: actionAlignJustify); |
| 343 | |
| 344 | tb->addActions(actions: alignGroup->actions()); |
| 345 | menu->addActions(actions: alignGroup->actions()); |
| 346 | tb->addAction(action: actionIndentMore); |
| 347 | tb->addAction(action: actionIndentLess); |
| 348 | menu->addAction(action: actionIndentMore); |
| 349 | menu->addAction(action: actionIndentLess); |
| 350 | |
| 351 | menu->addSeparator(); |
| 352 | |
| 353 | QPixmap pix(16, 16); |
| 354 | pix.fill(fillColor: Qt::black); |
| 355 | actionTextColor = menu->addAction(actionIcon: pix, text: tr(s: "&Color..." ), object: this, slot: &TextEdit::textColor); |
| 356 | tb->addAction(action: actionTextColor); |
| 357 | |
| 358 | menu->addSeparator(); |
| 359 | |
| 360 | const QIcon checkboxIcon = QIcon::fromTheme(name: "status-checkbox-checked" , fallback: QIcon(rsrcPath + "/checkbox-checked.png" )); |
| 361 | actionToggleCheckState = menu->addAction(actionIcon: checkboxIcon, text: tr(s: "Chec&ked" ), object: this, slot: &TextEdit::setChecked); |
| 362 | actionToggleCheckState->setShortcut(Qt::CTRL + Qt::Key_K); |
| 363 | actionToggleCheckState->setCheckable(true); |
| 364 | actionToggleCheckState->setPriority(QAction::LowPriority); |
| 365 | tb->addAction(action: actionToggleCheckState); |
| 366 | |
| 367 | tb = addToolBar(title: tr(s: "Format Actions" )); |
| 368 | tb->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea); |
| 369 | addToolBarBreak(area: Qt::TopToolBarArea); |
| 370 | addToolBar(toolbar: tb); |
| 371 | |
| 372 | comboStyle = new QComboBox(tb); |
| 373 | tb->addWidget(widget: comboStyle); |
| 374 | comboStyle->addItem(atext: "Standard" ); |
| 375 | comboStyle->addItem(atext: "Bullet List (Disc)" ); |
| 376 | comboStyle->addItem(atext: "Bullet List (Circle)" ); |
| 377 | comboStyle->addItem(atext: "Bullet List (Square)" ); |
| 378 | comboStyle->addItem(atext: "Task List (Unchecked)" ); |
| 379 | comboStyle->addItem(atext: "Task List (Checked)" ); |
| 380 | comboStyle->addItem(atext: "Ordered List (Decimal)" ); |
| 381 | comboStyle->addItem(atext: "Ordered List (Alpha lower)" ); |
| 382 | comboStyle->addItem(atext: "Ordered List (Alpha upper)" ); |
| 383 | comboStyle->addItem(atext: "Ordered List (Roman lower)" ); |
| 384 | comboStyle->addItem(atext: "Ordered List (Roman upper)" ); |
| 385 | comboStyle->addItem(atext: "Heading 1" ); |
| 386 | comboStyle->addItem(atext: "Heading 2" ); |
| 387 | comboStyle->addItem(atext: "Heading 3" ); |
| 388 | comboStyle->addItem(atext: "Heading 4" ); |
| 389 | comboStyle->addItem(atext: "Heading 5" ); |
| 390 | comboStyle->addItem(atext: "Heading 6" ); |
| 391 | |
| 392 | connect(sender: comboStyle, signal: QOverload<int>::of(ptr: &QComboBox::activated), receiver: this, slot: &TextEdit::textStyle); |
| 393 | |
| 394 | comboFont = new QFontComboBox(tb); |
| 395 | tb->addWidget(widget: comboFont); |
| 396 | connect(sender: comboFont, signal: &QComboBox::textActivated, receiver: this, slot: &TextEdit::textFamily); |
| 397 | |
| 398 | comboSize = new QComboBox(tb); |
| 399 | comboSize->setObjectName("comboSize" ); |
| 400 | tb->addWidget(widget: comboSize); |
| 401 | comboSize->setEditable(true); |
| 402 | |
| 403 | const QList<int> standardSizes = QFontDatabase::standardSizes(); |
| 404 | for (int size : standardSizes) |
| 405 | comboSize->addItem(atext: QString::number(size)); |
| 406 | comboSize->setCurrentIndex(standardSizes.indexOf(t: QApplication::font().pointSize())); |
| 407 | |
| 408 | connect(sender: comboSize, signal: &QComboBox::textActivated, receiver: this, slot: &TextEdit::textSize); |
| 409 | } |
| 410 | |
| 411 | bool TextEdit::load(const QString &f) |
| 412 | { |
| 413 | if (!QFile::exists(fileName: f)) |
| 414 | return false; |
| 415 | QFile file(f); |
| 416 | if (!file.open(flags: QFile::ReadOnly)) |
| 417 | return false; |
| 418 | |
| 419 | QByteArray data = file.readAll(); |
| 420 | QTextCodec *codec = Qt::codecForHtml(ba: data); |
| 421 | QString str = codec->toUnicode(data); |
| 422 | if (Qt::mightBeRichText(str)) { |
| 423 | QUrl baseUrl = (f.front() == QLatin1Char(':') ? QUrl(f) : QUrl::fromLocalFile(localfile: f)).adjusted(options: QUrl::RemoveFilename); |
| 424 | textEdit->document()->setBaseUrl(baseUrl); |
| 425 | textEdit->setHtml(str); |
| 426 | } else { |
| 427 | #if QT_CONFIG(textmarkdownreader) |
| 428 | QMimeDatabase db; |
| 429 | if (db.mimeTypeForFileNameAndData(fileName: f, data).name() == QLatin1String("text/markdown" )) |
| 430 | textEdit->setMarkdown(QString::fromUtf8(str: data)); |
| 431 | else |
| 432 | #endif |
| 433 | textEdit->setPlainText(QString::fromUtf8(str: data)); |
| 434 | } |
| 435 | |
| 436 | setCurrentFileName(f); |
| 437 | return true; |
| 438 | } |
| 439 | |
| 440 | bool TextEdit::maybeSave() |
| 441 | { |
| 442 | if (!textEdit->document()->isModified()) |
| 443 | return true; |
| 444 | |
| 445 | const QMessageBox::StandardButton ret = |
| 446 | QMessageBox::warning(parent: this, title: QCoreApplication::applicationName(), |
| 447 | text: tr(s: "The document has been modified.\n" |
| 448 | "Do you want to save your changes?" ), |
| 449 | buttons: QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); |
| 450 | if (ret == QMessageBox::Save) |
| 451 | return fileSave(); |
| 452 | else if (ret == QMessageBox::Cancel) |
| 453 | return false; |
| 454 | return true; |
| 455 | } |
| 456 | |
| 457 | void TextEdit::setCurrentFileName(const QString &fileName) |
| 458 | { |
| 459 | this->fileName = fileName; |
| 460 | textEdit->document()->setModified(false); |
| 461 | |
| 462 | QString shownName; |
| 463 | if (fileName.isEmpty()) |
| 464 | shownName = "untitled.txt" ; |
| 465 | else |
| 466 | shownName = QFileInfo(fileName).fileName(); |
| 467 | |
| 468 | setWindowTitle(tr(s: "%1[*] - %2" ).arg(args&: shownName, args: QCoreApplication::applicationName())); |
| 469 | setWindowModified(false); |
| 470 | } |
| 471 | |
| 472 | void TextEdit::fileNew() |
| 473 | { |
| 474 | if (maybeSave()) { |
| 475 | textEdit->clear(); |
| 476 | setCurrentFileName(QString()); |
| 477 | } |
| 478 | } |
| 479 | |
| 480 | void TextEdit::fileOpen() |
| 481 | { |
| 482 | QFileDialog fileDialog(this, tr(s: "Open File..." )); |
| 483 | fileDialog.setAcceptMode(QFileDialog::AcceptOpen); |
| 484 | fileDialog.setFileMode(QFileDialog::ExistingFile); |
| 485 | fileDialog.setMimeTypeFilters(QStringList() |
| 486 | #if QT_CONFIG(texthtmlparser) |
| 487 | << "text/html" |
| 488 | #endif |
| 489 | #if QT_CONFIG(textmarkdownreader) |
| 490 | |
| 491 | << "text/markdown" |
| 492 | #endif |
| 493 | << "text/plain" ); |
| 494 | if (fileDialog.exec() != QDialog::Accepted) |
| 495 | return; |
| 496 | const QString fn = fileDialog.selectedFiles().first(); |
| 497 | if (load(f: fn)) |
| 498 | statusBar()->showMessage(text: tr(s: "Opened \"%1\"" ).arg(a: QDir::toNativeSeparators(pathName: fn))); |
| 499 | else |
| 500 | statusBar()->showMessage(text: tr(s: "Could not open \"%1\"" ).arg(a: QDir::toNativeSeparators(pathName: fn))); |
| 501 | } |
| 502 | |
| 503 | bool TextEdit::fileSave() |
| 504 | { |
| 505 | if (fileName.isEmpty()) |
| 506 | return fileSaveAs(); |
| 507 | if (fileName.startsWith(QStringLiteral(":/" ))) |
| 508 | return fileSaveAs(); |
| 509 | |
| 510 | QTextDocumentWriter writer(fileName); |
| 511 | bool success = writer.write(document: textEdit->document()); |
| 512 | if (success) { |
| 513 | textEdit->document()->setModified(false); |
| 514 | statusBar()->showMessage(text: tr(s: "Wrote \"%1\"" ).arg(a: QDir::toNativeSeparators(pathName: fileName))); |
| 515 | } else { |
| 516 | statusBar()->showMessage(text: tr(s: "Could not write to file \"%1\"" ) |
| 517 | .arg(a: QDir::toNativeSeparators(pathName: fileName))); |
| 518 | } |
| 519 | return success; |
| 520 | } |
| 521 | |
| 522 | bool TextEdit::fileSaveAs() |
| 523 | { |
| 524 | QFileDialog fileDialog(this, tr(s: "Save as..." )); |
| 525 | fileDialog.setAcceptMode(QFileDialog::AcceptSave); |
| 526 | QStringList mimeTypes; |
| 527 | mimeTypes << "text/plain" |
| 528 | #if QT_CONFIG(textodfwriter) |
| 529 | << "application/vnd.oasis.opendocument.text" |
| 530 | #endif |
| 531 | #if QT_CONFIG(textmarkdownwriter) |
| 532 | << "text/markdown" |
| 533 | #endif |
| 534 | << "text/html" ; |
| 535 | fileDialog.setMimeTypeFilters(mimeTypes); |
| 536 | #if QT_CONFIG(textodfwriter) |
| 537 | fileDialog.setDefaultSuffix("odt" ); |
| 538 | #endif |
| 539 | if (fileDialog.exec() != QDialog::Accepted) |
| 540 | return false; |
| 541 | const QString fn = fileDialog.selectedFiles().first(); |
| 542 | setCurrentFileName(fn); |
| 543 | return fileSave(); |
| 544 | } |
| 545 | |
| 546 | void TextEdit::filePrint() |
| 547 | { |
| 548 | #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog) |
| 549 | QPrinter printer(QPrinter::HighResolution); |
| 550 | QPrintDialog *dlg = new QPrintDialog(&printer, this); |
| 551 | if (textEdit->textCursor().hasSelection()) |
| 552 | dlg->addEnabledOption(option: QAbstractPrintDialog::PrintSelection); |
| 553 | dlg->setWindowTitle(tr(s: "Print Document" )); |
| 554 | if (dlg->exec() == QDialog::Accepted) |
| 555 | textEdit->print(printer: &printer); |
| 556 | delete dlg; |
| 557 | #endif |
| 558 | } |
| 559 | |
| 560 | void TextEdit::filePrintPreview() |
| 561 | { |
| 562 | #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printpreviewdialog) |
| 563 | QPrinter printer(QPrinter::HighResolution); |
| 564 | QPrintPreviewDialog preview(&printer, this); |
| 565 | connect(sender: &preview, signal: &QPrintPreviewDialog::paintRequested, receiver: this, slot: &TextEdit::printPreview); |
| 566 | preview.exec(); |
| 567 | #endif |
| 568 | } |
| 569 | |
| 570 | void TextEdit::printPreview(QPrinter *printer) |
| 571 | { |
| 572 | #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) |
| 573 | textEdit->print(printer); |
| 574 | #else |
| 575 | Q_UNUSED(printer) |
| 576 | #endif |
| 577 | } |
| 578 | |
| 579 | |
| 580 | void TextEdit::filePrintPdf() |
| 581 | { |
| 582 | #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) |
| 583 | //! [0] |
| 584 | QFileDialog fileDialog(this, tr(s: "Export PDF" )); |
| 585 | fileDialog.setAcceptMode(QFileDialog::AcceptSave); |
| 586 | fileDialog.setMimeTypeFilters(QStringList("application/pdf" )); |
| 587 | fileDialog.setDefaultSuffix("pdf" ); |
| 588 | if (fileDialog.exec() != QDialog::Accepted) |
| 589 | return; |
| 590 | QString fileName = fileDialog.selectedFiles().first(); |
| 591 | QPrinter printer(QPrinter::HighResolution); |
| 592 | printer.setOutputFormat(QPrinter::PdfFormat); |
| 593 | printer.setOutputFileName(fileName); |
| 594 | textEdit->document()->print(printer: &printer); |
| 595 | statusBar()->showMessage(text: tr(s: "Exported \"%1\"" ) |
| 596 | .arg(a: QDir::toNativeSeparators(pathName: fileName))); |
| 597 | //! [0] |
| 598 | #endif |
| 599 | } |
| 600 | |
| 601 | void TextEdit::textBold() |
| 602 | { |
| 603 | QTextCharFormat fmt; |
| 604 | fmt.setFontWeight(actionTextBold->isChecked() ? QFont::Bold : QFont::Normal); |
| 605 | mergeFormatOnWordOrSelection(format: fmt); |
| 606 | } |
| 607 | |
| 608 | void TextEdit::textUnderline() |
| 609 | { |
| 610 | QTextCharFormat fmt; |
| 611 | fmt.setFontUnderline(actionTextUnderline->isChecked()); |
| 612 | mergeFormatOnWordOrSelection(format: fmt); |
| 613 | } |
| 614 | |
| 615 | void TextEdit::textItalic() |
| 616 | { |
| 617 | QTextCharFormat fmt; |
| 618 | fmt.setFontItalic(actionTextItalic->isChecked()); |
| 619 | mergeFormatOnWordOrSelection(format: fmt); |
| 620 | } |
| 621 | |
| 622 | void TextEdit::textFamily(const QString &f) |
| 623 | { |
| 624 | QTextCharFormat fmt; |
| 625 | fmt.setFontFamily(f); |
| 626 | mergeFormatOnWordOrSelection(format: fmt); |
| 627 | } |
| 628 | |
| 629 | void TextEdit::textSize(const QString &p) |
| 630 | { |
| 631 | qreal pointSize = p.toFloat(); |
| 632 | if (p.toFloat() > 0) { |
| 633 | QTextCharFormat fmt; |
| 634 | fmt.setFontPointSize(pointSize); |
| 635 | mergeFormatOnWordOrSelection(format: fmt); |
| 636 | } |
| 637 | } |
| 638 | |
| 639 | void TextEdit::textStyle(int styleIndex) |
| 640 | { |
| 641 | QTextCursor cursor = textEdit->textCursor(); |
| 642 | QTextListFormat::Style style = QTextListFormat::ListStyleUndefined; |
| 643 | QTextBlockFormat::MarkerType marker = QTextBlockFormat::MarkerType::NoMarker; |
| 644 | |
| 645 | switch (styleIndex) { |
| 646 | case 1: |
| 647 | style = QTextListFormat::ListDisc; |
| 648 | break; |
| 649 | case 2: |
| 650 | style = QTextListFormat::ListCircle; |
| 651 | break; |
| 652 | case 3: |
| 653 | style = QTextListFormat::ListSquare; |
| 654 | break; |
| 655 | case 4: |
| 656 | if (cursor.currentList()) |
| 657 | style = cursor.currentList()->format().style(); |
| 658 | else |
| 659 | style = QTextListFormat::ListDisc; |
| 660 | marker = QTextBlockFormat::MarkerType::Unchecked; |
| 661 | break; |
| 662 | case 5: |
| 663 | if (cursor.currentList()) |
| 664 | style = cursor.currentList()->format().style(); |
| 665 | else |
| 666 | style = QTextListFormat::ListDisc; |
| 667 | marker = QTextBlockFormat::MarkerType::Checked; |
| 668 | break; |
| 669 | case 6: |
| 670 | style = QTextListFormat::ListDecimal; |
| 671 | break; |
| 672 | case 7: |
| 673 | style = QTextListFormat::ListLowerAlpha; |
| 674 | break; |
| 675 | case 8: |
| 676 | style = QTextListFormat::ListUpperAlpha; |
| 677 | break; |
| 678 | case 9: |
| 679 | style = QTextListFormat::ListLowerRoman; |
| 680 | break; |
| 681 | case 10: |
| 682 | style = QTextListFormat::ListUpperRoman; |
| 683 | break; |
| 684 | default: |
| 685 | break; |
| 686 | } |
| 687 | |
| 688 | cursor.beginEditBlock(); |
| 689 | |
| 690 | QTextBlockFormat blockFmt = cursor.blockFormat(); |
| 691 | |
| 692 | if (style == QTextListFormat::ListStyleUndefined) { |
| 693 | blockFmt.setObjectIndex(-1); |
| 694 | int headingLevel = styleIndex >= 11 ? styleIndex - 11 + 1 : 0; // H1 to H6, or Standard |
| 695 | blockFmt.setHeadingLevel(headingLevel); |
| 696 | cursor.setBlockFormat(blockFmt); |
| 697 | |
| 698 | int sizeAdjustment = headingLevel ? 4 - headingLevel : 0; // H1 to H6: +3 to -2 |
| 699 | QTextCharFormat fmt; |
| 700 | fmt.setFontWeight(headingLevel ? QFont::Bold : QFont::Normal); |
| 701 | fmt.setProperty(propertyId: QTextFormat::FontSizeAdjustment, value: sizeAdjustment); |
| 702 | cursor.select(selection: QTextCursor::LineUnderCursor); |
| 703 | cursor.mergeCharFormat(modifier: fmt); |
| 704 | textEdit->mergeCurrentCharFormat(modifier: fmt); |
| 705 | } else { |
| 706 | blockFmt.setMarker(marker); |
| 707 | cursor.setBlockFormat(blockFmt); |
| 708 | QTextListFormat listFmt; |
| 709 | if (cursor.currentList()) { |
| 710 | listFmt = cursor.currentList()->format(); |
| 711 | } else { |
| 712 | listFmt.setIndent(blockFmt.indent() + 1); |
| 713 | blockFmt.setIndent(0); |
| 714 | cursor.setBlockFormat(blockFmt); |
| 715 | } |
| 716 | listFmt.setStyle(style); |
| 717 | cursor.createList(format: listFmt); |
| 718 | } |
| 719 | |
| 720 | cursor.endEditBlock(); |
| 721 | } |
| 722 | |
| 723 | void TextEdit::textColor() |
| 724 | { |
| 725 | QColor col = QColorDialog::getColor(initial: textEdit->textColor(), parent: this); |
| 726 | if (!col.isValid()) |
| 727 | return; |
| 728 | QTextCharFormat fmt; |
| 729 | fmt.setForeground(col); |
| 730 | mergeFormatOnWordOrSelection(format: fmt); |
| 731 | colorChanged(c: col); |
| 732 | } |
| 733 | |
| 734 | void TextEdit::textAlign(QAction *a) |
| 735 | { |
| 736 | if (a == actionAlignLeft) |
| 737 | textEdit->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute); |
| 738 | else if (a == actionAlignCenter) |
| 739 | textEdit->setAlignment(Qt::AlignHCenter); |
| 740 | else if (a == actionAlignRight) |
| 741 | textEdit->setAlignment(Qt::AlignRight | Qt::AlignAbsolute); |
| 742 | else if (a == actionAlignJustify) |
| 743 | textEdit->setAlignment(Qt::AlignJustify); |
| 744 | } |
| 745 | |
| 746 | void TextEdit::setChecked(bool checked) |
| 747 | { |
| 748 | textStyle(styleIndex: checked ? 5 : 4); |
| 749 | } |
| 750 | |
| 751 | void TextEdit::indent() |
| 752 | { |
| 753 | modifyIndentation(amount: 1); |
| 754 | } |
| 755 | |
| 756 | void TextEdit::unindent() |
| 757 | { |
| 758 | modifyIndentation(amount: -1); |
| 759 | } |
| 760 | |
| 761 | void TextEdit::modifyIndentation(int amount) |
| 762 | { |
| 763 | QTextCursor cursor = textEdit->textCursor(); |
| 764 | cursor.beginEditBlock(); |
| 765 | if (cursor.currentList()) { |
| 766 | QTextListFormat listFmt = cursor.currentList()->format(); |
| 767 | // See whether the line above is the list we want to move this item into, |
| 768 | // or whether we need a new list. |
| 769 | QTextCursor above(cursor); |
| 770 | above.movePosition(op: QTextCursor::Up); |
| 771 | if (above.currentList() && listFmt.indent() + amount == above.currentList()->format().indent()) { |
| 772 | above.currentList()->add(block: cursor.block()); |
| 773 | } else { |
| 774 | listFmt.setIndent(listFmt.indent() + amount); |
| 775 | cursor.createList(format: listFmt); |
| 776 | } |
| 777 | } else { |
| 778 | QTextBlockFormat blockFmt = cursor.blockFormat(); |
| 779 | blockFmt.setIndent(blockFmt.indent() + amount); |
| 780 | cursor.setBlockFormat(blockFmt); |
| 781 | } |
| 782 | cursor.endEditBlock(); |
| 783 | } |
| 784 | |
| 785 | void TextEdit::currentCharFormatChanged(const QTextCharFormat &format) |
| 786 | { |
| 787 | fontChanged(f: format.font()); |
| 788 | colorChanged(c: format.foreground().color()); |
| 789 | } |
| 790 | |
| 791 | void TextEdit::cursorPositionChanged() |
| 792 | { |
| 793 | alignmentChanged(a: textEdit->alignment()); |
| 794 | QTextList *list = textEdit->textCursor().currentList(); |
| 795 | if (list) { |
| 796 | switch (list->format().style()) { |
| 797 | case QTextListFormat::ListDisc: |
| 798 | comboStyle->setCurrentIndex(1); |
| 799 | break; |
| 800 | case QTextListFormat::ListCircle: |
| 801 | comboStyle->setCurrentIndex(2); |
| 802 | break; |
| 803 | case QTextListFormat::ListSquare: |
| 804 | comboStyle->setCurrentIndex(3); |
| 805 | break; |
| 806 | case QTextListFormat::ListDecimal: |
| 807 | comboStyle->setCurrentIndex(6); |
| 808 | break; |
| 809 | case QTextListFormat::ListLowerAlpha: |
| 810 | comboStyle->setCurrentIndex(7); |
| 811 | break; |
| 812 | case QTextListFormat::ListUpperAlpha: |
| 813 | comboStyle->setCurrentIndex(8); |
| 814 | break; |
| 815 | case QTextListFormat::ListLowerRoman: |
| 816 | comboStyle->setCurrentIndex(9); |
| 817 | break; |
| 818 | case QTextListFormat::ListUpperRoman: |
| 819 | comboStyle->setCurrentIndex(10); |
| 820 | break; |
| 821 | default: |
| 822 | comboStyle->setCurrentIndex(-1); |
| 823 | break; |
| 824 | } |
| 825 | switch (textEdit->textCursor().block().blockFormat().marker()) { |
| 826 | case QTextBlockFormat::MarkerType::NoMarker: |
| 827 | actionToggleCheckState->setChecked(false); |
| 828 | break; |
| 829 | case QTextBlockFormat::MarkerType::Unchecked: |
| 830 | comboStyle->setCurrentIndex(4); |
| 831 | actionToggleCheckState->setChecked(false); |
| 832 | break; |
| 833 | case QTextBlockFormat::MarkerType::Checked: |
| 834 | comboStyle->setCurrentIndex(5); |
| 835 | actionToggleCheckState->setChecked(true); |
| 836 | break; |
| 837 | } |
| 838 | } else { |
| 839 | int headingLevel = textEdit->textCursor().blockFormat().headingLevel(); |
| 840 | comboStyle->setCurrentIndex(headingLevel ? headingLevel + 10 : 0); |
| 841 | } |
| 842 | } |
| 843 | |
| 844 | void TextEdit::clipboardDataChanged() |
| 845 | { |
| 846 | #ifndef QT_NO_CLIPBOARD |
| 847 | if (const QMimeData *md = QApplication::clipboard()->mimeData()) |
| 848 | actionPaste->setEnabled(md->hasText()); |
| 849 | #endif |
| 850 | } |
| 851 | |
| 852 | void TextEdit::about() |
| 853 | { |
| 854 | QMessageBox::about(parent: this, title: tr(s: "About" ), text: tr(s: "This example demonstrates Qt's " |
| 855 | "rich text editing facilities in action, providing an example " |
| 856 | "document for you to experiment with." )); |
| 857 | } |
| 858 | |
| 859 | void TextEdit::mergeFormatOnWordOrSelection(const QTextCharFormat &format) |
| 860 | { |
| 861 | QTextCursor cursor = textEdit->textCursor(); |
| 862 | if (!cursor.hasSelection()) |
| 863 | cursor.select(selection: QTextCursor::WordUnderCursor); |
| 864 | cursor.mergeCharFormat(modifier: format); |
| 865 | textEdit->mergeCurrentCharFormat(modifier: format); |
| 866 | } |
| 867 | |
| 868 | void TextEdit::fontChanged(const QFont &f) |
| 869 | { |
| 870 | comboFont->setCurrentIndex(comboFont->findText(text: QFontInfo(f).family())); |
| 871 | comboSize->setCurrentIndex(comboSize->findText(text: QString::number(f.pointSize()))); |
| 872 | actionTextBold->setChecked(f.bold()); |
| 873 | actionTextItalic->setChecked(f.italic()); |
| 874 | actionTextUnderline->setChecked(f.underline()); |
| 875 | } |
| 876 | |
| 877 | void TextEdit::colorChanged(const QColor &c) |
| 878 | { |
| 879 | QPixmap pix(16, 16); |
| 880 | pix.fill(fillColor: c); |
| 881 | actionTextColor->setIcon(pix); |
| 882 | } |
| 883 | |
| 884 | void TextEdit::alignmentChanged(Qt::Alignment a) |
| 885 | { |
| 886 | if (a & Qt::AlignLeft) |
| 887 | actionAlignLeft->setChecked(true); |
| 888 | else if (a & Qt::AlignHCenter) |
| 889 | actionAlignCenter->setChecked(true); |
| 890 | else if (a & Qt::AlignRight) |
| 891 | actionAlignRight->setChecked(true); |
| 892 | else if (a & Qt::AlignJustify) |
| 893 | actionAlignJustify->setChecked(true); |
| 894 | } |
| 895 | |
| 896 | |