1#!/usr/bin/env python
2
3
4#############################################################################
5##
6## Copyright (C) 2013 Riverbank Computing Limited
7## Copyright (C) 2010 Hans-Peter Jansen <hpj@urpla.net>.
8## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
9## All rights reserved.
10##
11## This file is part of the examples of PyQt.
12##
13## $QT_BEGIN_LICENSE:LGPL$
14## Commercial Usage
15## Licensees holding valid Qt Commercial licenses may use this file in
16## accordance with the Qt Commercial License Agreement provided with the
17## Software or, alternatively, in accordance with the terms contained in
18## a written agreement between you and Nokia.
19##
20## GNU Lesser General Public License Usage
21## Alternatively, this file may be used under the terms of the GNU Lesser
22## General Public License version 2.1 as published by the Free Software
23## Foundation and appearing in the file LICENSE.LGPL included in the
24## packaging of this file.  Please review the following information to
25## ensure the GNU Lesser General Public License version 2.1 requirements
26## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
27##
28## In addition, as a special exception, Nokia gives you certain additional
29## rights.  These rights are described in the Nokia Qt LGPL Exception
30## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
31##
32## GNU General Public License Usage
33## Alternatively, this file may be used under the terms of the GNU
34## General Public License version 3.0 as published by the Free Software
35## Foundation and appearing in the file LICENSE.GPL included in the
36## packaging of this file.  Please review the following information to
37## ensure the GNU General Public License version 3.0 requirements will be
38## met: http://www.gnu.org/copyleft/gpl.html.
39##
40## If you have questions regarding the use of this file, please contact
41## Nokia at qt-info@nokia.com.
42## $QT_END_LICENSE$
43##
44#############################################################################
45
46
47import sys
48
49from PyQt5.QtCore import QFile, QFileInfo, Qt, QTextCodec
50from PyQt5.QtGui import (QFont, QFontDatabase, QFontInfo, QIcon, QKeySequence,
51        QPixmap, QTextBlockFormat, QTextCharFormat, QTextCursor,
52        QTextDocumentWriter, QTextListFormat)
53from PyQt5.QtWidgets import (QAction, QActionGroup, QApplication, QColorDialog,
54        QComboBox, QFileDialog, QFontComboBox, QMainWindow, QMenu, QMessageBox,
55        QTextEdit, QToolBar)
56from PyQt5.QtPrintSupport import QPrintDialog, QPrinter, QPrintPreviewDialog
57
58import textedit_rc
59
60
61if sys.platform.startswith('darwin'):
62    rsrcPath = ":/images/mac"
63else:
64    rsrcPath = ":/images/win"
65
66
67class TextEdit(QMainWindow):
68    def __init__(self, fileName=None, parent=None):
69        super(TextEdit, self).__init__(parent)
70
71        self.setWindowIcon(QIcon(':/images/logo.png'))
72        self.setToolButtonStyle(Qt.ToolButtonFollowStyle)
73        self.setupFileActions()
74        self.setupEditActions()
75        self.setupTextActions()
76
77        helpMenu = QMenu("Help", self)
78        self.menuBar().addMenu(helpMenu)
79        helpMenu.addAction("About", self.about)
80        helpMenu.addAction("About &Qt", QApplication.instance().aboutQt)
81
82        self.textEdit = QTextEdit(self)
83        self.textEdit.currentCharFormatChanged.connect(
84                self.currentCharFormatChanged)
85        self.textEdit.cursorPositionChanged.connect(self.cursorPositionChanged)
86        self.setCentralWidget(self.textEdit)
87        self.textEdit.setFocus()
88        self.setCurrentFileName()
89        self.fontChanged(self.textEdit.font())
90        self.colorChanged(self.textEdit.textColor())
91        self.alignmentChanged(self.textEdit.alignment())
92        self.textEdit.document().modificationChanged.connect(
93                self.actionSave.setEnabled)
94        self.textEdit.document().modificationChanged.connect(
95                self.setWindowModified)
96        self.textEdit.document().undoAvailable.connect(
97                self.actionUndo.setEnabled)
98        self.textEdit.document().redoAvailable.connect(
99                self.actionRedo.setEnabled)
100        self.setWindowModified(self.textEdit.document().isModified())
101        self.actionSave.setEnabled(self.textEdit.document().isModified())
102        self.actionUndo.setEnabled(self.textEdit.document().isUndoAvailable())
103        self.actionRedo.setEnabled(self.textEdit.document().isRedoAvailable())
104        self.actionUndo.triggered.connect(self.textEdit.undo)
105        self.actionRedo.triggered.connect(self.textEdit.redo)
106        self.actionCut.setEnabled(False)
107        self.actionCopy.setEnabled(False)
108        self.actionCut.triggered.connect(self.textEdit.cut)
109        self.actionCopy.triggered.connect(self.textEdit.copy)
110        self.actionPaste.triggered.connect(self.textEdit.paste)
111        self.textEdit.copyAvailable.connect(self.actionCut.setEnabled)
112        self.textEdit.copyAvailable.connect(self.actionCopy.setEnabled)
113        QApplication.clipboard().dataChanged.connect(self.clipboardDataChanged)
114
115        if fileName is None:
116            fileName = ':/example.html'
117
118        if not self.load(fileName):
119            self.fileNew()
120
121    def closeEvent(self, e):
122        if self.maybeSave():
123            e.accept()
124        else:
125            e.ignore()
126
127    def setupFileActions(self):
128        tb = QToolBar(self)
129        tb.setWindowTitle("File Actions")
130        self.addToolBar(tb)
131
132        menu = QMenu("&File", self)
133        self.menuBar().addMenu(menu)
134
135        self.actionNew = QAction(
136                QIcon.fromTheme('document-new',
137                        QIcon(rsrcPath + '/filenew.png')),
138                "&New", self, priority=QAction.LowPriority,
139                shortcut=QKeySequence.New, triggered=self.fileNew)
140        tb.addAction(self.actionNew)
141        menu.addAction(self.actionNew)
142
143        self.actionOpen = QAction(
144                QIcon.fromTheme('document-open',
145                        QIcon(rsrcPath + '/fileopen.png')),
146                "&Open...", self, shortcut=QKeySequence.Open,
147                triggered=self.fileOpen)
148        tb.addAction(self.actionOpen)
149        menu.addAction(self.actionOpen)
150        menu.addSeparator()
151
152        self.actionSave = QAction(
153                QIcon.fromTheme('document-save',
154                        QIcon(rsrcPath + '/filesave.png')),
155                "&Save", self, shortcut=QKeySequence.Save,
156                triggered=self.fileSave, enabled=False)
157        tb.addAction(self.actionSave)
158        menu.addAction(self.actionSave)
159
160        self.actionSaveAs = QAction("Save &As...", self,
161                priority=QAction.LowPriority,
162                shortcut=Qt.CTRL + Qt.SHIFT + Qt.Key_S,
163                triggered=self.fileSaveAs)
164        menu.addAction(self.actionSaveAs)
165        menu.addSeparator()
166
167        self.actionPrint = QAction(
168                QIcon.fromTheme('document-print',
169                        QIcon(rsrcPath + '/fileprint.png')),
170                "&Print...", self, priority=QAction.LowPriority,
171                shortcut=QKeySequence.Print, triggered=self.filePrint)
172        tb.addAction(self.actionPrint)
173        menu.addAction(self.actionPrint)
174
175        self.actionPrintPreview = QAction(
176                QIcon.fromTheme('fileprint',
177                        QIcon(rsrcPath + '/fileprint.png')),
178                "Print Preview...", self,
179                shortcut=Qt.CTRL + Qt.SHIFT + Qt.Key_P,
180                triggered=self.filePrintPreview)
181        menu.addAction(self.actionPrintPreview)
182
183        self.actionPrintPdf = QAction(
184                QIcon.fromTheme('exportpdf',
185                        QIcon(rsrcPath + '/exportpdf.png')),
186                "&Export PDF...", self, priority=QAction.LowPriority,
187                shortcut=Qt.CTRL + Qt.Key_D,
188                triggered=self.filePrintPdf)
189        tb.addAction(self.actionPrintPdf)
190        menu.addAction(self.actionPrintPdf)
191        menu.addSeparator()
192
193        self.actionQuit = QAction("&Quit", self, shortcut=QKeySequence.Quit,
194                triggered=self.close)
195        menu.addAction(self.actionQuit)
196
197    def setupEditActions(self):
198        tb = QToolBar(self)
199        tb.setWindowTitle("Edit Actions")
200        self.addToolBar(tb)
201
202        menu = QMenu("&Edit", self)
203        self.menuBar().addMenu(menu)
204
205        self.actionUndo = QAction(
206                QIcon.fromTheme('edit-undo',
207                        QIcon(rsrcPath + '/editundo.png')),
208                "&Undo", self, shortcut=QKeySequence.Undo)
209        tb.addAction(self.actionUndo)
210        menu.addAction(self.actionUndo)
211
212        self.actionRedo = QAction(
213                QIcon.fromTheme('edit-redo',
214                        QIcon(rsrcPath + '/editredo.png')),
215                "&Redo", self, priority=QAction.LowPriority,
216                shortcut=QKeySequence.Redo)
217        tb.addAction(self.actionRedo)
218        menu.addAction(self.actionRedo)
219        menu.addSeparator()
220
221        self.actionCut = QAction(
222                QIcon.fromTheme('edit-cut', QIcon(rsrcPath + '/editcut.png')),
223                "Cu&t", self, priority=QAction.LowPriority,
224                shortcut=QKeySequence.Cut)
225        tb.addAction(self.actionCut)
226        menu.addAction(self.actionCut)
227
228        self.actionCopy = QAction(
229                QIcon.fromTheme('edit-copy',
230                        QIcon(rsrcPath + '/editcopy.png')),
231                "&Copy", self, priority=QAction.LowPriority,
232                shortcut=QKeySequence.Copy)
233        tb.addAction(self.actionCopy)
234        menu.addAction(self.actionCopy)
235
236        self.actionPaste = QAction(
237                QIcon.fromTheme('edit-paste',
238                        QIcon(rsrcPath + '/editpaste.png')),
239                "&Paste", self, priority=QAction.LowPriority,
240                shortcut=QKeySequence.Paste,
241                enabled=(len(QApplication.clipboard().text()) != 0))
242        tb.addAction(self.actionPaste)
243        menu.addAction(self.actionPaste)
244
245    def setupTextActions(self):
246        tb = QToolBar(self)
247        tb.setWindowTitle("Format Actions")
248        self.addToolBar(tb)
249
250        menu = QMenu("F&ormat", self)
251        self.menuBar().addMenu(menu)
252
253        self.actionTextBold = QAction(
254                QIcon.fromTheme('format-text-bold',
255                        QIcon(rsrcPath + '/textbold.png')),
256                "&Bold", self, priority=QAction.LowPriority,
257                shortcut=Qt.CTRL + Qt.Key_B, triggered=self.textBold,
258                checkable=True)
259        bold = QFont()
260        bold.setBold(True)
261        self.actionTextBold.setFont(bold)
262        tb.addAction(self.actionTextBold)
263        menu.addAction(self.actionTextBold)
264
265        self.actionTextItalic = QAction(
266                QIcon.fromTheme('format-text-italic',
267                        QIcon(rsrcPath + '/textitalic.png')),
268                "&Italic", self, priority=QAction.LowPriority,
269                shortcut=Qt.CTRL + Qt.Key_I, triggered=self.textItalic,
270                checkable=True)
271        italic = QFont()
272        italic.setItalic(True)
273        self.actionTextItalic.setFont(italic)
274        tb.addAction(self.actionTextItalic)
275        menu.addAction(self.actionTextItalic)
276
277        self.actionTextUnderline = QAction(
278                QIcon.fromTheme('format-text-underline',
279                        QIcon(rsrcPath + '/textunder.png')),
280                "&Underline", self, priority=QAction.LowPriority,
281                shortcut=Qt.CTRL + Qt.Key_U, triggered=self.textUnderline,
282                checkable=True)
283        underline = QFont()
284        underline.setUnderline(True)
285        self.actionTextUnderline.setFont(underline)
286        tb.addAction(self.actionTextUnderline)
287        menu.addAction(self.actionTextUnderline)
288
289        menu.addSeparator()
290
291        grp = QActionGroup(self, triggered=self.textAlign)
292
293        # Make sure the alignLeft is always left of the alignRight.
294        if QApplication.isLeftToRight():
295            self.actionAlignLeft = QAction(
296                    QIcon.fromTheme('format-justify-left',
297                            QIcon(rsrcPath + '/textleft.png')),
298                    "&Left", grp)
299            self.actionAlignCenter = QAction(
300                    QIcon.fromTheme('format-justify-center',
301                            QIcon(rsrcPath + '/textcenter.png')),
302                    "C&enter", grp)
303            self.actionAlignRight = QAction(
304                    QIcon.fromTheme('format-justify-right',
305                            QIcon(rsrcPath + '/textright.png')),
306                    "&Right", grp)
307        else:
308            self.actionAlignRight = QAction(
309                    QIcon.fromTheme('format-justify-right',
310                            QIcon(rsrcPath + '/textright.png')),
311                    "&Right", grp)
312            self.actionAlignCenter = QAction(
313                    QIcon.fromTheme('format-justify-center',
314                            QIcon(rsrcPath + '/textcenter.png')),
315                    "C&enter", grp)
316            self.actionAlignLeft = QAction(
317                    QIcon.fromTheme('format-justify-left',
318                            QIcon(rsrcPath + '/textleft.png')),
319                    "&Left", grp)
320
321        self.actionAlignJustify = QAction(
322                QIcon.fromTheme('format-justify-fill',
323                        QIcon(rsrcPath + '/textjustify.png')),
324                "&Justify", grp)
325
326        self.actionAlignLeft.setShortcut(Qt.CTRL + Qt.Key_L)
327        self.actionAlignLeft.setCheckable(True)
328        self.actionAlignLeft.setPriority(QAction.LowPriority)
329
330        self.actionAlignCenter.setShortcut(Qt.CTRL + Qt.Key_E)
331        self.actionAlignCenter.setCheckable(True)
332        self.actionAlignCenter.setPriority(QAction.LowPriority)
333
334        self.actionAlignRight.setShortcut(Qt.CTRL + Qt.Key_R)
335        self.actionAlignRight.setCheckable(True)
336        self.actionAlignRight.setPriority(QAction.LowPriority)
337
338        self.actionAlignJustify.setShortcut(Qt.CTRL + Qt.Key_J)
339        self.actionAlignJustify.setCheckable(True)
340        self.actionAlignJustify.setPriority(QAction.LowPriority)
341
342        tb.addActions(grp.actions())
343        menu.addActions(grp.actions())
344        menu.addSeparator()
345
346        pix = QPixmap(16, 16)
347        pix.fill(Qt.black)
348        self.actionTextColor = QAction(QIcon(pix), "&Color...", self,
349                triggered=self.textColor)
350        tb.addAction(self.actionTextColor)
351        menu.addAction(self.actionTextColor)
352
353        tb = QToolBar(self)
354        tb.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea)
355        tb.setWindowTitle("Format Actions")
356        self.addToolBarBreak(Qt.TopToolBarArea)
357        self.addToolBar(tb)
358
359        comboStyle = QComboBox(tb)
360        tb.addWidget(comboStyle)
361        comboStyle.addItem("Standard")
362        comboStyle.addItem("Bullet List (Disc)")
363        comboStyle.addItem("Bullet List (Circle)")
364        comboStyle.addItem("Bullet List (Square)")
365        comboStyle.addItem("Ordered List (Decimal)")
366        comboStyle.addItem("Ordered List (Alpha lower)")
367        comboStyle.addItem("Ordered List (Alpha upper)")
368        comboStyle.addItem("Ordered List (Roman lower)")
369        comboStyle.addItem("Ordered List (Roman upper)")
370        comboStyle.activated.connect(self.textStyle)
371
372        self.comboFont = QFontComboBox(tb)
373        tb.addWidget(self.comboFont)
374        self.comboFont.activated[str].connect(self.textFamily)
375
376        self.comboSize = QComboBox(tb)
377        self.comboSize.setObjectName("comboSize")
378        tb.addWidget(self.comboSize)
379        self.comboSize.setEditable(True)
380
381        db = QFontDatabase()
382        for size in db.standardSizes():
383            self.comboSize.addItem("%s" % (size))
384
385        self.comboSize.activated[str].connect(self.textSize)
386        self.comboSize.setCurrentIndex(
387                self.comboSize.findText(
388                        "%s" % (QApplication.font().pointSize())))
389
390    def load(self, f):
391        if not QFile.exists(f):
392            return False
393
394        fh = QFile(f)
395        if not fh.open(QFile.ReadOnly):
396            return False
397
398        data = fh.readAll()
399        codec = QTextCodec.codecForHtml(data)
400        unistr = codec.toUnicode(data)
401
402        if Qt.mightBeRichText(unistr):
403            self.textEdit.setHtml(unistr)
404        else:
405            self.textEdit.setPlainText(unistr)
406
407        self.setCurrentFileName(f)
408        return True
409
410    def maybeSave(self):
411        if not self.textEdit.document().isModified():
412            return True
413
414        if self.fileName.startswith(':/'):
415            return True
416
417        ret = QMessageBox.warning(self, "Application",
418                "The document has been modified.\n"
419                "Do you want to save your changes?",
420                QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
421
422        if ret == QMessageBox.Save:
423            return self.fileSave()
424
425        if ret == QMessageBox.Cancel:
426            return False
427
428        return True
429
430    def setCurrentFileName(self, fileName=''):
431        self.fileName = fileName
432        self.textEdit.document().setModified(False)
433
434        if not fileName:
435            shownName = 'untitled.txt'
436        else:
437            shownName = QFileInfo(fileName).fileName()
438
439        self.setWindowTitle(self.tr("%s[*] - %s" % (shownName, "Rich Text")))
440        self.setWindowModified(False)
441
442    def fileNew(self):
443        if self.maybeSave():
444            self.textEdit.clear()
445            self.setCurrentFileName()
446
447    def fileOpen(self):
448        fn, _ = QFileDialog.getOpenFileName(self, "Open File...", None,
449                "HTML-Files (*.htm *.html);;All Files (*)")
450
451        if fn:
452            self.load(fn)
453
454    def fileSave(self):
455        if not self.fileName:
456            return self.fileSaveAs()
457
458        writer = QTextDocumentWriter(self.fileName)
459        success = writer.write(self.textEdit.document())
460        if success:
461            self.textEdit.document().setModified(False)
462
463        return success
464
465    def fileSaveAs(self):
466        fn, _ = QFileDialog.getSaveFileName(self, "Save as...", None,
467                "ODF files (*.odt);;HTML-Files (*.htm *.html);;All Files (*)")
468
469        if not fn:
470            return False
471
472        lfn = fn.lower()
473        if not lfn.endswith(('.odt', '.htm', '.html')):
474            # The default.
475            fn += '.odt'
476
477        self.setCurrentFileName(fn)
478        return self.fileSave()
479
480    def filePrint(self):
481        printer = QPrinter(QPrinter.HighResolution)
482        dlg = QPrintDialog(printer, self)
483
484        if self.textEdit.textCursor().hasSelection():
485            dlg.addEnabledOption(QPrintDialog.PrintSelection)
486
487        dlg.setWindowTitle("Print Document")
488
489        if dlg.exec_() == QPrintDialog.Accepted:
490            self.textEdit.print_(printer)
491
492        del dlg
493
494    def filePrintPreview(self):
495        printer = QPrinter(QPrinter.HighResolution)
496        preview = QPrintPreviewDialog(printer, self)
497        preview.paintRequested.connect(self.printPreview)
498        preview.exec_()
499
500    def printPreview(self, printer):
501        self.textEdit.print_(printer)
502
503    def filePrintPdf(self):
504        fn, _ = QFileDialog.getSaveFileName(self, "Export PDF", None,
505                "PDF files (*.pdf);;All Files (*)")
506
507        if fn:
508            if QFileInfo(fn).suffix().isEmpty():
509                fn += '.pdf'
510
511            printer = QPrinter(QPrinter.HighResolution)
512            printer.setOutputFormat(QPrinter.PdfFormat)
513            printer.setOutputFileName(fn)
514            self.textEdit.document().print_(printer)
515
516    def textBold(self):
517        fmt = QTextCharFormat()
518        fmt.setFontWeight(self.actionTextBold.isChecked() and QFont.Bold or QFont.Normal)
519        self.mergeFormatOnWordOrSelection(fmt)
520
521    def textUnderline(self):
522        fmt = QTextCharFormat()
523        fmt.setFontUnderline(self.actionTextUnderline.isChecked())
524        self.mergeFormatOnWordOrSelection(fmt)
525
526    def textItalic(self):
527        fmt = QTextCharFormat()
528        fmt.setFontItalic(self.actionTextItalic.isChecked())
529        self.mergeFormatOnWordOrSelection(fmt)
530
531    def textFamily(self, family):
532        fmt = QTextCharFormat()
533        fmt.setFontFamily(family)
534        self.mergeFormatOnWordOrSelection(fmt)
535
536    def textSize(self, pointSize):
537        pointSize = float(pointSize)
538        if pointSize > 0:
539            fmt = QTextCharFormat()
540            fmt.setFontPointSize(pointSize)
541            self.mergeFormatOnWordOrSelection(fmt)
542
543    def textStyle(self, styleIndex):
544        cursor = self.textEdit.textCursor()
545        if styleIndex:
546            styleDict = {
547                1: QTextListFormat.ListDisc,
548                2: QTextListFormat.ListCircle,
549                3: QTextListFormat.ListSquare,
550                4: QTextListFormat.ListDecimal,
551                5: QTextListFormat.ListLowerAlpha,
552                6: QTextListFormat.ListUpperAlpha,
553                7: QTextListFormat.ListLowerRoman,
554                8: QTextListFormat.ListUpperRoman,
555            }
556
557            style = styleDict.get(styleIndex, QTextListFormat.ListDisc)
558            cursor.beginEditBlock()
559            blockFmt = cursor.blockFormat()
560            listFmt = QTextListFormat()
561
562            if cursor.currentList():
563                listFmt = cursor.currentList().format()
564            else:
565                listFmt.setIndent(blockFmt.indent() + 1)
566                blockFmt.setIndent(0)
567                cursor.setBlockFormat(blockFmt)
568
569            listFmt.setStyle(style)
570            cursor.createList(listFmt)
571            cursor.endEditBlock()
572        else:
573            bfmt = QTextBlockFormat()
574            bfmt.setObjectIndex(-1)
575            cursor.mergeBlockFormat(bfmt)
576
577    def textColor(self):
578        col = QColorDialog.getColor(self.textEdit.textColor(), self)
579        if not col.isValid():
580            return
581
582        fmt = QTextCharFormat()
583        fmt.setForeground(col)
584        self.mergeFormatOnWordOrSelection(fmt)
585        self.colorChanged(col)
586
587    def textAlign(self, action):
588        if action == self.actionAlignLeft:
589            self.textEdit.setAlignment(Qt.AlignLeft | Qt.AlignAbsolute)
590        elif action == self.actionAlignCenter:
591            self.textEdit.setAlignment(Qt.AlignHCenter)
592        elif action == self.actionAlignRight:
593            self.textEdit.setAlignment(Qt.AlignRight | Qt.AlignAbsolute)
594        elif action == self.actionAlignJustify:
595            self.textEdit.setAlignment(Qt.AlignJustify)
596
597    def currentCharFormatChanged(self, format):
598        self.fontChanged(format.font())
599        self.colorChanged(format.foreground().color())
600
601    def cursorPositionChanged(self):
602        self.alignmentChanged(self.textEdit.alignment())
603
604    def clipboardDataChanged(self):
605        self.actionPaste.setEnabled(len(QApplication.clipboard().text()) != 0)
606
607    def about(self):
608        QMessageBox.about(self, "About",
609                "This example demonstrates Qt's rich text editing facilities "
610                "in action, providing an example document for you to "
611                "experiment with.")
612
613    def mergeFormatOnWordOrSelection(self, format):
614        cursor = self.textEdit.textCursor()
615        if not cursor.hasSelection():
616            cursor.select(QTextCursor.WordUnderCursor)
617
618        cursor.mergeCharFormat(format)
619        self.textEdit.mergeCurrentCharFormat(format)
620
621    def fontChanged(self, font):
622        self.comboFont.setCurrentIndex(
623                self.comboFont.findText(QFontInfo(font).family()))
624        self.comboSize.setCurrentIndex(
625                self.comboSize.findText("%s" % font.pointSize()))
626        self.actionTextBold.setChecked(font.bold())
627        self.actionTextItalic.setChecked(font.italic())
628        self.actionTextUnderline.setChecked(font.underline())
629
630    def colorChanged(self, color):
631        pix = QPixmap(16, 16)
632        pix.fill(color)
633        self.actionTextColor.setIcon(QIcon(pix))
634
635    def alignmentChanged(self, alignment):
636        if alignment & Qt.AlignLeft:
637            self.actionAlignLeft.setChecked(True)
638        elif alignment & Qt.AlignHCenter:
639            self.actionAlignCenter.setChecked(True)
640        elif alignment & Qt.AlignRight:
641            self.actionAlignRight.setChecked(True)
642        elif alignment & Qt.AlignJustify:
643            self.actionAlignJustify.setChecked(True)
644
645
646if __name__ == '__main__':
647    app = QApplication(sys.argv)
648
649    mainWindows = []
650    for fn in sys.argv[1:] or [None]:
651        textEdit = TextEdit(fn)
652        textEdit.resize(700, 800)
653        textEdit.show()
654        mainWindows.append(textEdit)
655
656    sys.exit(app.exec_())
657