1 | /* |
2 | SPDX-FileCopyrightText: 2019-2020 Nibaldo González S. <nibgonz@gmail.com> |
3 | |
4 | SPDX-License-Identifier: LGPL-2.0-or-later |
5 | */ |
6 | |
7 | /* |
8 | * NOTE: The KateModeMenuListData::SearchLine class is based on |
9 | * KListWidgetSearchLine, by Scott Wheeler <wheeler@kde.org> and |
10 | * Gustavo Sverzut Barbieri <gsbarbieri@users.sourceforge.net>. |
11 | * See: https://api.kde.org/frameworks/kitemviews/html/classKListWidgetSearchLine.html |
12 | * |
13 | * TODO: Add keyboard shortcut to show the menu. |
14 | * See: KateModeMenuList::showEvent() |
15 | */ |
16 | |
17 | #ifndef KATEMODEMENULIST_H |
18 | #define |
19 | |
20 | #include <QGridLayout> |
21 | #include <QIcon> |
22 | #include <QKeyEvent> |
23 | #include <QLabel> |
24 | #include <QLineEdit> |
25 | #include <QListView> |
26 | #include <QMenu> |
27 | #include <QPointer> |
28 | #include <QPushButton> |
29 | #include <QScrollBar> |
30 | #include <QStandardItemModel> |
31 | #include <QString> |
32 | |
33 | namespace KTextEditor |
34 | { |
35 | class DocumentPrivate; |
36 | class Document; |
37 | } |
38 | |
39 | namespace KateModeMenuListData |
40 | { |
41 | class ListView; |
42 | class ListItem; |
43 | class SearchLine; |
44 | class Factory; |
45 | } |
46 | |
47 | class KateFileType; |
48 | /** |
49 | * Class of menu to select the |
50 | * syntax highlighting language (mode menu). |
51 | * Provides a menu with a scrollable list plus search bar. |
52 | * |
53 | * This is an alternative to the classic mode menu of the KateModeMenu class. |
54 | * |
55 | * @see KateModeManager, KateFileType, KateModeMenu |
56 | */ |
57 | class : public QMenu |
58 | { |
59 | public: |
60 | /** |
61 | * Horizontal Alignment with respect to the trigger button. |
62 | * "AlignHDefault" is the normal alignment. |
63 | * "AlignHInverse" uses right alignment in Left-to-right layouts and |
64 | * left alignmentnin Right-to-left layouts (used in some languages). |
65 | * "AlignLeft" and "AlignRight" forces the alignment, regardless of the layout direction. |
66 | * @see setButton(), QWidget::layoutDirection(), Qt::LayoutDirection |
67 | */ |
68 | enum { , , , }; |
69 | /** |
70 | * Vertical Alignment with respect to the trigger button. |
71 | * "AlignVDefault" uses normal alignment (below the button) and "AlignTop" |
72 | * forces the alignment above the trigger button. |
73 | * @see setButton(), KateStatusBarOpenUpMenu::setVisible() |
74 | */ |
75 | enum { , }; |
76 | /** |
77 | * Define if the trigger button label must be updated when selecting an item. |
78 | * @see setButton() |
79 | */ |
80 | enum class : bool; |
81 | /** |
82 | * Search bar position, above or below the list. |
83 | */ |
84 | enum { , }; |
85 | /** |
86 | * Defines where the list will scroll after clearing the search or changing the view. |
87 | * @see setAutoScroll(), autoScroll() |
88 | */ |
89 | enum { , }; |
90 | |
91 | (const QString &title, QWidget *parent) |
92 | : QMenu(title, parent) |
93 | { |
94 | init(); |
95 | } |
96 | |
97 | /** |
98 | * Reload all items. |
99 | * @see KateModeManager::update() |
100 | */ |
101 | void (); |
102 | |
103 | /** |
104 | * Update the selected item in the list widget, but without changing |
105 | * the syntax highlighting in the document. |
106 | * This is useful for updating this menu, when changing the syntax highlighting |
107 | * from another menu, or from an external one. This doesn't hide or show the menu. |
108 | * @param nameMode Raw name of the syntax highlight definition. If it's empty, |
109 | * the "Normal" mode will be used. |
110 | * @return True if @p nameMode exists and is selected. |
111 | */ |
112 | bool (const QString &nameMode); |
113 | /** |
114 | * Update the selected item in the list widget, but without changing |
115 | * the syntax highlighting in the document. This doesn't hide or show the menu. |
116 | * The menu is kept updated according to the active syntax highlighting, |
117 | * obtained from the KTextEditor::DocumentPrivate class. |
118 | * @return True if the item is selected correctly. |
119 | * @see KTextEditor::DocumentPrivate::fileType() |
120 | */ |
121 | bool (); |
122 | |
123 | /** |
124 | * Set the button that shows this menu. It allows to update the label |
125 | * of the button and define the alignment of the menu with respect to it. |
126 | * This function doesn't call QPushButton::setMenu(). |
127 | * @param button Trigger button. |
128 | * @param positionX Horizontal position of the menu with respect to the trigger button. |
129 | * @param positionY Vertical position of the menu with respect to the trigger button. |
130 | * @param autoUpdateTextButton Determines whether the text of the button should be |
131 | * changed when selecting an item from the menu. |
132 | * |
133 | * @see AlignmentHButton, AlignmentVButton, AutoUpdateTextButton |
134 | */ |
135 | void (QPushButton *button, |
136 | AlignmentHButton positionX = AlignHDefault, |
137 | AlignmentVButton positionY = AlignTop, |
138 | AutoUpdateTextButton autoUpdateTextButton = AutoUpdateTextButton(false)); |
139 | |
140 | /** |
141 | * Define the scroll when cleaning the search or changing the view. |
142 | * The default value is AutoScroll::ScrollToSelectedItem. |
143 | * @see AutoScroll |
144 | */ |
145 | void (AutoScroll scroll) |
146 | { |
147 | m_autoScroll = scroll; |
148 | } |
149 | |
150 | /** |
151 | * Set document to apply the syntax highlighting. |
152 | * @see KTextEditor::DocumentPrivate |
153 | */ |
154 | void (KTextEditor::Document *doc); |
155 | |
156 | protected: |
157 | friend KateModeMenuListData::ListView; |
158 | friend KateModeMenuListData::ListItem; |
159 | friend KateModeMenuListData::SearchLine; |
160 | |
161 | /** |
162 | * Action when displaying the menu. |
163 | * Override from QWidget. |
164 | */ |
165 | void (QShowEvent *event) override; |
166 | |
167 | private: |
168 | void (); |
169 | |
170 | void (); |
171 | |
172 | /** |
173 | * Define the size of the list widget, in pixels. The @p width is also |
174 | * applied to the search bar. This does not recalculate the word wrap in items. |
175 | */ |
176 | inline void (const int height, const int width = 266); |
177 | |
178 | /** |
179 | * Load the data model with the syntax highlighting definitions to show in the list. |
180 | */ |
181 | void (); |
182 | |
183 | /** |
184 | * Scroll the list, according to AutoScroll. |
185 | * @see AutoScroll |
186 | */ |
187 | void (); |
188 | |
189 | /** |
190 | * Set a custom word wrap on a text line, according to a maximum width (in pixels). |
191 | * @param text Line of text |
192 | * @param maxWidth Width of the text container, in pixels. |
193 | * @param fontMetrics Font metrics. See QWidget::fontMetrics() |
194 | */ |
195 | QString (const QString &text, const int maxWidth, const QFontMetrics &fontMetrics) const; |
196 | |
197 | /** |
198 | * Update the selected item in the list, with the active syntax highlighting. |
199 | * This method only changes the selected item, with the checkbox icon, doesn't apply |
200 | * syntax highlighting in the document or hides the menu. |
201 | * @see selectHighlighting(), selectHighlightingFromExternal(), selectHighlightingSetVisibility() |
202 | */ |
203 | void (KateModeMenuListData::ListItem *item); |
204 | |
205 | /** |
206 | * Select an item from the list and apply the syntax highlighting in the document. |
207 | * This is equivalent to the slot: KateModeMenuList::selectHighlighting(). |
208 | * @param bHideMenu If the menu should be hidden after applying the highlight. |
209 | * @see selectHighlighting() |
210 | */ |
211 | void selectHighlightingSetVisibility(QStandardItem *pItem, const bool ); |
212 | |
213 | /** |
214 | * Create a new section in the list of items and add it to the model. |
215 | * It corresponds to a separator line and a title. |
216 | * @param sectionName Section title. |
217 | * @param background Background color is generally transparent. |
218 | * @param bSeparator True if a separation line will also be created before the section title. |
219 | * @param modelPosition Position in the model where to insert the new section. If the value is |
220 | * less than zero, the section is added to the end of the list/model. |
221 | * @return A pointer to the item created with the section title. |
222 | */ |
223 | KateModeMenuListData::ListItem *(const QString §ionName, const QBrush &background, bool bSeparator = true, int modelPosition = -1); |
224 | |
225 | /** |
226 | * Load message when the list is empty in the search. |
227 | */ |
228 | void (); |
229 | |
230 | AutoScroll = ScrollToSelectedItem; |
231 | AlignmentHButton ; |
232 | AlignmentVButton ; |
233 | AutoUpdateTextButton ; |
234 | |
235 | QPointer<QPushButton> = nullptr; |
236 | QLabel * = nullptr; |
237 | QGridLayout * = nullptr; |
238 | QScrollBar * = nullptr; |
239 | |
240 | KateModeMenuListData::SearchLine * = nullptr; |
241 | KateModeMenuListData::ListView * = nullptr; |
242 | QStandardItemModel * = nullptr; |
243 | |
244 | /** |
245 | * Item with active syntax highlighting. |
246 | */ |
247 | KateModeMenuListData::ListItem * = nullptr; |
248 | |
249 | /** |
250 | * Icon for selected/active item (checkbox). |
251 | * NOTE: Selected and inactive items show an icon with incorrect color, |
252 | * however, this isn't a problem, since the list widget is never inactive. |
253 | */ |
254 | const QIcon = QIcon::fromTheme(QStringLiteral("checkbox" )); |
255 | QIcon ; |
256 | int = 16; |
257 | |
258 | int ; |
259 | |
260 | QPointer<KTextEditor::DocumentPrivate> ; |
261 | |
262 | bool = false; |
263 | |
264 | private: |
265 | /** |
266 | * Action when selecting a item in the list. This also applies |
267 | * the syntax highlighting in the document and hides the menu. |
268 | * This is equivalent to KateModeMenuList::selectHighlightingSetVisibility(). |
269 | * @see selectHighlightingSetVisibility(), updateSelectedItem() |
270 | */ |
271 | void (const QModelIndex &index); |
272 | }; |
273 | |
274 | namespace KateModeMenuListData |
275 | { |
276 | /** |
277 | * Class of List Widget. |
278 | */ |
279 | class : public QListView |
280 | { |
281 | private: |
282 | (KateModeMenuList *) |
283 | : QListView(menu) |
284 | { |
285 | m_parentMenu = menu; |
286 | } |
287 | |
288 | public: |
289 | () override |
290 | { |
291 | } |
292 | |
293 | /** |
294 | * Define the size of the widget list. |
295 | * @p height and @p width are values in pixels. |
296 | */ |
297 | void (const int height, const int width = 266); |
298 | |
299 | /** |
300 | * Get the width of the list, in pixels. |
301 | * @see QAbstractScrollArea::sizeHint() |
302 | */ |
303 | inline int () const; |
304 | |
305 | /** |
306 | * Get the width of the contents of the list (in pixels), that is, |
307 | * the list minus the scroll bar and margins. |
308 | */ |
309 | int () const; |
310 | |
311 | /** |
312 | * Get the width of the contents of the list (in pixels), that is, the list minus |
313 | * the scroll bar and margins. The parameter allows you to specify additional margins |
314 | * according to the scroll bar, which can be superimposed or fixed depending to the |
315 | * desktop environment or operating system. |
316 | * @param overlayScrollbarMargin Additional margin for the scroll bar, if it is |
317 | * superimposed on the list. |
318 | * @param classicScrollbarMargin Additional margin for the scroll bar, if fixed in the list. |
319 | */ |
320 | inline int (const int overlayScrollbarMargin, const int classicScrollbarMargin) const; |
321 | |
322 | inline void (const int rowItem) |
323 | { |
324 | selectionModel()->setCurrentIndex(index: m_parentMenu->m_model->index(row: rowItem, column: 0), command: QItemSelectionModel::ClearAndSelect); |
325 | } |
326 | |
327 | inline QStandardItem *() const |
328 | { |
329 | return m_parentMenu->m_model->item(row: currentIndex().row(), column: 0); |
330 | } |
331 | |
332 | inline void (const int rowItem, QAbstractItemView::ScrollHint hint = QAbstractItemView::PositionAtCenter) |
333 | { |
334 | scrollTo(index: m_parentMenu->m_model->index(row: rowItem, column: 0), hint); |
335 | } |
336 | |
337 | inline void () |
338 | { |
339 | setCurrentItem(1); |
340 | scrollToTop(); |
341 | } |
342 | |
343 | protected: |
344 | /** |
345 | * Override from QListView. |
346 | */ |
347 | void (QKeyEvent *event) override; |
348 | |
349 | private: |
350 | KateModeMenuList * = nullptr; |
351 | friend Factory; |
352 | }; |
353 | |
354 | /** |
355 | * Class of an Item of the Data Model of the List. |
356 | * @see KateModeMenuListData::ListView, KateFileType, QStandardItemModel |
357 | */ |
358 | class : public QStandardItem |
359 | { |
360 | private: |
361 | () |
362 | : QStandardItem() |
363 | { |
364 | } |
365 | |
366 | const KateFileType * = nullptr; |
367 | QString ; |
368 | |
369 | friend Factory; |
370 | |
371 | public: |
372 | () override |
373 | { |
374 | } |
375 | |
376 | /** |
377 | * Associate this item with a KateFileType object. |
378 | */ |
379 | inline void (KateFileType *type) |
380 | { |
381 | m_type = type; |
382 | } |
383 | const KateFileType *() const |
384 | { |
385 | return m_type; |
386 | } |
387 | bool () const |
388 | { |
389 | return m_type; |
390 | } |
391 | |
392 | /** |
393 | * Generate name of the item used for the search. |
394 | * @param itemName The item name. |
395 | * @return True if a new name is generated for the search. |
396 | */ |
397 | bool (const QString &itemName); |
398 | |
399 | /** |
400 | * Find matches in the extensions of the item mode, with a @p text. |
401 | * @param text Text to match, without dots or asterisks. For example, in |
402 | * a common extension, it corresponds to the text after "*." |
403 | * @return True if a match is found, false if not. |
404 | */ |
405 | bool (const QString &text) const; |
406 | |
407 | const QString &() const |
408 | { |
409 | return m_searchName; |
410 | } |
411 | }; |
412 | |
413 | /** |
414 | * Class of Search Bar. |
415 | * Based on the KListWidgetSearchLine class. |
416 | */ |
417 | class : public QLineEdit |
418 | { |
419 | public: |
420 | () override |
421 | { |
422 | m_bestResults.clear(); |
423 | } |
424 | |
425 | /** |
426 | * Define the width of the search bar, in pixels. |
427 | */ |
428 | void (const int width); |
429 | |
430 | private: |
431 | (KateModeMenuList *) |
432 | : QLineEdit(menu) |
433 | { |
434 | m_parentMenu = menu; |
435 | init(); |
436 | } |
437 | |
438 | void (); |
439 | |
440 | /** |
441 | * Select result of the items search. |
442 | * Used only by KateModeMenuListData::SearchLine::updateSearch(). |
443 | */ |
444 | void (const int rowItem, bool &bEmptySection, int &lastSection, int &firstSection, int &lastItem); |
445 | |
446 | /** |
447 | * Delay in search results after typing, in milliseconds. |
448 | * Default value: 200 |
449 | */ |
450 | static const int = 170; |
451 | |
452 | /** |
453 | * This prevents auto-scrolling when the search is kept clean. |
454 | */ |
455 | bool = false; |
456 | |
457 | QString = QString(); |
458 | int = 0; |
459 | Qt::CaseSensitivity = Qt::CaseInsensitive; |
460 | |
461 | /** |
462 | * List of items to display in the "Best Search Matches" section. The integer value |
463 | * corresponds to the original position of the item in the model. The purpose of this |
464 | * is to restore the position of the items when starting or cleaning a search. |
465 | */ |
466 | QList<QPair<ListItem *, int>> ; |
467 | |
468 | KateModeMenuList * = nullptr; |
469 | friend Factory; |
470 | friend void KateModeMenuList::(); |
471 | |
472 | protected: |
473 | /** |
474 | * Override from QLineEdit. This allows you to navigate through |
475 | * the menu and write in the search bar simultaneously with the keyboard. |
476 | */ |
477 | void (QKeyEvent *event) override; |
478 | |
479 | public: |
480 | virtual void (); |
481 | virtual void (const QString &s = QString()); |
482 | |
483 | private: |
484 | void (const QString &s); |
485 | void (); |
486 | }; |
487 | |
488 | class |
489 | { |
490 | private: |
491 | friend KateModeMenuList; |
492 | (){}; |
493 | static ListView *(KateModeMenuList *) |
494 | { |
495 | return new ListView(parentMenu); |
496 | } |
497 | static ListItem *() |
498 | { |
499 | return new ListItem(); |
500 | } |
501 | static SearchLine *(KateModeMenuList *) |
502 | { |
503 | return new SearchLine(parentMenu); |
504 | } |
505 | }; |
506 | } |
507 | |
508 | #endif // KATEMODEMENULIST_H |
509 | |