KTextEditor

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

KDE's Doxygen guidelines are available online.