1 from customeditor import CustomEditor, QtCore, QtGui, Qt
2 from wideeditor import WideEditor
3 from camelot.view.art import Icon
4
5 -class RichTextEditor(CustomEditor, WideEditor):
6
7 - def __init__(self, parent=None, editable=True, **kwargs):
8 CustomEditor.__init__(self, parent)
9 self.layout = QtGui.QVBoxLayout(self)
10 self.layout.setSpacing(0)
11 self.layout.setMargin(0)
12 self.editable = editable
13 self.setSizePolicy( QtGui.QSizePolicy.Expanding,
14 QtGui.QSizePolicy.Expanding )
15
16 class CustomTextEdit(QtGui.QTextEdit):
17 """A TextEdit editor that sends editingFinished events when the text was changed
18 and focus is lost
19 """
20
21 def __init__(self, parent):
22 super(CustomTextEdit, self).__init__(parent)
23 self._changed = False
24 self.connect(self, QtCore.SIGNAL('textChanged()'), self.setTextChanged)
25
26 def focusOutEvent(self, event):
27 if self._changed:
28 self.emit(QtCore.SIGNAL('editingFinished()'))
29
30 def textChanged(self):
31 return self._changed
32
33 def setTextChanged(self, state=True):
34 self._changed = state
35
36 def setHtml(self, html):
37 QtGui.QTextEdit.setHtml(self, html)
38 self._changed = False
39
40 self.textedit = CustomTextEdit(self)
41
42 self.connect(self.textedit,
43 QtCore.SIGNAL('editingFinished()'),
44 self.editingFinished)
45 self.textedit.setAcceptRichText(True)
46
47 if not self.editable:
48 self.textedit.setReadOnly(True)
49 else:
50 self.initButtons(editable)
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 self.layout.addWidget(self.textedit)
184
185 self.setLayout(self.layout)
186
187
188
189
190 self.textedit.setFontWeight(QtGui.QFont.Normal)
191 self.textedit.setFontItalic(False)
192 self.textedit.setFontUnderline(False)
193 self.textedit.setFocus(Qt.OtherFocusReason)
194 self.update_alignment()
195
196 if self.editable:
197 self.connect(self.textedit,
198 QtCore.SIGNAL('currentCharFormatChanged(const QTextCharFormat&)'),
199 self.update_format)
200 self.connect(self.textedit,
201 QtCore.SIGNAL('cursorPositionChanged()'),
202 self.update_text)
203
204 - def editingFinished(self):
205 if self.textedit.textChanged():
206 self.emit(QtCore.SIGNAL('editingFinished()'))
207
208
209
210
211
212
214 self.toolbar = QtGui.QToolBar(self)
215 self.toolbar.setContentsMargins(0, 0, 0, 0)
216 self.toolbar.setEnabled(editable)
217
218 self.bold_button = QtGui.QToolButton(self)
219 icon = Icon('tango/16x16/actions/format-text-bold.png').getQIcon()
220 self.bold_button.setIcon(icon)
221 self.bold_button.setAutoRaise(True)
222 self.bold_button.setCheckable(True)
223 self.bold_button.setEnabled(editable)
224 self.bold_button.setMaximumSize(QtCore.QSize(20, 20))
225 self.bold_button.setShortcut(QtGui.QKeySequence('Ctrl+B'))
226 self.connect(self.bold_button, QtCore.SIGNAL('clicked()'), self.set_bold)
227
228 self.italic_button = QtGui.QToolButton(self)
229 icon = Icon('tango/16x16/actions/format-text-italic.png').getQIcon()
230 self.italic_button.setIcon(icon)
231 self.italic_button.setAutoRaise(True)
232 self.italic_button.setCheckable(True)
233 self.italic_button.setEnabled(editable)
234 self.italic_button.setMaximumSize(QtCore.QSize(20, 20))
235 self.italic_button.setShortcut(QtGui.QKeySequence('Ctrl+I'))
236 self.connect(self.italic_button,
237 QtCore.SIGNAL('clicked(bool)'),
238 self.set_italic)
239
240 self.underline_button = QtGui.QToolButton(self)
241 icon = Icon('tango/16x16/actions/format-text-underline.png').getQIcon()
242 self.underline_button.setIcon(icon)
243 self.underline_button.setAutoRaise(True)
244 self.underline_button.setCheckable(True)
245 self.underline_button.setEnabled(editable)
246 self.underline_button.setMaximumSize(QtCore.QSize(20, 20))
247 self.underline_button.setShortcut(QtGui.QKeySequence('Ctrl+U'))
248 self.connect(self.underline_button,
249 QtCore.SIGNAL('clicked(bool)'),
250 self.set_underline)
251
252 self.copy_button = QtGui.QToolButton(self)
253 icon = Icon('tango/16x16/actions/edit-copy.png').getQIcon()
254 self.copy_button.setIcon(icon)
255 self.copy_button.setAutoRaise(True)
256 self.copy_button.setEnabled(editable)
257 self.copy_button.setMaximumSize(QtCore.QSize(20, 20))
258 self.connect(self.copy_button,
259 QtCore.SIGNAL('clicked(bool)'),
260 self.textedit.copy)
261
262 self.cut_button = QtGui.QToolButton(self)
263 icon = Icon('tango/16x16/actions/edit-cut.png').getQIcon()
264 self.cut_button.setIcon(icon)
265 self.cut_button.setAutoRaise(True)
266 self.cut_button.setEnabled(editable)
267 self.cut_button.setMaximumSize(QtCore.QSize(20, 20))
268 self.connect(self.cut_button,
269 QtCore.SIGNAL('clicked(bool)'),
270 self.textedit.cut)
271
272 self.paste_button = QtGui.QToolButton(self)
273 icon = Icon('tango/16x16/actions/edit-paste.png').getQIcon()
274 self.paste_button.setIcon(icon)
275 self.paste_button.setAutoRaise(True)
276 self.paste_button.setEnabled(editable)
277 self.paste_button.setMaximumSize(QtCore.QSize(20, 20))
278 self.connect(self.paste_button,
279 QtCore.SIGNAL('clicked(bool)'),
280 self.textedit.paste)
281
282 self.alignleft_button = QtGui.QToolButton(self)
283 icon = Icon('tango/16x16/actions/format-justify-left.png').getQIcon()
284 self.alignleft_button.setIcon(icon)
285 self.alignleft_button.setAutoRaise(True)
286 self.alignleft_button.setCheckable(True)
287 self.alignleft_button.setEnabled(editable)
288 self.alignleft_button.setMaximumSize(QtCore.QSize(20, 20))
289 self.connect(self.alignleft_button,
290 QtCore.SIGNAL('clicked(bool)'),
291 self.set_alignleft)
292
293 self.aligncenter_button = QtGui.QToolButton(self)
294 icon = Icon('tango/16x16/actions/format-justify-center.png').getQIcon()
295 self.aligncenter_button.setIcon(icon)
296 self.aligncenter_button.setAutoRaise(True)
297 self.aligncenter_button.setCheckable(True)
298 self.aligncenter_button.setEnabled(editable)
299 self.aligncenter_button.setMaximumSize(QtCore.QSize(20, 20))
300 self.connect(self.aligncenter_button,
301 QtCore.SIGNAL('clicked(bool)'),
302 self.set_aligncenter)
303
304 self.alignright_button = QtGui.QToolButton(self)
305 icon = Icon('tango/16x16/actions/format-justify-right.png').getQIcon()
306 self.alignright_button.setIcon(icon)
307 self.alignright_button.setAutoRaise(True)
308 self.alignright_button.setCheckable(True)
309 self.alignright_button.setEnabled(editable)
310 self.alignright_button.setMaximumSize(QtCore.QSize(20, 20))
311 self.connect(self.alignright_button,
312 QtCore.SIGNAL('clicked(bool)'),
313 self.set_alignright)
314
315 self.color_button = QtGui.QToolButton(self)
316 self.color_button.setAutoRaise(True)
317 self.color_button.setEnabled(editable)
318 self.color_button.setMaximumSize(QtCore.QSize(20, 20))
319 self.connect(self.color_button,
320 QtCore.SIGNAL('clicked(bool)'),
321 self.set_color)
322
323 self.toolbar.addWidget(self.copy_button)
324 self.toolbar.addWidget(self.cut_button)
325 self.toolbar.addWidget(self.paste_button)
326 self.toolbar.addSeparator()
327 self.toolbar.addWidget(self.bold_button)
328 self.toolbar.addWidget(self.italic_button)
329 self.toolbar.addWidget(self.underline_button)
330 self.toolbar.addSeparator()
331 self.toolbar.addWidget(self.alignleft_button)
332 self.toolbar.addWidget(self.aligncenter_button)
333 self.toolbar.addWidget(self.alignright_button)
334 self.toolbar.addSeparator()
335 self.toolbar.addWidget(self.color_button)
336
337
338
339
340 self.layout.addWidget(self.toolbar)
341
342
343
344
345 - def set_enabled(self, editable=True):
346 if self.textedit.isEnabled() != editable:
347 if not editable:
348 self.layout().removeWidget(self.bold_button)
349 self.layout().removeWidget(self.italic_button)
350 self.layout().removeWidget(self.underline_button)
351 self.layout().removeWidget(self.toolbar)
352 self.layout().removeWidget(self.color_button)
353 self.layout().removeWidget(self.aligncenter_button)
354 self.layout().removeWidget(self.alignleft_button)
355 self.layout().removeWidget(self.alignright_button)
356 self.layout().removeWidget(self.copy_button)
357 self.layout().removeWidget(self.cut_button)
358 self.layout().removeWidget(self.paste_button)
359 else:
360 value = self.get_value()
361 self.layout.removeWidget(self.textedit)
362 self.initButtons(editable)
363 self.layout.addWidget(self.textedit)
364 self.set_value(value)
365 self.textedit.setEnabled(editable)
366
367
368
369
370
371
372 - def set_bold(self):
373 if self.bold_button.isChecked():
374 self.textedit.setFocus(Qt.OtherFocusReason)
375 self.textedit.setFontWeight(QtGui.QFont.Bold)
376 else:
377 self.textedit.setFocus(Qt.OtherFocusReason)
378 self.textedit.setFontWeight(QtGui.QFont.Normal)
379
380 - def set_italic(self, bool):
381 if bool:
382 self.textedit.setFocus(Qt.OtherFocusReason)
383 self.textedit.setFontItalic(True)
384 else:
385 self.textedit.setFocus(Qt.OtherFocusReason)
386 self.textedit.setFontItalic(False)
387
388 - def set_underline(self, bool):
389 if bool:
390 self.textedit.setFocus(Qt.OtherFocusReason)
391 self.textedit.setFontUnderline(True)
392 else:
393 self.textedit.setFocus(Qt.OtherFocusReason)
394 self.textedit.setFontUnderline(False)
395
396
397 - def set_alignleft(self, bool):
398 if bool:
399 self.textedit.setFocus(Qt.OtherFocusReason)
400 self.textedit.setAlignment(Qt.AlignLeft)
401 self.update_alignment(Qt.AlignLeft)
402
403 - def set_aligncenter(self, bool):
404 if bool:
405 self.textedit.setFocus(Qt.OtherFocusReason)
406 self.textedit.setAlignment(Qt.AlignCenter)
407 self.update_alignment(Qt.AlignCenter)
408
409 - def set_alignright(self, bool):
410 if bool:
411 self.textedit.setFocus(Qt.OtherFocusReason)
412 self.textedit.setAlignment(Qt.AlignRight)
413 self.update_alignment(Qt.AlignRight)
414
415 - def update_alignment(self, al=None):
416 if self.editable:
417 if al is None:
418 al = self.textedit.alignment()
419 if al == Qt.AlignLeft:
420 self.alignleft_button.setChecked(True)
421 self.aligncenter_button.setChecked(False)
422 self.alignright_button.setChecked(False)
423 elif al == Qt.AlignCenter:
424 self.aligncenter_button.setChecked(True)
425 self.alignleft_button.setChecked(False)
426 self.alignright_button.setChecked(False)
427 elif al == Qt.AlignRight:
428 self.alignright_button.setChecked(True)
429 self.alignleft_button.setChecked(False)
430 self.aligncenter_button.setChecked(False)
431
432 - def set_color(self):
433 color = QtGui.QColorDialog.getColor(self.textedit.textColor())
434 if color.isValid():
435 self.textedit.setFocus(Qt.OtherFocusReason)
436 self.textedit.setTextColor(color)
437 pixmap = QtGui.QPixmap(16, 16)
438 pixmap.fill(color)
439 self.color_button.setIcon(QtGui.QIcon(pixmap))
440
441 - def update_color(self):
442 if self.editable:
443 color = self.textedit.textColor()
444 pixmap = QtGui.QPixmap(16, 16)
445 pixmap.fill(color)
446 self.color_button.setIcon(QtGui.QIcon(pixmap))
447
449 if self.editable:
450 font = format.font()
451 self.bold_button.setChecked(font.bold())
452 self.italic_button.setChecked(font.italic())
453 self.underline_button.setChecked(font.underline())
454 self.update_alignment(self.textedit.alignment())
455
456 - def update_text(self):
457 if self.editable:
458 self.update_alignment()
459 self.update_color()
460
461 - def get_value(self):
462 from xml.dom import minidom
463 tree = minidom.parseString(unicode(self.textedit.toHtml()).encode('utf-8'))
464 value = u''.join([node.toxml() for node in tree.getElementsByTagName('html')[0].getElementsByTagName('body')[0].childNodes])
465 return CustomEditor.get_value(self) or value
466
467 - def set_value(self, value):
468 value = CustomEditor.set_value(self, value)
469 if value!=None:
470 if unicode(self.textedit.toHtml())!=value:
471 self.update_alignment()
472 self.textedit.setHtml(value)
473 self.update_color()
474 else:
475 self.textedit.clear()
476