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 */
68 enum AlignmentHButton { AlignHDefault, AlignHInverse, AlignLeft, AlignRight };
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 AlignmentVButton { AlignVDefault, AlignTop };
76 /**
77 * Define if the trigger button label must be updated when selecting an item.
78 * @see setButton()
79 */
80 enum class AutoUpdateTextButton : bool;
81 /**
82 * Search bar position, above or below the list.
83 */
84 enum SearchBarPosition { Top, Bottom };
85 /**
86 * Defines where the list will scroll after clearing the search or changing the view.
87 * @see setAutoScroll(), autoScroll()
88 */
89 enum AutoScroll { ScrollToSelectedItem, ScrollToTop };
90
93 {
94 init();
95 }
96
97 /**
98 * Reload all items.
99 * @see KateModeManager::update()
100 */
101 void reloadItems();
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 selectHighlightingFromExternal(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 */
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 setButton(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 */
146 {
147 m_autoScroll = scroll;
148 }
149
150 /**
151 * Set document to apply the syntax highlighting.
152 * @see KTextEditor::DocumentPrivate
153 */
155
156protected:
160
161 /**
162 * Action when displaying the menu.
163 * Override from QWidget.
164 */
165 void showEvent(QShowEvent *event) override;
166
167private:
168 void init();
169
170 void onAboutToShowMenu();
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 setSizeList(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 loadHighlightingModel();
182
183 /**
184 * Scroll the list, according to AutoScroll.
185 * @see AutoScroll
186 */
187 void autoScroll();
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 setWordWrap(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 updateSelectedItem(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 bHideMenu);
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 *createSectionList(const QString &sectionName, 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 loadEmptyMsg();
229
230 AutoScroll m_autoScroll = ScrollToSelectedItem;
231 AlignmentHButton m_positionX;
232 AlignmentVButton m_positionY;
233 AutoUpdateTextButton m_autoUpdateTextButton;
234
235 QPointer<QPushButton> m_pushButton = nullptr;
236 QLabel *m_emptyListMsg = nullptr;
237 QGridLayout *m_layoutList = nullptr;
238 QScrollBar *m_scroll = nullptr;
239
240 KateModeMenuListData::SearchLine *m_searchBar = nullptr;
241 KateModeMenuListData::ListView *m_list = nullptr;
242 QStandardItemModel *m_model = nullptr;
243
244 /**
245 * Item with active syntax highlighting.
246 */
247 KateModeMenuListData::ListItem *m_selectedItem = 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 m_checkIcon = QIcon::fromTheme(QStringLiteral("checkbox"));
255 QIcon m_emptyIcon;
256 int m_iconSize = 16;
257
258 int m_defaultHeightItemSection;
259
261
262 bool m_initialized = false;
263
264private:
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 selectHighlighting(const QModelIndex &index);
272};
273
274namespace KateModeMenuListData
275{
276/**
277 * Class of List Widget.
278 */
279class ListView : public QListView
280{
281private:
283 : QListView(menu)
284 {
285 m_parentMenu = menu;
286 }
287
288public:
289 ~ListView() 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 setSizeList(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 getWidth() 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 getContentWidth() 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 getContentWidth(const int overlayScrollbarMargin, const int classicScrollbarMargin) const;
321
322 inline void setCurrentItem(const int rowItem)
323 {
324 selectionModel()->setCurrentIndex(m_parentMenu->m_model->index(rowItem, 0), QItemSelectionModel::ClearAndSelect);
325 }
326
327 inline QStandardItem *currentItem() const
328 {
329 return m_parentMenu->m_model->item(currentIndex().row(), 0);
330 }
331
332 inline void scrollToItem(const int rowItem, QAbstractItemView::ScrollHint hint = QAbstractItemView::PositionAtCenter)
333 {
334 scrollTo(m_parentMenu->m_model->index(rowItem, 0), hint);
335 }
336
337 inline void scrollToFirstItem()
338 {
339 setCurrentItem(1);
340 scrollToTop();
341 }
342
343protected:
344 /**
345 * Override from QListView.
346 */
347 void keyPressEvent(QKeyEvent *event) override;
348
349private:
350 KateModeMenuList *m_parentMenu = 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 */
359{
360private:
361 ListItem()
362 : QStandardItem()
363 {
364 }
365
366 const KateFileType *m_type = nullptr;
367 QString m_searchName;
368
369 friend Factory;
370
371public:
372 ~ListItem() override
373 {
374 }
375
376 /**
377 * Associate this item with a KateFileType object.
378 */
379 inline void setMode(KateFileType *type)
380 {
381 m_type = type;
382 }
383 const KateFileType *getMode() const
384 {
385 return m_type;
386 }
387 bool hasMode() 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 generateSearchName(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 matchExtension(const QString &text) const;
406
407 const QString &getSearchName() const
408 {
409 return m_searchName;
410 }
411};
412
413/**
414 * Class of Search Bar.
415 * Based on the KListWidgetSearchLine class.
416 */
417class SearchLine : public QLineEdit
418{
419public:
420 ~SearchLine() override
421 {
422 m_bestResults.clear();
423 }
424
425 /**
426 * Define the width of the search bar, in pixels.
427 */
428 void setWidth(const int width);
429
430private:
432 : QLineEdit(menu)
433 {
434 m_parentMenu = menu;
435 init();
436 }
437
438 void init();
439
440 /**
441 * Select result of the items search.
442 * Used only by KateModeMenuListData::SearchLine::updateSearch().
443 */
444 void setSearchResult(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 m_searchDelay = 170;
451
452 /**
453 * This prevents auto-scrolling when the search is kept clean.
454 */
455 bool m_bSearchStateAutoScroll = false;
456
457 QString m_search = QString();
458 int m_queuedSearches = 0;
459 Qt::CaseSensitivity m_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>> m_bestResults;
467
468 KateModeMenuList *m_parentMenu = nullptr;
469 friend Factory;
470 friend void KateModeMenuList::reloadItems();
471
472protected:
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 keyPressEvent(QKeyEvent *event) override;
478
479public:
480 virtual void clear();
481 virtual void updateSearch(const QString &s = QString());
482
483private:
484 void _k_queueSearch(const QString &s);
485 void _k_activateSearch();
486};
487
488class Factory
489{
490private:
491 friend KateModeMenuList;
492 Factory(){};
493 static ListView *createListView(KateModeMenuList *parentMenu)
494 {
495 return new ListView(parentMenu);
496 }
497 static ListItem *createListItem()
498 {
499 return new ListItem();
500 }
501 static SearchLine *createSearchLine(KateModeMenuList *parentMenu)
502 {
503 return new SearchLine(parentMenu);
504 }
505};
506}
507
508#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, QAbstractItemView::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 Sat Feb 24 2024 20:00:58 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.