1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the Qt Designer of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "richtexteditor_p.h"
|
---|
43 | #include "htmlhighlighter_p.h"
|
---|
44 | #include "iconselector_p.h"
|
---|
45 | #include "ui_addlinkdialog.h"
|
---|
46 | #include "abstractsettings_p.h"
|
---|
47 |
|
---|
48 | #include "iconloader_p.h"
|
---|
49 |
|
---|
50 | #include <QtDesigner/QDesignerFormEditorInterface>
|
---|
51 |
|
---|
52 | #include <QtCore/QList>
|
---|
53 | #include <QtCore/QMap>
|
---|
54 | #include <QtCore/QPointer>
|
---|
55 |
|
---|
56 | #include <QtGui/QAction>
|
---|
57 | #include <QtGui/QColorDialog>
|
---|
58 | #include <QtGui/QComboBox>
|
---|
59 | #include <QtGui/QFontDatabase>
|
---|
60 | #include <QtGui/QTextCursor>
|
---|
61 | #include <QtGui/QPainter>
|
---|
62 | #include <QtGui/QIcon>
|
---|
63 | #include <QtGui/QMenu>
|
---|
64 | #include <QtGui/QMoveEvent>
|
---|
65 | #include <QtGui/QTabWidget>
|
---|
66 | #include <QtGui/QTextDocument>
|
---|
67 | #include <QtGui/QTextBlock>
|
---|
68 | #include <QtGui/QToolBar>
|
---|
69 | #include <QtGui/QToolButton>
|
---|
70 | #include <QtGui/QVBoxLayout>
|
---|
71 | #include <QtGui/QHBoxLayout>
|
---|
72 | #include <QtGui/QPushButton>
|
---|
73 | #include <QtGui/QDialogButtonBox>
|
---|
74 |
|
---|
75 | QT_BEGIN_NAMESPACE
|
---|
76 |
|
---|
77 | static const char *RichTextDialogC = "RichTextDialog";
|
---|
78 | static const char *Geometry = "Geometry";
|
---|
79 |
|
---|
80 | namespace qdesigner_internal {
|
---|
81 |
|
---|
82 | class RichTextEditor : public QTextEdit
|
---|
83 | {
|
---|
84 | Q_OBJECT
|
---|
85 | public:
|
---|
86 | RichTextEditor(QWidget *parent = 0);
|
---|
87 | void setDefaultFont(const QFont &font);
|
---|
88 |
|
---|
89 | QToolBar *createToolBar(QDesignerFormEditorInterface *core, QWidget *parent = 0);
|
---|
90 |
|
---|
91 | public slots:
|
---|
92 | void setFontBold(bool b);
|
---|
93 | void setFontPointSize(double);
|
---|
94 | void setText(const QString &text);
|
---|
95 | QString text(Qt::TextFormat format) const;
|
---|
96 |
|
---|
97 | signals:
|
---|
98 | void stateChanged();
|
---|
99 | };
|
---|
100 |
|
---|
101 | class AddLinkDialog : public QDialog
|
---|
102 | {
|
---|
103 | Q_OBJECT
|
---|
104 |
|
---|
105 | public:
|
---|
106 | AddLinkDialog(RichTextEditor *editor, QWidget *parent = 0);
|
---|
107 | ~AddLinkDialog();
|
---|
108 |
|
---|
109 | int showDialog();
|
---|
110 |
|
---|
111 | public slots:
|
---|
112 | void accept();
|
---|
113 |
|
---|
114 | private:
|
---|
115 | RichTextEditor *m_editor;
|
---|
116 | Ui::AddLinkDialog *m_ui;
|
---|
117 | };
|
---|
118 |
|
---|
119 | AddLinkDialog::AddLinkDialog(RichTextEditor *editor, QWidget *parent) :
|
---|
120 | QDialog(parent),
|
---|
121 | m_ui(new Ui::AddLinkDialog)
|
---|
122 | {
|
---|
123 | m_ui->setupUi(this);
|
---|
124 |
|
---|
125 | setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
---|
126 |
|
---|
127 | m_editor = editor;
|
---|
128 | }
|
---|
129 |
|
---|
130 | AddLinkDialog::~AddLinkDialog()
|
---|
131 | {
|
---|
132 | delete m_ui;
|
---|
133 | }
|
---|
134 |
|
---|
135 | int AddLinkDialog::showDialog()
|
---|
136 | {
|
---|
137 | // Set initial focus
|
---|
138 | const QTextCursor cursor = m_editor->textCursor();
|
---|
139 | if (cursor.hasSelection()) {
|
---|
140 | m_ui->titleInput->setText(cursor.selectedText());
|
---|
141 | m_ui->urlInput->setFocus();
|
---|
142 | } else {
|
---|
143 | m_ui->titleInput->setFocus();
|
---|
144 | }
|
---|
145 |
|
---|
146 | return exec();
|
---|
147 | }
|
---|
148 |
|
---|
149 | void AddLinkDialog::accept()
|
---|
150 | {
|
---|
151 | const QString title = m_ui->titleInput->text();
|
---|
152 | const QString url = m_ui->urlInput->text();
|
---|
153 |
|
---|
154 | if (!title.isEmpty()) {
|
---|
155 | QString html = QLatin1String("<a href=\"");
|
---|
156 | html += url;
|
---|
157 | html += QLatin1String("\">");
|
---|
158 | html += title;
|
---|
159 | html += QLatin1String("</a>");
|
---|
160 |
|
---|
161 | m_editor->insertHtml(html);
|
---|
162 | }
|
---|
163 |
|
---|
164 | m_ui->titleInput->clear();
|
---|
165 | m_ui->urlInput->clear();
|
---|
166 |
|
---|
167 | QDialog::accept();
|
---|
168 | }
|
---|
169 |
|
---|
170 | class HtmlTextEdit : public QTextEdit
|
---|
171 | {
|
---|
172 | Q_OBJECT
|
---|
173 |
|
---|
174 | public:
|
---|
175 | HtmlTextEdit(QWidget *parent = 0)
|
---|
176 | : QTextEdit(parent)
|
---|
177 | {}
|
---|
178 |
|
---|
179 | void contextMenuEvent(QContextMenuEvent *event);
|
---|
180 |
|
---|
181 | private slots:
|
---|
182 | void actionTriggered(QAction *action);
|
---|
183 | };
|
---|
184 |
|
---|
185 | void HtmlTextEdit::contextMenuEvent(QContextMenuEvent *event)
|
---|
186 | {
|
---|
187 | QMenu *menu = createStandardContextMenu();
|
---|
188 | QMenu *htmlMenu = new QMenu(tr("Insert HTML entity"), menu);
|
---|
189 |
|
---|
190 | typedef struct {
|
---|
191 | const char *text;
|
---|
192 | const char *entity;
|
---|
193 | } Entry;
|
---|
194 |
|
---|
195 | const Entry entries[] = {
|
---|
196 | { "&& (&&)", "&" },
|
---|
197 | { "& ", " " },
|
---|
198 | { "&< (<)", "<" },
|
---|
199 | { "&> (>)", ">" },
|
---|
200 | { "&© (Copyright)", "©" },
|
---|
201 | { "&® (Trade Mark)", "®" },
|
---|
202 | };
|
---|
203 |
|
---|
204 | for (int i = 0; i < 6; ++i) {
|
---|
205 | QAction *entityAction = new QAction(QLatin1String(entries[i].text),
|
---|
206 | htmlMenu);
|
---|
207 | entityAction->setData(QLatin1String(entries[i].entity));
|
---|
208 | htmlMenu->addAction(entityAction);
|
---|
209 | }
|
---|
210 |
|
---|
211 | menu->addMenu(htmlMenu);
|
---|
212 | connect(htmlMenu, SIGNAL(triggered(QAction*)),
|
---|
213 | SLOT(actionTriggered(QAction*)));
|
---|
214 | menu->exec(event->globalPos());
|
---|
215 | delete menu;
|
---|
216 | }
|
---|
217 |
|
---|
218 | void HtmlTextEdit::actionTriggered(QAction *action)
|
---|
219 | {
|
---|
220 | insertPlainText(action->data().toString());
|
---|
221 | }
|
---|
222 |
|
---|
223 | class ColorAction : public QAction
|
---|
224 | {
|
---|
225 | Q_OBJECT
|
---|
226 |
|
---|
227 | public:
|
---|
228 | ColorAction(QObject *parent);
|
---|
229 |
|
---|
230 | const QColor& color() const { return m_color; }
|
---|
231 | void setColor(const QColor &color);
|
---|
232 |
|
---|
233 | signals:
|
---|
234 | void colorChanged(const QColor &color);
|
---|
235 |
|
---|
236 | private slots:
|
---|
237 | void chooseColor();
|
---|
238 |
|
---|
239 | private:
|
---|
240 | QColor m_color;
|
---|
241 | };
|
---|
242 |
|
---|
243 | ColorAction::ColorAction(QObject *parent):
|
---|
244 | QAction(parent)
|
---|
245 | {
|
---|
246 | setText(tr("Text Color"));
|
---|
247 | setColor(Qt::black);
|
---|
248 | connect(this, SIGNAL(triggered()), this, SLOT(chooseColor()));
|
---|
249 | }
|
---|
250 |
|
---|
251 | void ColorAction::setColor(const QColor &color)
|
---|
252 | {
|
---|
253 | if (color == m_color)
|
---|
254 | return;
|
---|
255 | m_color = color;
|
---|
256 | QPixmap pix(24, 24);
|
---|
257 | QPainter painter(&pix);
|
---|
258 | painter.setRenderHint(QPainter::Antialiasing, false);
|
---|
259 | painter.fillRect(pix.rect(), m_color);
|
---|
260 | painter.setPen(m_color.darker());
|
---|
261 | painter.drawRect(pix.rect().adjusted(0, 0, -1, -1));
|
---|
262 | setIcon(pix);
|
---|
263 | }
|
---|
264 |
|
---|
265 | void ColorAction::chooseColor()
|
---|
266 | {
|
---|
267 | const QColor col = QColorDialog::getColor(m_color, 0);
|
---|
268 | if (col.isValid() && col != m_color) {
|
---|
269 | setColor(col);
|
---|
270 | emit colorChanged(m_color);
|
---|
271 | }
|
---|
272 | }
|
---|
273 |
|
---|
274 | class RichTextEditorToolBar : public QToolBar
|
---|
275 | {
|
---|
276 | Q_OBJECT
|
---|
277 | public:
|
---|
278 | RichTextEditorToolBar(QDesignerFormEditorInterface *core,
|
---|
279 | RichTextEditor *editor,
|
---|
280 | QWidget *parent = 0);
|
---|
281 |
|
---|
282 | public slots:
|
---|
283 | void updateActions();
|
---|
284 |
|
---|
285 | private slots:
|
---|
286 | void alignmentActionTriggered(QAction *action);
|
---|
287 | void sizeInputActivated(const QString &size);
|
---|
288 | void colorChanged(const QColor &color);
|
---|
289 | void setVAlignSuper(bool super);
|
---|
290 | void setVAlignSub(bool sub);
|
---|
291 | void insertLink();
|
---|
292 | void insertImage();
|
---|
293 |
|
---|
294 | private:
|
---|
295 | QAction *m_bold_action;
|
---|
296 | QAction *m_italic_action;
|
---|
297 | QAction *m_underline_action;
|
---|
298 | QAction *m_valign_sup_action;
|
---|
299 | QAction *m_valign_sub_action;
|
---|
300 | QAction *m_align_left_action;
|
---|
301 | QAction *m_align_center_action;
|
---|
302 | QAction *m_align_right_action;
|
---|
303 | QAction *m_align_justify_action;
|
---|
304 | QAction *m_link_action;
|
---|
305 | QAction *m_image_action;
|
---|
306 | ColorAction *m_color_action;
|
---|
307 | QComboBox *m_font_size_input;
|
---|
308 |
|
---|
309 | QDesignerFormEditorInterface *m_core;
|
---|
310 | QPointer<RichTextEditor> m_editor;
|
---|
311 | };
|
---|
312 |
|
---|
313 | static QAction *createCheckableAction(const QIcon &icon, const QString &text,
|
---|
314 | QObject *receiver, const char *slot,
|
---|
315 | QObject *parent = 0)
|
---|
316 | {
|
---|
317 | QAction *result = new QAction(parent);
|
---|
318 | result->setIcon(icon);
|
---|
319 | result->setText(text);
|
---|
320 | result->setCheckable(true);
|
---|
321 | result->setChecked(false);
|
---|
322 | if (slot)
|
---|
323 | QObject::connect(result, SIGNAL(triggered(bool)), receiver, slot);
|
---|
324 | return result;
|
---|
325 | }
|
---|
326 |
|
---|
327 | RichTextEditorToolBar::RichTextEditorToolBar(QDesignerFormEditorInterface *core,
|
---|
328 | RichTextEditor *editor,
|
---|
329 | QWidget *parent) :
|
---|
330 | QToolBar(parent),
|
---|
331 | m_link_action(new QAction(this)),
|
---|
332 | m_image_action(new QAction(this)),
|
---|
333 | m_color_action(new ColorAction(this)),
|
---|
334 | m_font_size_input(new QComboBox),
|
---|
335 | m_core(core),
|
---|
336 | m_editor(editor)
|
---|
337 | {
|
---|
338 | // Font size combo box
|
---|
339 | m_font_size_input->setEditable(false);
|
---|
340 | const QList<int> font_sizes = QFontDatabase::standardSizes();
|
---|
341 | foreach (int font_size, font_sizes)
|
---|
342 | m_font_size_input->addItem(QString::number(font_size));
|
---|
343 |
|
---|
344 | connect(m_font_size_input, SIGNAL(activated(QString)),
|
---|
345 | this, SLOT(sizeInputActivated(QString)));
|
---|
346 | addWidget(m_font_size_input);
|
---|
347 |
|
---|
348 | addSeparator();
|
---|
349 |
|
---|
350 | // Bold, italic and underline buttons
|
---|
351 |
|
---|
352 | m_bold_action = createCheckableAction(
|
---|
353 | createIconSet(QLatin1String("textbold.png")),
|
---|
354 | tr("Bold"), editor, SLOT(setFontBold(bool)), this);
|
---|
355 | m_bold_action->setShortcut(tr("CTRL+B"));
|
---|
356 | addAction(m_bold_action);
|
---|
357 |
|
---|
358 | m_italic_action = createCheckableAction(
|
---|
359 | createIconSet(QLatin1String("textitalic.png")),
|
---|
360 | tr("Italic"), editor, SLOT(setFontItalic(bool)), this);
|
---|
361 | m_italic_action->setShortcut(tr("CTRL+I"));
|
---|
362 | addAction(m_italic_action);
|
---|
363 |
|
---|
364 | m_underline_action = createCheckableAction(
|
---|
365 | createIconSet(QLatin1String("textunder.png")),
|
---|
366 | tr("Underline"), editor, SLOT(setFontUnderline(bool)), this);
|
---|
367 | m_underline_action->setShortcut(tr("CTRL+U"));
|
---|
368 | addAction(m_underline_action);
|
---|
369 |
|
---|
370 | addSeparator();
|
---|
371 |
|
---|
372 | // Left, center, right and justified alignment buttons
|
---|
373 |
|
---|
374 | QActionGroup *alignment_group = new QActionGroup(this);
|
---|
375 | connect(alignment_group, SIGNAL(triggered(QAction*)),
|
---|
376 | SLOT(alignmentActionTriggered(QAction*)));
|
---|
377 |
|
---|
378 | m_align_left_action = createCheckableAction(
|
---|
379 | createIconSet(QLatin1String("textleft.png")),
|
---|
380 | tr("Left Align"), editor, 0, alignment_group);
|
---|
381 | addAction(m_align_left_action);
|
---|
382 |
|
---|
383 | m_align_center_action = createCheckableAction(
|
---|
384 | createIconSet(QLatin1String("textcenter.png")),
|
---|
385 | tr("Center"), editor, 0, alignment_group);
|
---|
386 | addAction(m_align_center_action);
|
---|
387 |
|
---|
388 | m_align_right_action = createCheckableAction(
|
---|
389 | createIconSet(QLatin1String("textright.png")),
|
---|
390 | tr("Right Align"), editor, 0, alignment_group);
|
---|
391 | addAction(m_align_right_action);
|
---|
392 |
|
---|
393 | m_align_justify_action = createCheckableAction(
|
---|
394 | createIconSet(QLatin1String("textjustify.png")),
|
---|
395 | tr("Justify"), editor, 0, alignment_group);
|
---|
396 | addAction(m_align_justify_action);
|
---|
397 |
|
---|
398 | addSeparator();
|
---|
399 |
|
---|
400 | // Superscript and subscript buttons
|
---|
401 |
|
---|
402 | m_valign_sup_action = createCheckableAction(
|
---|
403 | createIconSet(QLatin1String("textsuperscript.png")),
|
---|
404 | tr("Superscript"),
|
---|
405 | this, SLOT(setVAlignSuper(bool)), this);
|
---|
406 | addAction(m_valign_sup_action);
|
---|
407 |
|
---|
408 | m_valign_sub_action = createCheckableAction(
|
---|
409 | createIconSet(QLatin1String("textsubscript.png")),
|
---|
410 | tr("Subscript"),
|
---|
411 | this, SLOT(setVAlignSub(bool)), this);
|
---|
412 | addAction(m_valign_sub_action);
|
---|
413 |
|
---|
414 | addSeparator();
|
---|
415 |
|
---|
416 | // Insert hyperlink and image buttons
|
---|
417 |
|
---|
418 | m_link_action->setIcon(createIconSet(QLatin1String("textanchor.png")));
|
---|
419 | m_link_action->setText(tr("Insert &Link"));
|
---|
420 | connect(m_link_action, SIGNAL(triggered()), SLOT(insertLink()));
|
---|
421 | addAction(m_link_action);
|
---|
422 |
|
---|
423 | m_image_action->setIcon(createIconSet(QLatin1String("insertimage.png")));
|
---|
424 | m_image_action->setText(tr("Insert &Image"));
|
---|
425 | connect(m_image_action, SIGNAL(triggered()), SLOT(insertImage()));
|
---|
426 | addAction(m_image_action);
|
---|
427 |
|
---|
428 | addSeparator();
|
---|
429 |
|
---|
430 | // Text color button
|
---|
431 | connect(m_color_action, SIGNAL(colorChanged(QColor)),
|
---|
432 | this, SLOT(colorChanged(QColor)));
|
---|
433 | addAction(m_color_action);
|
---|
434 |
|
---|
435 | connect(editor, SIGNAL(textChanged()), this, SLOT(updateActions()));
|
---|
436 | connect(editor, SIGNAL(stateChanged()), this, SLOT(updateActions()));
|
---|
437 |
|
---|
438 | updateActions();
|
---|
439 | }
|
---|
440 |
|
---|
441 | void RichTextEditorToolBar::alignmentActionTriggered(QAction *action)
|
---|
442 | {
|
---|
443 | Qt::Alignment new_alignment;
|
---|
444 |
|
---|
445 | if (action == m_align_left_action) {
|
---|
446 | new_alignment = Qt::AlignLeft;
|
---|
447 | } else if (action == m_align_center_action) {
|
---|
448 | new_alignment = Qt::AlignCenter;
|
---|
449 | } else if (action == m_align_right_action) {
|
---|
450 | new_alignment = Qt::AlignRight;
|
---|
451 | } else {
|
---|
452 | new_alignment = Qt::AlignJustify;
|
---|
453 | }
|
---|
454 |
|
---|
455 | m_editor->setAlignment(new_alignment);
|
---|
456 | }
|
---|
457 |
|
---|
458 | void RichTextEditorToolBar::colorChanged(const QColor &color)
|
---|
459 | {
|
---|
460 | m_editor->setTextColor(color);
|
---|
461 | m_editor->setFocus();
|
---|
462 | }
|
---|
463 |
|
---|
464 | void RichTextEditorToolBar::sizeInputActivated(const QString &size)
|
---|
465 | {
|
---|
466 | bool ok;
|
---|
467 | int i = size.toInt(&ok);
|
---|
468 | if (!ok)
|
---|
469 | return;
|
---|
470 |
|
---|
471 | m_editor->setFontPointSize(i);
|
---|
472 | m_editor->setFocus();
|
---|
473 | }
|
---|
474 |
|
---|
475 | void RichTextEditorToolBar::setVAlignSuper(bool super)
|
---|
476 | {
|
---|
477 | const QTextCharFormat::VerticalAlignment align = super ?
|
---|
478 | QTextCharFormat::AlignSuperScript : QTextCharFormat::AlignNormal;
|
---|
479 |
|
---|
480 | QTextCharFormat charFormat = m_editor->currentCharFormat();
|
---|
481 | charFormat.setVerticalAlignment(align);
|
---|
482 | m_editor->setCurrentCharFormat(charFormat);
|
---|
483 |
|
---|
484 | m_valign_sub_action->setChecked(false);
|
---|
485 | }
|
---|
486 |
|
---|
487 | void RichTextEditorToolBar::setVAlignSub(bool sub)
|
---|
488 | {
|
---|
489 | const QTextCharFormat::VerticalAlignment align = sub ?
|
---|
490 | QTextCharFormat::AlignSubScript : QTextCharFormat::AlignNormal;
|
---|
491 |
|
---|
492 | QTextCharFormat charFormat = m_editor->currentCharFormat();
|
---|
493 | charFormat.setVerticalAlignment(align);
|
---|
494 | m_editor->setCurrentCharFormat(charFormat);
|
---|
495 |
|
---|
496 | m_valign_sup_action->setChecked(false);
|
---|
497 | }
|
---|
498 |
|
---|
499 | void RichTextEditorToolBar::insertLink()
|
---|
500 | {
|
---|
501 | AddLinkDialog linkDialog(m_editor, this);
|
---|
502 | linkDialog.showDialog();
|
---|
503 | m_editor->setFocus();
|
---|
504 | }
|
---|
505 |
|
---|
506 | void RichTextEditorToolBar::insertImage()
|
---|
507 | {
|
---|
508 | const QString path = IconSelector::choosePixmapResource(m_core, m_core->resourceModel(), QString(), this);
|
---|
509 | if (!path.isEmpty())
|
---|
510 | m_editor->insertHtml(QLatin1String("<img src=\"") + path + QLatin1String("\"/>"));
|
---|
511 | }
|
---|
512 |
|
---|
513 | void RichTextEditorToolBar::updateActions()
|
---|
514 | {
|
---|
515 | if (m_editor == 0) {
|
---|
516 | setEnabled(false);
|
---|
517 | return;
|
---|
518 | }
|
---|
519 |
|
---|
520 | const Qt::Alignment alignment = m_editor->alignment();
|
---|
521 | const QTextCursor cursor = m_editor->textCursor();
|
---|
522 | const QTextCharFormat charFormat = cursor.charFormat();
|
---|
523 | const QFont font = charFormat.font();
|
---|
524 | const QTextCharFormat::VerticalAlignment valign =
|
---|
525 | charFormat.verticalAlignment();
|
---|
526 | const bool superScript = valign == QTextCharFormat::AlignSuperScript;
|
---|
527 | const bool subScript = valign == QTextCharFormat::AlignSubScript;
|
---|
528 |
|
---|
529 | if (alignment & Qt::AlignLeft) {
|
---|
530 | m_align_left_action->setChecked(true);
|
---|
531 | } else if (alignment & Qt::AlignRight) {
|
---|
532 | m_align_right_action->setChecked(true);
|
---|
533 | } else if (alignment & Qt::AlignHCenter) {
|
---|
534 | m_align_center_action->setChecked(true);
|
---|
535 | } else {
|
---|
536 | m_align_justify_action->setChecked(true);
|
---|
537 | }
|
---|
538 |
|
---|
539 | m_bold_action->setChecked(font.bold());
|
---|
540 | m_italic_action->setChecked(font.italic());
|
---|
541 | m_underline_action->setChecked(font.underline());
|
---|
542 | m_valign_sup_action->setChecked(superScript);
|
---|
543 | m_valign_sub_action->setChecked(subScript);
|
---|
544 |
|
---|
545 | const int size = font.pointSize();
|
---|
546 | const int idx = m_font_size_input->findText(QString::number(size));
|
---|
547 | if (idx != -1)
|
---|
548 | m_font_size_input->setCurrentIndex(idx);
|
---|
549 |
|
---|
550 | m_color_action->setColor(m_editor->textColor());
|
---|
551 | }
|
---|
552 |
|
---|
553 | RichTextEditor::RichTextEditor(QWidget *parent)
|
---|
554 | : QTextEdit(parent)
|
---|
555 | {
|
---|
556 | connect(this, SIGNAL(currentCharFormatChanged(QTextCharFormat)),
|
---|
557 | this, SIGNAL(stateChanged()));
|
---|
558 | connect(this, SIGNAL(cursorPositionChanged()),
|
---|
559 | this, SIGNAL(stateChanged()));
|
---|
560 | }
|
---|
561 |
|
---|
562 | QToolBar *RichTextEditor::createToolBar(QDesignerFormEditorInterface *core, QWidget *parent)
|
---|
563 | {
|
---|
564 | return new RichTextEditorToolBar(core, this, parent);
|
---|
565 | }
|
---|
566 |
|
---|
567 | void RichTextEditor::setFontBold(bool b)
|
---|
568 | {
|
---|
569 | if (b)
|
---|
570 | setFontWeight(QFont::Bold);
|
---|
571 | else
|
---|
572 | setFontWeight(QFont::Normal);
|
---|
573 | }
|
---|
574 |
|
---|
575 | void RichTextEditor::setFontPointSize(double d)
|
---|
576 | {
|
---|
577 | QTextEdit::setFontPointSize(qreal(d));
|
---|
578 | }
|
---|
579 |
|
---|
580 | void RichTextEditor::setText(const QString &text)
|
---|
581 | {
|
---|
582 | if (Qt::mightBeRichText(text))
|
---|
583 | setHtml(text);
|
---|
584 | else
|
---|
585 | setPlainText(text);
|
---|
586 | }
|
---|
587 |
|
---|
588 | void RichTextEditor::setDefaultFont(const QFont &font)
|
---|
589 | {
|
---|
590 | document()->setDefaultFont(font);
|
---|
591 | if (font.pointSize() > 0)
|
---|
592 | setFontPointSize(font.pointSize());
|
---|
593 | else
|
---|
594 | setFontPointSize(QFontInfo(font).pointSize());
|
---|
595 | emit textChanged();
|
---|
596 | }
|
---|
597 |
|
---|
598 | QString RichTextEditor::text(Qt::TextFormat format) const
|
---|
599 | {
|
---|
600 | switch (format) {
|
---|
601 | case Qt::LogText:
|
---|
602 | case Qt::PlainText:
|
---|
603 | return toPlainText();
|
---|
604 | case Qt::RichText:
|
---|
605 | return toHtml();
|
---|
606 | case Qt::AutoText:
|
---|
607 | break;
|
---|
608 | }
|
---|
609 | const QString html = toHtml();
|
---|
610 | const QString plain = toPlainText();
|
---|
611 | QTextEdit tester;
|
---|
612 | tester.setPlainText(plain);
|
---|
613 | return tester.toHtml() == html ? plain : html;
|
---|
614 | }
|
---|
615 |
|
---|
616 | RichTextEditorDialog::RichTextEditorDialog(QDesignerFormEditorInterface *core, QWidget *parent) :
|
---|
617 | QDialog(parent),
|
---|
618 | m_editor(new RichTextEditor()),
|
---|
619 | m_text_edit(new HtmlTextEdit),
|
---|
620 | m_tab_widget(new QTabWidget),
|
---|
621 | m_state(Clean),
|
---|
622 | m_core(core)
|
---|
623 | {
|
---|
624 | setWindowTitle(tr("Edit text"));
|
---|
625 | setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
---|
626 |
|
---|
627 | m_text_edit->setAcceptRichText(false);
|
---|
628 | new HtmlHighlighter(m_text_edit);
|
---|
629 |
|
---|
630 | connect(m_editor, SIGNAL(textChanged()), this, SLOT(richTextChanged()));
|
---|
631 | connect(m_text_edit, SIGNAL(textChanged()), this, SLOT(sourceChanged()));
|
---|
632 |
|
---|
633 | // The toolbar needs to be created after the RichTextEditor
|
---|
634 | QToolBar *tool_bar = m_editor->createToolBar(core);
|
---|
635 | tool_bar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
---|
636 |
|
---|
637 | QWidget *rich_edit = new QWidget;
|
---|
638 | QVBoxLayout *rich_edit_layout = new QVBoxLayout(rich_edit);
|
---|
639 | rich_edit_layout->addWidget(tool_bar);
|
---|
640 | rich_edit_layout->addWidget(m_editor);
|
---|
641 |
|
---|
642 | QWidget *plain_edit = new QWidget;
|
---|
643 | QVBoxLayout *plain_edit_layout = new QVBoxLayout(plain_edit);
|
---|
644 | plain_edit_layout->addWidget(m_text_edit);
|
---|
645 |
|
---|
646 | m_tab_widget->setTabPosition(QTabWidget::South);
|
---|
647 | m_tab_widget->addTab(rich_edit, tr("Rich Text"));
|
---|
648 | m_tab_widget->addTab(plain_edit, tr("Source"));
|
---|
649 | connect(m_tab_widget, SIGNAL(currentChanged(int)),
|
---|
650 | SLOT(tabIndexChanged(int)));
|
---|
651 |
|
---|
652 | QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal);
|
---|
653 | QPushButton *ok_button = buttonBox->button(QDialogButtonBox::Ok);
|
---|
654 | ok_button->setText(tr("&OK"));
|
---|
655 | ok_button->setDefault(true);
|
---|
656 | buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("&Cancel"));
|
---|
657 | connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
---|
658 | connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
---|
659 |
|
---|
660 | QVBoxLayout *layout = new QVBoxLayout(this);
|
---|
661 | layout->addWidget(m_tab_widget);
|
---|
662 | layout->addWidget(buttonBox);
|
---|
663 |
|
---|
664 | m_editor->setFocus();
|
---|
665 |
|
---|
666 | QDesignerSettingsInterface *settings = core->settingsManager();
|
---|
667 | settings->beginGroup(QLatin1String(RichTextDialogC));
|
---|
668 |
|
---|
669 | if (settings->contains(QLatin1String(Geometry)))
|
---|
670 | restoreGeometry(settings->value(QLatin1String(Geometry)).toByteArray());
|
---|
671 |
|
---|
672 | settings->endGroup();
|
---|
673 | }
|
---|
674 |
|
---|
675 | RichTextEditorDialog::~RichTextEditorDialog()
|
---|
676 | {
|
---|
677 | QDesignerSettingsInterface *settings = m_core->settingsManager();
|
---|
678 | settings->beginGroup(QLatin1String(RichTextDialogC));
|
---|
679 |
|
---|
680 | settings->setValue(QLatin1String(Geometry), saveGeometry());
|
---|
681 | settings->endGroup();
|
---|
682 | }
|
---|
683 |
|
---|
684 | int RichTextEditorDialog::showDialog()
|
---|
685 | {
|
---|
686 | m_tab_widget->setCurrentIndex(0);
|
---|
687 | m_editor->selectAll();
|
---|
688 | m_editor->setFocus();
|
---|
689 |
|
---|
690 | return exec();
|
---|
691 | }
|
---|
692 |
|
---|
693 | void RichTextEditorDialog::setDefaultFont(const QFont &font)
|
---|
694 | {
|
---|
695 | m_editor->setDefaultFont(font);
|
---|
696 | }
|
---|
697 |
|
---|
698 | void RichTextEditorDialog::setText(const QString &text)
|
---|
699 | {
|
---|
700 | m_editor->setText(text);
|
---|
701 | m_text_edit->setPlainText(text);
|
---|
702 | m_state = Clean;
|
---|
703 | }
|
---|
704 |
|
---|
705 | QString RichTextEditorDialog::text(Qt::TextFormat format) const
|
---|
706 | {
|
---|
707 | // In autotext mode, if the user has changed the source, use that
|
---|
708 | if (format == Qt::AutoText && (m_state == Clean || m_state == SourceChanged))
|
---|
709 | return m_text_edit->toPlainText();
|
---|
710 | // If the plain text HTML editor is selected, first copy its contents over
|
---|
711 | // to the rich text editor so that it is converted to Qt-HTML or actual
|
---|
712 | // plain text.
|
---|
713 | if (m_tab_widget->currentIndex() == SourceIndex && m_state == SourceChanged)
|
---|
714 | m_editor->setHtml(m_text_edit->toPlainText());
|
---|
715 | return m_editor->text(format);
|
---|
716 | }
|
---|
717 |
|
---|
718 | void RichTextEditorDialog::tabIndexChanged(int newIndex)
|
---|
719 | {
|
---|
720 | // Anything changed, is there a need for a conversion?
|
---|
721 | if (newIndex == SourceIndex && m_state != RichTextChanged)
|
---|
722 | return;
|
---|
723 | if (newIndex == RichTextIndex && m_state != SourceChanged)
|
---|
724 | return;
|
---|
725 | const State oldState = m_state;
|
---|
726 | // Remember the cursor position, since it is invalidated by setPlainText
|
---|
727 | QTextEdit *new_edit = (newIndex == SourceIndex) ? m_text_edit : m_editor;
|
---|
728 | const int position = new_edit->textCursor().position();
|
---|
729 |
|
---|
730 | if (newIndex == SourceIndex)
|
---|
731 | m_text_edit->setPlainText(m_editor->text(Qt::RichText));
|
---|
732 | else
|
---|
733 | m_editor->setHtml(m_text_edit->toPlainText());
|
---|
734 |
|
---|
735 | QTextCursor cursor = new_edit->textCursor();
|
---|
736 | cursor.movePosition(QTextCursor::End);
|
---|
737 | if (cursor.position() > position) {
|
---|
738 | cursor.setPosition(position);
|
---|
739 | }
|
---|
740 | new_edit->setTextCursor(cursor);
|
---|
741 | m_state = oldState; // Changed is triggered by setting the text
|
---|
742 | }
|
---|
743 |
|
---|
744 | void RichTextEditorDialog::richTextChanged()
|
---|
745 | {
|
---|
746 | m_state = RichTextChanged;
|
---|
747 | }
|
---|
748 |
|
---|
749 | void RichTextEditorDialog::sourceChanged()
|
---|
750 | {
|
---|
751 | m_state = SourceChanged;
|
---|
752 | }
|
---|
753 |
|
---|
754 | } // namespace qdesigner_internal
|
---|
755 |
|
---|
756 | QT_END_NAMESPACE
|
---|
757 |
|
---|
758 | #include "richtexteditor.moc"
|
---|