KTextEditor

katemodemenulist.h
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 KATEMODEMENULIST_H
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
33namespace KTextEditor
34{
35class DocumentPrivate;
36class Document;
37}
38
39namespace KateModeMenuListData
40{
41class ListView;
42class ListItem;
43class SearchLine;
44class Factory;
45}
46
47class 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 */
57class KateModeMenuList : public QMenu
58{
59public:
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 */
69 AlignHDefault,
70 AlignHInverse,
71 AlignLeft,
72 AlignRight
73 };
74 /**
75 * Vertical Alignment with respect to the trigger button.
76 * "AlignVDefault" uses normal alignment (below the button) and "AlignTop"
77 * forces the alignment above the trigger button.
78 * @see setButton(), KateStatusBarOpenUpMenu::setVisible()
79 */
81 AlignVDefault,
82 AlignTop
83 };
84 /**
85 * Define if the trigger button label must be updated when selecting an item.
86 * @see setButton()
87 */
88 enum class AutoUpdateTextButton : bool;
89 /**
90 * Search bar position, above or below the list.
91 */
93 Top,
94 Bottom
95 };
96 /**
97 * Defines where the list will scroll after clearing the search or changing the view.
98 * @see setAutoScroll(), autoScroll()
99 */
101 ScrollToSelectedItem,
102 ScrollToTop
103 };
104
106 : QMenu(title, parent)
107 {
108 init();
109 }
110
111 /**
112 * Reload all items.
113 * @see KateModeManager::update()
114 */
115 void reloadItems();
116
117 /**
118 * Update the selected item in the list widget, but without changing
119 * the syntax highlighting in the document.
120 * This is useful for updating this menu, when changing the syntax highlighting
121 * from another menu, or from an external one. This doesn't hide or show the menu.
122 * @param nameMode Raw name of the syntax highlight definition. If it's empty,
123 * the "Normal" mode will be used.
124 * @return True if @p nameMode exists and is selected.
125 */
126 bool selectHighlightingFromExternal(const QString &nameMode);
127 /**
128 * Update the selected item in the list widget, but without changing
129 * the syntax highlighting in the document. This doesn't hide or show the menu.
130 * The menu is kept updated according to the active syntax highlighting,
131 * obtained from the KTextEditor::DocumentPrivate class.
132 * @return True if the item is selected correctly.
133 * @see KTextEditor::DocumentPrivate::fileType()
134 */
136
137 /**
138 * Set the button that shows this menu. It allows to update the label
139 * of the button and define the alignment of the menu with respect to it.
140 * This function doesn't call QPushButton::setMenu().
141 * @param button Trigger button.
142 * @param positionX Horizontal position of the menu with respect to the trigger button.
143 * @param positionY Vertical position of the menu with respect to the trigger button.
144 * @param autoUpdateTextButton Determines whether the text of the button should be
145 * changed when selecting an item from the menu.
146 *
147 * @see AlignmentHButton, AlignmentVButton, AutoUpdateTextButton
148 */
149 void setButton(QPushButton *button,
150 AlignmentHButton positionX = AlignHDefault,
151 AlignmentVButton positionY = AlignTop,
152 AutoUpdateTextButton autoUpdateTextButton = AutoUpdateTextButton(false));
153
154 /**
155 * Define the scroll when cleaning the search or changing the view.
156 * The default value is AutoScroll::ScrollToSelectedItem.
157 * @see AutoScroll
158 */
160 {
161 m_autoScroll = scroll;
162 }
163
164 /**
165 * Set document to apply the syntax highlighting.
166 * @see KTextEditor::DocumentPrivate
167 */
169
170protected:
174
175 /**
176 * Action when displaying the menu.
177 * Override from QWidget.
178 */
179 void showEvent(QShowEvent *event) override;
180
181private:
182 void init();
183
184 void onAboutToShowMenu();
185
186 /**
187 * Define the size of the list widget, in pixels. The @p width is also
188 * applied to the search bar. This does not recalculate the word wrap in items.
189 */
190 inline void setSizeList(const int height, const int width = 266);
191
192 /**
193 * Load the data model with the syntax highlighting definitions to show in the list.
194 */
195 void loadHighlightingModel();
196
197 /**
198 * Scroll the list, according to AutoScroll.
199 * @see AutoScroll
200 */
201 void autoScroll();
202
203 /**
204 * Set a custom word wrap on a text line, according to a maximum width (in pixels).
205 * @param text Line of text
206 * @param maxWidth Width of the text container, in pixels.
207 * @param fontMetrics Font metrics. See QWidget::fontMetrics()
208 */
209 QString setWordWrap(const QString &text, const int maxWidth, const QFontMetrics &fontMetrics) const;
210
211 /**
212 * Update the selected item in the list, with the active syntax highlighting.
213 * This method only changes the selected item, with the checkbox icon, doesn't apply
214 * syntax highlighting in the document or hides the menu.
215 * @see selectHighlighting(), selectHighlightingFromExternal(), selectHighlightingSetVisibility()
216 */
217 void updateSelectedItem(KateModeMenuListData::ListItem *item);
218
219 /**
220 * Select an item from the list and apply the syntax highlighting in the document.
221 * This is equivalent to the slot: KateModeMenuList::selectHighlighting().
222 * @param bHideMenu If the menu should be hidden after applying the highlight.
223 * @see selectHighlighting()
224 */
225 void selectHighlightingSetVisibility(QStandardItem *pItem, const bool bHideMenu);
226
227 /**
228 * Create a new section in the list of items and add it to the model.
229 * It corresponds to a separator line and a title.
230 * @param sectionName Section title.
231 * @param background Background color is generally transparent.
232 * @param bSeparator True if a separation line will also be created before the section title.
233 * @param modelPosition Position in the model where to insert the new section. If the value is
234 * less than zero, the section is added to the end of the list/model.
235 * @return A pointer to the item created with the section title.
236 */
237 KateModeMenuListData::ListItem *createSectionList(const QString &sectionName, const QBrush &background, bool bSeparator = true, int modelPosition = -1);
238
239 /**
240 * Load message when the list is empty in the search.
241 */
242 void loadEmptyMsg();
243
244 AutoScroll m_autoScroll = ScrollToSelectedItem;
245 AlignmentHButton m_positionX;
246 AlignmentVButton m_positionY;
247 AutoUpdateTextButton m_autoUpdateTextButton;
248
249 QPointer<QPushButton> m_pushButton = nullptr;
250 QLabel *m_emptyListMsg = nullptr;
251 QGridLayout *m_layoutList = nullptr;
252 QScrollBar *m_scroll = nullptr;
253
254 KateModeMenuListData::SearchLine *m_searchBar = nullptr;
255 KateModeMenuListData::ListView *m_list = nullptr;
256 QStandardItemModel *m_model = nullptr;
257
258 /**
259 * Item with active syntax highlighting.
260 */
261 KateModeMenuListData::ListItem *m_selectedItem = nullptr;
262
263 /**
264 * Icon for selected/active item (checkbox).
265 * NOTE: Selected and inactive items show an icon with incorrect color,
266 * however, this isn't a problem, since the list widget is never inactive.
267 */
268 const QIcon m_checkIcon = QIcon::fromTheme(QStringLiteral("checkbox"));
269 QIcon m_emptyIcon;
270 int m_iconSize = 16;
271
272 int m_defaultHeightItemSection;
273
275
276 bool m_initialized = false;
277
278private:
279 /**
280 * Action when selecting a item in the list. This also applies
281 * the syntax highlighting in the document and hides the menu.
282 * This is equivalent to KateModeMenuList::selectHighlightingSetVisibility().
283 * @see selectHighlightingSetVisibility(), updateSelectedItem()
284 */
285 void selectHighlighting(const QModelIndex &index);
286};
287
288namespace KateModeMenuListData
289{
290/**
291 * Class of List Widget.
292 */
293class ListView : public QListView
294{
295private:
297 : QListView(menu)
298 {
299 m_parentMenu = menu;
300 }
301
302public:
303 ~ListView() override
304 {
305 }
306
307 /**
308 * Define the size of the widget list.
309 * @p height and @p width are values in pixels.
310 */
311 void setSizeList(const int height, const int width = 266);
312
313 /**
314 * Get the width of the list, in pixels.
315 * @see QAbstractScrollArea::sizeHint()
316 */
317 inline int getWidth() const;
318
319 /**
320 * Get the width of the contents of the list (in pixels), that is,
321 * the list minus the scroll bar and margins.
322 */
323 int getContentWidth() const;
324
325 /**
326 * Get the width of the contents of the list (in pixels), that is, the list minus
327 * the scroll bar and margins. The parameter allows you to specify additional margins
328 * according to the scroll bar, which can be superimposed or fixed depending to the
329 * desktop environment or operating system.
330 * @param overlayScrollbarMargin Additional margin for the scroll bar, if it is
331 * superimposed on the list.
332 * @param classicScrollbarMargin Additional margin for the scroll bar, if fixed in the list.
333 */
334 inline int getContentWidth(const int overlayScrollbarMargin, const int classicScrollbarMargin) const;
335
336 inline void setCurrentItem(const int rowItem)
337 {
338 selectionModel()->setCurrentIndex(m_parentMenu->m_model->index(rowItem, 0), QItemSelectionModel::ClearAndSelect);
339 }
340
341 inline QStandardItem *currentItem() const
342 {
343 return m_parentMenu->m_model->item(currentIndex().row(), 0);
344 }
345
346 inline void scrollToItem(const int rowItem, QAbstractItemView::ScrollHint hint = QAbstractItemView::PositionAtCenter)
347 {
348 scrollTo(m_parentMenu->m_model->index(rowItem, 0), hint);
349 }
350
351 inline void scrollToFirstItem()
352 {
353 setCurrentItem(1);
354 scrollToTop();
355 }
356
357protected:
358 /**
359 * Override from QListView.
360 */
361 void keyPressEvent(QKeyEvent *event) override;
362
363private:
364 KateModeMenuList *m_parentMenu = nullptr;
365 friend Factory;
366};
367
368/**
369 * Class of an Item of the Data Model of the List.
370 * @see KateModeMenuListData::ListView, KateFileType, QStandardItemModel
371 */
373{
374private:
375 ListItem()
376 : QStandardItem()
377 {
378 }
379
380 const KateFileType *m_type = nullptr;
381 QString m_searchName;
382
383 friend Factory;
384
385public:
386 ~ListItem() override
387 {
388 }
389
390 /**
391 * Associate this item with a KateFileType object.
392 */
393 inline void setMode(KateFileType *type)
394 {
395 m_type = type;
396 }
397 const KateFileType *getMode() const
398 {
399 return m_type;
400 }
401 bool hasMode() const
402 {
403 return m_type;
404 }
405
406 /**
407 * Generate name of the item used for the search.
408 * @param itemName The item name.
409 * @return True if a new name is generated for the search.
410 */
411 bool generateSearchName(const QString &itemName);
412
413 /**
414 * Find matches in the extensions of the item mode, with a @p text.
415 * @param text Text to match, without dots or asterisks. For example, in
416 * a common extension, it corresponds to the text after "*."
417 * @return True if a match is found, false if not.
418 */
419 bool matchExtension(const QString &text) const;
420
421 const QString &getSearchName() const
422 {
423 return m_searchName;
424 }
425};
426
427/**
428 * Class of Search Bar.
429 * Based on the KListWidgetSearchLine class.
430 */
431class SearchLine : public QLineEdit
432{
433public:
434 ~SearchLine() override
435 {
436 m_bestResults.clear();
437 }
438
439 /**
440 * Define the width of the search bar, in pixels.
441 */
442 void setWidth(const int width);
443
444private:
446 : QLineEdit(menu)
447 {
448 m_parentMenu = menu;
449 init();
450 }
451
452 void init();
453
454 /**
455 * Select result of the items search.
456 * Used only by KateModeMenuListData::SearchLine::updateSearch().
457 */
458 void setSearchResult(const int rowItem, bool &bEmptySection, int &lastSection, int &firstSection, int &lastItem);
459
460 /**
461 * Delay in search results after typing, in milliseconds.
462 * Default value: 200
463 */
464 static const int m_searchDelay = 170;
465
466 /**
467 * This prevents auto-scrolling when the search is kept clean.
468 */
469 bool m_bSearchStateAutoScroll = false;
470
471 QString m_search = QString();
472 int m_queuedSearches = 0;
473 Qt::CaseSensitivity m_caseSensitivity = Qt::CaseInsensitive;
474
475 /**
476 * List of items to display in the "Best Search Matches" section. The integer value
477 * corresponds to the original position of the item in the model. The purpose of this
478 * is to restore the position of the items when starting or cleaning a search.
479 */
480 QList<QPair<ListItem *, int>> m_bestResults;
481
482 KateModeMenuList *m_parentMenu = nullptr;
483 friend Factory;
484 friend void KateModeMenuList::reloadItems();
485
486protected:
487 /**
488 * Override from QLineEdit. This allows you to navigate through
489 * the menu and write in the search bar simultaneously with the keyboard.
490 */
491 void keyPressEvent(QKeyEvent *event) override;
492
493public:
494 virtual void clear();
495 virtual void updateSearch(const QString &s = QString());
496
497private:
498 void _k_queueSearch(const QString &s);
499 void _k_activateSearch();
500};
501
502class Factory
503{
504private:
505 friend KateModeMenuList;
506 Factory() { };
507 static ListView *createListView(KateModeMenuList *parentMenu)
508 {
509 return new ListView(parentMenu);
510 }
511 static ListItem *createListItem()
512 {
513 return new ListItem();
514 }
515 static SearchLine *createSearchLine(KateModeMenuList *parentMenu)
516 {
517 return new SearchLine(parentMenu);
518 }
519};
520}
521
522#endif // KATEMODEMENULIST_H
A KParts derived class representing a text document.
Definition document.h:284
Class of an Item of the Data Model of the List.
void setMode(KateFileType *type)
Associate this item with a KateFileType object.
bool generateSearchName(const QString &itemName)
Generate name of the item used for the search.
bool matchExtension(const QString &text) const
Find matches in the extensions of the item mode, with a text.
void setSizeList(const int height, const int width=266)
Define the size of the widget list.
int getContentWidth() const
Get the width of the contents of the list (in pixels), that is, the list minus the scroll bar and mar...
int getWidth() const
Get the width of the list, in pixels.
void keyPressEvent(QKeyEvent *event) override
Override from QListView.
void setWidth(const int width)
Define the width of the search bar, in pixels.
void keyPressEvent(QKeyEvent *event) override
Override from QLineEdit.
Class of menu to select the syntax highlighting language (mode menu).
bool selectHighlightingFromExternal()
Update the selected item in the list widget, but without changing the syntax highlighting in the docu...
AlignmentVButton
Vertical Alignment with respect to the trigger button.
void updateMenu(KTextEditor::Document *doc)
Set document to apply the syntax highlighting.
void setAutoScroll(AutoScroll scroll)
Define the scroll when cleaning the search or changing the view.
AlignmentHButton
Horizontal Alignment with respect to the trigger button.
void reloadItems()
Reload all items.
void showEvent(QShowEvent *event) override
Action when displaying the menu.
AutoScroll
Defines where the list will scroll after clearing the search or changing the view.
SearchBarPosition
Search bar position, above or below the list.
void setButton(QPushButton *button, AlignmentHButton positionX=AlignHDefault, AlignmentVButton positionY=AlignTop, AutoUpdateTextButton autoUpdateTextButton=AutoUpdateTextButton(false))
Set the button that shows this menu.
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
QModelIndex currentIndex() const const
QItemSelectionModel * selectionModel() const const
QIcon fromTheme(const QString &name)
virtual void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
QLineEdit(QWidget *parent)
virtual bool event(QEvent *e) override
QListView(QWidget *parent)
virtual bool event(QEvent *e) override
virtual void scrollTo(const QModelIndex &index, ScrollHint hint) override
virtual bool event(QEvent *e) override
QObject * parent() const const
QString text() const const
virtual int type() const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
QStandardItem * item(int row, int column) const const
CaseSensitivity
QFontMetrics fontMetrics() const const
void scroll(int dx, int dy)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:11:27 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.