1/*
2 This file is part of the KDE libraries
3
4 SPDX-FileCopyrightText: 2000, 2001 Dawit Alemayehu <adawit@kde.org>
5 SPDX-FileCopyrightText: 2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.1-or-later
8*/
9
10#ifndef KCOMBOBOX_H
11#define KCOMBOBOX_H
12
13#include <kcompletion.h>
14
15#include <kcompletion_export.h>
16#include <kcompletionbase.h>
17
18#include <QComboBox>
19#include <memory>
20
21class KCompletionBox;
22class KComboBoxPrivate;
23
24class QLineEdit;
25class QMenu;
26
27/**
28 * @class KComboBox kcombobox.h KComboBox
29 *
30 * @short A combo box with completion support.
31 *
32 * This widget inherits from QComboBox and implements the following
33 * additional features:
34 * @li a completion object that provides both automatic
35 * and manual text completion as well as text rotation
36 * @li configurable key bindings to activate these features
37 * @li a popup menu item that can be used to allow the user to change
38 * the text completion mode on the fly.
39 *
40 * To support these additional features, KComboBox emits a few additional signals
41 * such as completion(const QString&) and textRotation(KeyBindingType).
42 *
43 * The completion signal can be connected to a slot that will assist the user in
44 * filling out the remaining text while the rotation signal can be used to traverse
45 * through all possible matches whenever text completion results in multiple matches.
46 * Additionally, the returnPressed(const QString &) signal is emitted when the user
47 * presses the Return or Enter key.
48 *
49 * KCombobox by default creates a completion object when you invoke the
50 * completionObject(bool) member function for the first time or
51 * explicitly use setCompletionObject(KCompletion*, bool) to assign your
52 * own completion object. Additionally, to make this widget more functional,
53 * KComboBox will by default handle text rotation and completion events
54 * internally whenever a completion object is created through either one of the
55 * methods mentioned above. If you do not need this functionality, simply use
56 * KCompletionBase::setHandleSignals(bool) or alternatively set the boolean
57 * parameter in the @c setCompletionObject() call to @c false.
58 *
59 * Beware: The completion object can be deleted on you, especially if a call
60 * such as setEditable(false) is made. Store the pointer at your own risk,
61 * and consider using QPointer<KCompletion>.
62 *
63 * The default key bindings for completion and rotation are determined from the
64 * global settings in KStandardShortcut. These values, however, can be overridden
65 * locally by invoking KCompletionBase::setKeyBinding(). The values can
66 * easily be reverted back to the default settings by calling
67 * useGlobalSettings(). An alternate method would be to default individual
68 * key bindings by using setKeyBinding() with the default second argument.
69 *
70 * A non-editable combo box only has one completion mode, @c CompletionAuto.
71 * Unlike an editable combo box, the CompletionAuto mode works by matching
72 * any typed key with the first letter of entries in the combo box. Please note
73 * that if you call setEditable(false) to change an editable combo box to a
74 * non-editable one, the text completion object associated with the combo box will
75 * no longer exist unless you created the completion object yourself and assigned
76 * it to this widget or you called setAutoDeleteCompletionObject(false). In other
77 * words do not do the following:
78 *
79 * \code
80 * KComboBox* combo = new KComboBox(true, this);
81 * KCompletion* comp = combo->completionObject();
82 * combo->setEditable(false);
83 * comp->clear(); // CRASH: completion object does not exist anymore.
84 * \endcode
85 *
86 *
87 * A read-only KComboBox will have the same background color as a
88 * disabled KComboBox, but its foreground color will be the one used for
89 * the editable mode. This differs from QComboBox's implementation
90 * and is done to give visual distinction between the three different modes:
91 * disabled, read-only, and editable.
92 *
93 * \b Usage
94 *
95 * To enable the basic completion feature:
96 *
97 * \code
98 * KComboBox *combo = new KComboBox(true, this);
99 * KCompletion *comp = combo->completionObject();
100 * // Connect to the Return pressed signal - optional
101 * connect(combo, &KComboBox::returnPressed, comp, [this](const QString &text) { addItem(text); });
102 *
103 * // Provide the to be completed strings. Note that those are separate from the combo's
104 * // contents.
105 * comp->insertItems(someQStringList);
106 * \endcode
107 *
108 * To use your own completion object:
109 *
110 * \code
111 * KComboBox *combo = new KComboBox(this);
112 * KUrlCompletion *comp = new KUrlCompletion();
113 * // You can either delete the allocated completion object manually when you
114 * // don't need it anymore, or call setAutoDeleteCompletionObject(true) and it
115 * // will be deleted automatically
116 * comp->setAutoDeleteCompletionObject(true);
117 * combo->setCompletionObject(comp);
118 * // Connect to the return pressed signal - optional
119 * connect(combo, &KComboBox::returnPressed, comp, [this](const QString &text) { addItem(text); });
120 * \endcode
121 *
122 * Miscellaneous function calls:
123 *
124 * \code
125 * // Tell the widget not to handle completion and rotation
126 * combo->setHandleSignals(false);
127 * // Set your own completion key for manual completions.
128 * combo->setKeyBinding(KCompletionBase::TextCompletion, Qt::End);
129 * \endcode
130 *
131 * \image html kcombobox.png "KComboBox widgets, one non-editable, one editable with KUrlCompletion"
132 *
133 * @author Dawit Alemayehu <adawit@kde.org>
134 */
135class KCOMPLETION_EXPORT KComboBox : public QComboBox, public KCompletionBase // krazy:exclude=qclasses
136{
137 Q_OBJECT
138 Q_PROPERTY(bool autoCompletion READ autoCompletion WRITE setAutoCompletion)
139 Q_PROPERTY(bool trapReturnKey READ trapReturnKey WRITE setTrapReturnKey)
140
141public:
142 /**
143 * Constructs a read-only (or rather select-only) combo box.
144 *
145 * @param parent The parent object of this widget
146 */
147 explicit KComboBox(QWidget *parent = nullptr);
148
149 /**
150 * Constructs an editable or read-only combo box.
151 *
152 * @param rw When @c true, widget will be editable.
153 * @param parent The parent object of this widget.
154 */
155 explicit KComboBox(bool rw, QWidget *parent = nullptr);
156
157 /**
158 * Destructor.
159 */
160 ~KComboBox() override;
161
162 /**
163 * Sets @p url into the edit field of the combo box.
164 *
165 * It uses QUrl::toDisplayString() so that the url is properly decoded for
166 * displaying.
167 */
168 void setEditUrl(const QUrl &url);
169
170 /**
171 * Appends @p url to the combo box.
172 *
173 * QUrl::toDisplayString() is used so that the url is properly decoded
174 * for displaying.
175 */
176 void addUrl(const QUrl &url);
177
178 /**
179 * Appends @p url with the @p icon to the combo box.
180 *
181 * QUrl::toDisplayString() is used so that the url is properly decoded
182 * for displaying.
183 */
184 void addUrl(const QIcon &icon, const QUrl &url);
185
186 /**
187 * Inserts @p url at position @p index into the combo box.
188 *
189 * QUrl::toDisplayString() is used so that the url is properly decoded
190 * for displaying.
191 */
192 void insertUrl(int index, const QUrl &url);
193
194 /**
195 * Inserts @p url with the @p icon at position @p index into
196 * the combo box.
197 *
198 * QUrl::toDisplayString() is used so that the url is
199 * properly decoded for displaying.
200 */
201 void insertUrl(int index, const QIcon &icon, const QUrl &url);
202
203 /**
204 * Replaces the item at position @p index with @p url.
205 *
206 * QUrl::toDisplayString() is used so that the url is properly decoded
207 * for displaying.
208 */
209 void changeUrl(int index, const QUrl &url);
210
211 /**
212 * Replaces the item at position @p index with @p url and @p icon.
213 *
214 * QUrl::toDisplayString() is used so that the url is properly decoded
215 * for displaying.
216 */
217 void changeUrl(int index, const QIcon &icon, const QUrl &url);
218
219 /**
220 * Returns the current cursor position.
221 *
222 * This method always returns a -1 if the combo box is @em not
223 * editable (read-only).
224 *
225 * @return Current cursor position.
226 */
227 int cursorPosition() const;
228
229 /**
230 * Reimplemented from QComboBox.
231 *
232 * If @c true, the completion mode will be set to automatic.
233 * Otherwise, it is defaulted to the global setting. This
234 * method has been replaced by the more comprehensive
235 * setCompletionMode().
236 *
237 * @param autocomplete Flag to enable/disable automatic completion mode.
238 */
239 virtual void setAutoCompletion(bool autocomplete);
240
241 /**
242 * Reimplemented from QComboBox.
243 *
244 * Returns @c true if the current completion mode is set
245 * to automatic. See its more comprehensive replacement
246 * completionMode().
247 *
248 * @return @c true when completion mode is automatic.
249 */
250 bool autoCompletion() const;
251
252 /**
253 * Returns @c true when decoded URL drops are enabled
254 */
255 bool urlDropsEnabled() const;
256
257 /**
258 * Convenience method which iterates over all items and checks if
259 * any of them is equal to @p text.
260 *
261 * If @p text is an empty string, @c false
262 * is returned.
263 *
264 * @return @c true if an item with the string @p text is in the combo box.
265 */
266 bool contains(const QString &text) const;
267
268 /**
269 * By default, KComboBox recognizes Key_Return and Key_Enter and emits the
270 * returnPressed(const QString &) signal, but it also lets the event pass,
271 * for example causing a dialog's default button to be called.
272 *
273 * Call this method with @p trap set to true to make KComboBox stop these
274 * events. The signals will still be emitted of course.
275 *
276 * @note This only affects editable combo boxes.
277 *
278 * @see setTrapReturnKey()
279 */
280 void setTrapReturnKey(bool trap);
281
282 /**
283 * @return @c true if Key_Return or Key_Enter input events will be stopped or
284 * @c false if they will be propagated.
285 *
286 * @see setTrapReturnKey()
287 */
288 bool trapReturnKey() const;
289
290 /**
291 * This method will create a completion box by calling
292 * KLineEdit::completionBox, if none is there yet.
293 *
294 * @param create Set this to false if you don't want the box to be created
295 * i.e. to test if it is available.
296 * @returns the completion box that is used in completion mode
297 * CompletionPopup and CompletionPopupAuto.
298 */
299 KCompletionBox *completionBox(bool create = true);
300
301 /**
302 * Reimplemented for internal reasons. API remains unaffected.
303 * Note that QComboBox::setLineEdit is not virtual in Qt4, do not
304 * use a KComboBox in a QComboBox pointer.
305 *
306 * NOTE: Only editable combo boxes can have a line editor. As such
307 * any attempt to assign a line edit to a non-editable combo box will
308 * simply be ignored.
309 */
310 virtual void setLineEdit(QLineEdit *);
311
312 /**
313 * Reimplemented so that setEditable(true) creates a KLineEdit
314 * instead of QLineEdit.
315 *
316 * Note that QComboBox::setEditable is not virtual, so do not
317 * use a KComboBox in a QComboBox pointer.
318 */
319 void setEditable(bool editable);
320
321 /**
322 * Pointer to KLineEdit's context menu, or nullptr if it does not exist at
323 * the given moment.
324 *
325 * @since 5.78
326 */
327 QMenu *contextMenu() const;
328
329 QSize minimumSizeHint() const override;
330
331Q_SIGNALS:
332 /**
333 * Emitted when the user presses the Return or Enter key.
334 *
335 * The argument is the current text being edited.
336 *
337 * @note This signal is only emitted when the widget is editable.
338 *
339 */
340 void returnPressed(const QString &text); // clazy:exclude=overloaded-signal
341
342 /**
343 * Emitted when the completion key is pressed.
344 *
345 * The argument is the current text being edited.
346 *
347 * Note that this signal is @em not available when the widget is non-editable
348 * or the completion mode is set to @c CompletionNone.
349 */
350 void completion(const QString &);
351
352 /**
353 * Emitted when the shortcut for substring completion is pressed.
354 */
355 void substringCompletion(const QString &);
356
357 /**
358 * Emitted when the text rotation key bindings are pressed.
359 *
360 * The argument indicates which key binding was pressed. In this case this
361 * can be either one of four values: @c PrevCompletionMatch,
362 * @c NextCompletionMatch, @c RotateUp or @c RotateDown.
363 *
364 * Note that this signal is @em not emitted if the completion
365 * mode is set to CompletionNone.
366 *
367 * @see KCompletionBase::setKeyBinding() for details
368 */
369 void textRotation(KCompletionBase::KeyBindingType);
370
371 /**
372 * Emitted whenever the completion mode is changed by the user
373 * through the context menu.
374 */
375 void completionModeChanged(KCompletion::CompletionMode);
376
377 /**
378 * Emitted before the context menu is displayed.
379 *
380 * The signal allows you to add your own entries into the context menu.
381 * Note that you <em>must not</em> store the pointer to the QPopupMenu since it is
382 * created and deleted on demand. Otherwise, you can crash your app.
383 *
384 * @param contextMenu the context menu about to be displayed
385 */
386 void aboutToShowContextMenu(QMenu *contextMenu);
387
388public Q_SLOTS:
389
390 /**
391 * Iterates through all possible matches of the completed text
392 * or the history list.
393 *
394 * Depending on the value of the argument, this function either
395 * iterates through the history list of this widget or all the
396 * possible matches in whenever multiple matches result from a
397 * text completion request. Note that the all-possible-match
398 * iteration will not work if there are no previous matches, i.e.
399 * no text has been completed and the *nix shell history list
400 * rotation is only available if the insertion policy for this
401 * widget is set either @c QComobBox::AtTop or @c QComboBox::AtBottom.
402 * For other insertion modes whatever has been typed by the user
403 * when the rotation event was initiated will be lost.
404 *
405 * @param type The key binding invoked.
406 */
407 void rotateText(KCompletionBase::KeyBindingType type);
408
409 /**
410 * Sets the completed text in the line edit appropriately.
411 *
412 * This function is an implementation for
413 * KCompletionBase::setCompletedText.
414 */
415 void setCompletedText(const QString &) override;
416
417 /**
418 * Sets @p items into the completion box if completionMode() is
419 * CompletionPopup. The popup will be shown immediately.
420 */
421 void setCompletedItems(const QStringList &items, bool autoSuggest = true) override;
422
423 /**
424 * Selects the first item that matches @p item.
425 *
426 * If there is no such item, it is inserted at position @p index
427 * if @p insert is true. Otherwise, no item is selected.
428 */
429 void setCurrentItem(const QString &item, bool insert = false, int index = -1);
430
431protected Q_SLOTS:
432
433 /**
434 * Completes text according to the completion mode.
435 *
436 * @note This method is not invoked if the completion mode is
437 * set to @c CompletionNone. Also if the mode is set to @c CompletionShell
438 * and multiple matches are found, this method will complete the
439 * text to the first match with a beep to indicate that there are
440 * more matches. Then any successive completion key event iterates
441 * through the remaining matches. This way the rotation functionality
442 * is left to iterate through the list as usual.
443 */
444 virtual void makeCompletion(const QString &);
445
446protected:
447 /**
448 * This function sets the line edit text and
449 * highlights the text appropriately if the boolean
450 * value is set to true.
451 *
452 * @param text The text to be set in the line edit
453 * @param marked Whether the text inserted should be highlighted
454 */
455 virtual void setCompletedText(const QString &text, bool marked);
456
457protected:
458 KCOMPLETION_NO_EXPORT KComboBox(KComboBoxPrivate &dd, QWidget *parent);
459
460protected:
461 std::unique_ptr<KComboBoxPrivate> const d_ptr;
462
463private:
464 Q_DECLARE_PRIVATE(KComboBox)
465};
466
467#endif
468

source code of kcompletion/src/kcombobox.h