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