24 class EditorButtonsWidget(QWidget): |
30 class EditorButtonsWidget(QWidget): |
25 """ |
31 """ |
26 Class implementing a widget containing various buttons for accessing |
32 Class implementing a widget containing various buttons for accessing |
27 editor actions. |
33 editor actions. |
28 """ |
34 """ |
|
35 |
29 def __init__(self, editor, parent=None): |
36 def __init__(self, editor, parent=None): |
30 """ |
37 """ |
31 Constructor |
38 Constructor |
32 |
39 |
33 @param editor reference to the editor |
40 @param editor reference to the editor |
34 @type Editor |
41 @type Editor |
35 @param parent reference to the parent widget |
42 @param parent reference to the parent widget |
36 @type QWidget |
43 @type QWidget |
37 """ |
44 """ |
38 super().__init__(parent) |
45 super().__init__(parent) |
39 |
46 |
40 margin = 2 |
47 margin = 2 |
41 spacing = 3 |
48 spacing = 3 |
42 |
49 |
43 self.__buttonsWidget = QWidget(self) |
50 self.__buttonsWidget = QWidget(self) |
44 |
51 |
45 self.__layout = QVBoxLayout(self.__buttonsWidget) |
52 self.__layout = QVBoxLayout(self.__buttonsWidget) |
46 self.__layout.setContentsMargins(0, 0, 0, 0) |
53 self.__layout.setContentsMargins(0, 0, 0, 0) |
47 self.__layout.setSpacing(spacing) |
54 self.__layout.setSpacing(spacing) |
48 |
55 |
49 self.__provider = None |
56 self.__provider = None |
50 |
57 |
51 self.__editor = editor |
58 self.__editor = editor |
52 self.__editor.languageChanged.connect(self.__updateButtonStates) |
59 self.__editor.languageChanged.connect(self.__updateButtonStates) |
53 self.__editor.editorSaved.connect(self.__updateButtonStates) |
60 self.__editor.editorSaved.connect(self.__updateButtonStates) |
54 self.__editor.editorRenamed.connect(self.__updateButtonStates) |
61 self.__editor.editorRenamed.connect(self.__updateButtonStates) |
55 self.__editor.selectionChanged.connect(self.__editorSelectionChanged) |
62 self.__editor.selectionChanged.connect(self.__editorSelectionChanged) |
56 self.__editor.settingsRead.connect(self.__editorSettingsRead) |
63 self.__editor.settingsRead.connect(self.__editorSettingsRead) |
57 |
64 |
58 self.__createButtons() |
65 self.__createButtons() |
59 |
66 |
60 self.__layout.addStretch() |
67 self.__layout.addStretch() |
61 |
68 |
62 self.__outerLayout = QVBoxLayout(self) |
69 self.__outerLayout = QVBoxLayout(self) |
63 self.__outerLayout.setContentsMargins(margin, margin, margin, margin) |
70 self.__outerLayout.setContentsMargins(margin, margin, margin, margin) |
64 self.__outerLayout.setSpacing(spacing) |
71 self.__outerLayout.setSpacing(spacing) |
65 self.__outerLayout.setAlignment(Qt.AlignmentFlag.AlignHCenter) |
72 self.__outerLayout.setAlignment(Qt.AlignmentFlag.AlignHCenter) |
66 |
73 |
67 self.__upButton = QToolButton(self) |
74 self.__upButton = QToolButton(self) |
68 self.__upButton.setArrowType(Qt.ArrowType.UpArrow) |
75 self.__upButton.setArrowType(Qt.ArrowType.UpArrow) |
69 self.__upButton.setSizePolicy( |
76 self.__upButton.setSizePolicy( |
70 QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum) |
77 QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum |
|
78 ) |
71 self.__upButton.setAutoRepeat(True) |
79 self.__upButton.setAutoRepeat(True) |
72 |
80 |
73 self.__scroller = QScrollArea(self) |
81 self.__scroller = QScrollArea(self) |
74 self.__scroller.setWidget(self.__buttonsWidget) |
82 self.__scroller.setWidget(self.__buttonsWidget) |
75 self.__scroller.setSizePolicy( |
83 self.__scroller.setSizePolicy( |
76 QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) |
84 QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding |
|
85 ) |
77 self.__scroller.setFrameShape(QFrame.Shape.NoFrame) |
86 self.__scroller.setFrameShape(QFrame.Shape.NoFrame) |
78 self.__scroller.setVerticalScrollBarPolicy( |
87 self.__scroller.setVerticalScrollBarPolicy( |
79 Qt.ScrollBarPolicy.ScrollBarAlwaysOff) |
88 Qt.ScrollBarPolicy.ScrollBarAlwaysOff |
|
89 ) |
80 self.__scroller.setHorizontalScrollBarPolicy( |
90 self.__scroller.setHorizontalScrollBarPolicy( |
81 Qt.ScrollBarPolicy.ScrollBarAlwaysOff) |
91 Qt.ScrollBarPolicy.ScrollBarAlwaysOff |
|
92 ) |
82 self.__scroller.setWidgetResizable(False) |
93 self.__scroller.setWidgetResizable(False) |
83 |
94 |
84 self.__downButton = QToolButton(self) |
95 self.__downButton = QToolButton(self) |
85 self.__downButton.setArrowType(Qt.ArrowType.DownArrow) |
96 self.__downButton.setArrowType(Qt.ArrowType.DownArrow) |
86 self.__downButton.setSizePolicy( |
97 self.__downButton.setSizePolicy( |
87 QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum) |
98 QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum |
|
99 ) |
88 self.__downButton.setAutoRepeat(True) |
100 self.__downButton.setAutoRepeat(True) |
89 |
101 |
90 self.__outerLayout.addWidget(self.__upButton) |
102 self.__outerLayout.addWidget(self.__upButton) |
91 self.__outerLayout.addWidget(self.__scroller) |
103 self.__outerLayout.addWidget(self.__scroller) |
92 self.__outerLayout.addWidget(self.__downButton) |
104 self.__outerLayout.addWidget(self.__downButton) |
93 |
105 |
94 self.__upButton.clicked.connect(self.__slideUp) |
106 self.__upButton.clicked.connect(self.__slideUp) |
95 self.__downButton.clicked.connect(self.__slideDown) |
107 self.__downButton.clicked.connect(self.__slideDown) |
96 |
108 |
97 self.setMaximumWidth( |
109 self.setMaximumWidth(self.__buttons["bold"].sizeHint().width() + 2 * margin) |
98 self.__buttons["bold"].sizeHint().width() + 2 * margin) |
110 |
99 |
|
100 self.__updateButtonStates() |
111 self.__updateButtonStates() |
101 |
112 |
102 ####################################################################### |
113 ####################################################################### |
103 ## Methods below implement some event handlers |
114 ## Methods below implement some event handlers |
104 ####################################################################### |
115 ####################################################################### |
105 |
116 |
106 def show(self): |
117 def show(self): |
107 """ |
118 """ |
108 Public slot to show the widget. |
119 Public slot to show the widget. |
109 """ |
120 """ |
110 super().show() |
121 super().show() |
111 self.__enableScrollerButtons() |
122 self.__enableScrollerButtons() |
112 |
123 |
113 def resizeEvent(self, evt): |
124 def resizeEvent(self, evt): |
114 """ |
125 """ |
115 Protected method to handle resize events. |
126 Protected method to handle resize events. |
116 |
127 |
117 @param evt reference to the resize event (QResizeEvent) |
128 @param evt reference to the resize event (QResizeEvent) |
118 """ |
129 """ |
119 self.__enableScrollerButtons() |
130 self.__enableScrollerButtons() |
120 super().resizeEvent(evt) |
131 super().resizeEvent(evt) |
121 |
132 |
122 ####################################################################### |
133 ####################################################################### |
123 ## Methods below implement scroller related functions |
134 ## Methods below implement scroller related functions |
124 ####################################################################### |
135 ####################################################################### |
125 |
136 |
126 def __enableScrollerButtons(self): |
137 def __enableScrollerButtons(self): |
127 """ |
138 """ |
128 Private method to set the enabled state of the scroll buttons. |
139 Private method to set the enabled state of the scroll buttons. |
129 """ |
140 """ |
130 scrollBar = self.__scroller.verticalScrollBar() |
141 scrollBar = self.__scroller.verticalScrollBar() |
131 self.__upButton.setEnabled(scrollBar.value() > 0) |
142 self.__upButton.setEnabled(scrollBar.value() > 0) |
132 self.__downButton.setEnabled(scrollBar.value() < scrollBar.maximum()) |
143 self.__downButton.setEnabled(scrollBar.value() < scrollBar.maximum()) |
133 |
144 |
134 def __slideUp(self): |
145 def __slideUp(self): |
135 """ |
146 """ |
136 Private slot to move the widget upwards, i.e. show contents to the |
147 Private slot to move the widget upwards, i.e. show contents to the |
137 bottom. |
148 bottom. |
138 """ |
149 """ |
139 self.__slide(True) |
150 self.__slide(True) |
140 |
151 |
141 def __slideDown(self): |
152 def __slideDown(self): |
142 """ |
153 """ |
143 Private slot to move the widget downwards, i.e. show contents to |
154 Private slot to move the widget downwards, i.e. show contents to |
144 the top. |
155 the top. |
145 """ |
156 """ |
146 self.__slide(False) |
157 self.__slide(False) |
147 |
158 |
148 def __slide(self, up): |
159 def __slide(self, up): |
149 """ |
160 """ |
150 Private method to move the sliding widget. |
161 Private method to move the sliding widget. |
151 |
162 |
152 @param up flag indicating to move upwards (boolean) |
163 @param up flag indicating to move upwards (boolean) |
153 """ |
164 """ |
154 scrollBar = self.__scroller.verticalScrollBar() |
165 scrollBar = self.__scroller.verticalScrollBar() |
155 stepSize = scrollBar.singleStep() |
166 stepSize = scrollBar.singleStep() |
156 if up: |
167 if up: |
160 newValue = 0 |
171 newValue = 0 |
161 elif newValue > scrollBar.maximum(): |
172 elif newValue > scrollBar.maximum(): |
162 newValue = scrollBar.maximum() |
173 newValue = scrollBar.maximum() |
163 scrollBar.setValue(newValue) |
174 scrollBar.setValue(newValue) |
164 self.__enableScrollerButtons() |
175 self.__enableScrollerButtons() |
165 |
176 |
166 ####################################################################### |
177 ####################################################################### |
167 ## Methods below implement the format button functions |
178 ## Methods below implement the format button functions |
168 ####################################################################### |
179 ####################################################################### |
169 |
180 |
170 def __createButtons(self): |
181 def __createButtons(self): |
171 """ |
182 """ |
172 Private slot to create the various tool buttons. |
183 Private slot to create the various tool buttons. |
173 """ |
184 """ |
174 self.__buttons = {} |
185 self.__buttons = {} |
175 self.__separators = [] |
186 self.__separators = [] |
176 self.__headerMenu = QMenu() |
187 self.__headerMenu = QMenu() |
177 |
188 |
178 self.__addButton("bold", "formatTextBold", |
189 self.__addButton("bold", "formatTextBold", self.tr("Bold")) |
179 self.tr("Bold")) |
190 self.__addButton("italic", "formatTextItalic", self.tr("Italic")) |
180 self.__addButton("italic", "formatTextItalic", |
191 self.__addButton( |
181 self.tr("Italic")) |
192 "strikethrough", "formatTextStrikethrough", self.tr("Strike Through") |
182 self.__addButton("strikethrough", "formatTextStrikethrough", |
193 ) |
183 self.tr("Strike Through")) |
|
184 self.__addSeparator() |
194 self.__addSeparator() |
185 self.__addButton("header1", "formatTextHeader1", |
195 self.__addButton("header1", "formatTextHeader1", self.tr("Header 1")) |
186 self.tr("Header 1")) |
196 self.__addButton("header2", "formatTextHeader2", self.tr("Header 2")) |
187 self.__addButton("header2", "formatTextHeader2", |
197 self.__addButton("header3", "formatTextHeader3", self.tr("Header 3")) |
188 self.tr("Header 2")) |
198 button = self.__addButton("header", "formatTextHeader", self.tr("Header")) |
189 self.__addButton("header3", "formatTextHeader3", |
|
190 self.tr("Header 3")) |
|
191 button = self.__addButton("header", "formatTextHeader", |
|
192 self.tr("Header")) |
|
193 button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) |
199 button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) |
194 button.setMenu(self.__headerMenu) |
200 button.setMenu(self.__headerMenu) |
195 self.__addSeparator() |
201 self.__addSeparator() |
196 self.__addButton("code", "formatTextInlineCode", |
202 self.__addButton("code", "formatTextInlineCode", self.tr("Inline Code")) |
197 self.tr("Inline Code")) |
203 self.__addButton("codeBlock", "formatTextCodeBlock", self.tr("Code Block")) |
198 self.__addButton("codeBlock", "formatTextCodeBlock", |
204 self.__addButton("quote", "formatTextQuote", self.tr("Quote")) |
199 self.tr("Code Block")) |
|
200 self.__addButton("quote", "formatTextQuote", |
|
201 self.tr("Quote")) |
|
202 self.__addSeparator() |
205 self.__addSeparator() |
203 self.__addButton("hyperlink", "formatTextHyperlink", |
206 self.__addButton("hyperlink", "formatTextHyperlink", self.tr("Add Hyperlink")) |
204 self.tr("Add Hyperlink")) |
207 self.__addButton( |
205 self.__addButton("line", "formatTextHorizontalLine", |
208 "line", "formatTextHorizontalLine", self.tr("Add Horizontal Line") |
206 self.tr("Add Horizontal Line")) |
209 ) |
207 self.__addButton("image", "formatTextImage", |
210 self.__addButton("image", "formatTextImage", self.tr("Add Image")) |
208 self.tr("Add Image")) |
|
209 self.__addSeparator() |
211 self.__addSeparator() |
210 self.__addButton("bulletedList", "formatTextBulletedList", |
212 self.__addButton( |
211 self.tr("Add Bulleted List")) |
213 "bulletedList", "formatTextBulletedList", self.tr("Add Bulleted List") |
212 self.__addButton("numberedList", "formatTextNumberedList", |
214 ) |
213 self.tr("Add Numbered List")) |
215 self.__addButton( |
214 |
216 "numberedList", "formatTextNumberedList", self.tr("Add Numbered List") |
|
217 ) |
|
218 |
215 self.__headerMenu.triggered.connect(self.__headerMenuTriggered) |
219 self.__headerMenu.triggered.connect(self.__headerMenuTriggered) |
216 |
220 |
217 def __addButton(self, formatName, iconName, toolTip): |
221 def __addButton(self, formatName, iconName, toolTip): |
218 """ |
222 """ |
219 Private method to add a format button. |
223 Private method to add a format button. |
220 |
224 |
221 @param formatName unique name of the format |
225 @param formatName unique name of the format |
222 @type str |
226 @type str |
223 @param iconName name of the icon for the button |
227 @param iconName name of the icon for the button |
224 @type str |
228 @type str |
225 @param toolTip text for the tool tip |
229 @param toolTip text for the tool tip |
245 if isinstance(self.__layout, QVBoxLayout): |
249 if isinstance(self.__layout, QVBoxLayout): |
246 line.setFrameShape(QFrame.Shape.HLine) |
250 line.setFrameShape(QFrame.Shape.HLine) |
247 else: |
251 else: |
248 line.setFrameShape(QFrame.Shape.VLine) |
252 line.setFrameShape(QFrame.Shape.VLine) |
249 line.setFrameShadow(QFrame.Shadow.Sunken) |
253 line.setFrameShadow(QFrame.Shadow.Sunken) |
250 |
254 |
251 self.__layout.addWidget(line) |
255 self.__layout.addWidget(line) |
252 self.__separators.append(line) |
256 self.__separators.append(line) |
253 |
257 |
254 @pyqtSlot() |
258 @pyqtSlot() |
255 def __updateButtonStates(self): |
259 def __updateButtonStates(self): |
256 """ |
260 """ |
257 Private slot to change the button states. |
261 Private slot to change the button states. |
258 """ |
262 """ |
259 provider = MarkupProviders.getMarkupProvider(self.__editor) |
263 provider = MarkupProviders.getMarkupProvider(self.__editor) |
260 if ( |
264 if self.__provider is None or provider.kind() != self.__provider.kind(): |
261 self.__provider is None or |
|
262 provider.kind() != self.__provider.kind() |
|
263 ): |
|
264 self.__provider = provider |
265 self.__provider = provider |
265 |
266 |
266 self.__buttons["bold"].setEnabled(self.__provider.hasBold()) |
267 self.__buttons["bold"].setEnabled(self.__provider.hasBold()) |
267 self.__buttons["italic"].setEnabled(self.__provider.hasItalic()) |
268 self.__buttons["italic"].setEnabled(self.__provider.hasItalic()) |
268 self.__buttons["strikethrough"].setEnabled( |
269 self.__buttons["strikethrough"].setEnabled( |
269 self.__provider.hasStrikethrough()) |
270 self.__provider.hasStrikethrough() |
270 |
271 ) |
|
272 |
271 headerLevels = self.__provider.headerLevels() |
273 headerLevels = self.__provider.headerLevels() |
272 self.__buttons["header1"].setEnabled(headerLevels >= 1) |
274 self.__buttons["header1"].setEnabled(headerLevels >= 1) |
273 self.__buttons["header2"].setEnabled(headerLevels >= 2) |
275 self.__buttons["header2"].setEnabled(headerLevels >= 2) |
274 self.__buttons["header3"].setEnabled(headerLevels >= 3) |
276 self.__buttons["header3"].setEnabled(headerLevels >= 3) |
275 self.__buttons["header"].setEnabled(headerLevels > 3) |
277 self.__buttons["header"].setEnabled(headerLevels > 3) |
276 self.__headerMenu.clear() |
278 self.__headerMenu.clear() |
277 for level in range(1, headerLevels + 1): |
279 for level in range(1, headerLevels + 1): |
278 act = self.__headerMenu.addAction( |
280 act = self.__headerMenu.addAction(self.tr("Level {0}").format(level)) |
279 self.tr("Level {0}").format(level)) |
|
280 act.setData("header{0}".format(level)) |
281 act.setData("header{0}".format(level)) |
281 |
282 |
282 self.__buttons["code"].setEnabled(self.__provider.hasCode()) |
283 self.__buttons["code"].setEnabled(self.__provider.hasCode()) |
283 self.__buttons["codeBlock"].setEnabled( |
284 self.__buttons["codeBlock"].setEnabled(self.__provider.hasCodeBlock()) |
284 self.__provider.hasCodeBlock()) |
285 |
285 |
286 self.__buttons["bulletedList"].setEnabled(self.__provider.hasBulletedList()) |
286 self.__buttons["bulletedList"].setEnabled( |
287 self.__buttons["numberedList"].setEnabled(self.__provider.hasNumberedList()) |
287 self.__provider.hasBulletedList()) |
288 |
288 self.__buttons["numberedList"].setEnabled( |
|
289 self.__provider.hasNumberedList()) |
|
290 |
|
291 self.__editorSelectionChanged() |
289 self.__editorSelectionChanged() |
292 |
290 |
293 if Preferences.getEditor("HideFormatButtons"): |
291 if Preferences.getEditor("HideFormatButtons"): |
294 self.setVisible(self.__provider.kind() != "none") |
292 self.setVisible(self.__provider.kind() != "none") |
295 |
293 |
296 def __formatClicked(self, formatName): |
294 def __formatClicked(self, formatName): |
297 """ |
295 """ |
298 Private slot to handle a format button being clicked. |
296 Private slot to handle a format button being clicked. |
299 |
297 |
300 @param formatName format type of the button |
298 @param formatName format type of the button |
301 @type str |
299 @type str |
302 """ |
300 """ |
303 if formatName == "bold": |
301 if formatName == "bold": |
304 self.__provider.bold(self.__editor) |
302 self.__provider.bold(self.__editor) |
324 self.__provider.image(self.__editor) |
322 self.__provider.image(self.__editor) |
325 elif formatName == "bulletedList": |
323 elif formatName == "bulletedList": |
326 self.__provider.bulletedList(self.__editor) |
324 self.__provider.bulletedList(self.__editor) |
327 elif formatName == "numberedList": |
325 elif formatName == "numberedList": |
328 self.__provider.numberedList(self.__editor) |
326 self.__provider.numberedList(self.__editor) |
329 |
327 |
330 def __headerMenuTriggered(self, act): |
328 def __headerMenuTriggered(self, act): |
331 """ |
329 """ |
332 Private method handling the selection of a header menu entry. |
330 Private method handling the selection of a header menu entry. |
333 |
331 |
334 @param act action of the headers menu that was triggered |
332 @param act action of the headers menu that was triggered |
335 @type QAction |
333 @type QAction |
336 """ |
334 """ |
337 formatName = act.data() |
335 formatName = act.data() |
338 self.__formatClicked(formatName) |
336 self.__formatClicked(formatName) |
339 |
337 |
340 def __editorSelectionChanged(self): |
338 def __editorSelectionChanged(self): |
341 """ |
339 """ |
342 Private slot to handle a change of the editor's selection. |
340 Private slot to handle a change of the editor's selection. |
343 """ |
341 """ |
344 hasSelection = self.__editor.hasSelectedText() |
342 hasSelection = self.__editor.hasSelectedText() |
345 if self.__provider: |
343 if self.__provider: |
346 self.__buttons["quote"].setEnabled( |
344 self.__buttons["quote"].setEnabled( |
347 self.__provider.hasQuote() and ( |
345 self.__provider.hasQuote() |
348 self.__provider.kind() == "html" or hasSelection |
346 and (self.__provider.kind() == "html" or hasSelection) |
349 ) |
|
350 ) |
347 ) |
351 self.__buttons["hyperlink"].setEnabled( |
348 self.__buttons["hyperlink"].setEnabled( |
352 self.__provider.hasHyperlink() and not hasSelection) |
349 self.__provider.hasHyperlink() and not hasSelection |
|
350 ) |
353 self.__buttons["line"].setEnabled( |
351 self.__buttons["line"].setEnabled( |
354 self.__provider.hasLine() and not hasSelection) |
352 self.__provider.hasLine() and not hasSelection |
|
353 ) |
355 self.__buttons["image"].setEnabled( |
354 self.__buttons["image"].setEnabled( |
356 self.__provider.hasImage() and not hasSelection) |
355 self.__provider.hasImage() and not hasSelection |
357 |
356 ) |
|
357 |
358 def __editorSettingsRead(self): |
358 def __editorSettingsRead(self): |
359 """ |
359 """ |
360 Private slot to handle a change of the editor related settings. |
360 Private slot to handle a change of the editor related settings. |
361 """ |
361 """ |
362 if Preferences.getEditor("HideFormatButtons"): |
362 if Preferences.getEditor("HideFormatButtons"): |