| 1 | /* |
| 2 | SPDX-FileCopyrightText: 2006-2010 Peter Penz <peter.penz@gmx.at> |
| 3 | SPDX-FileCopyrightText: 2006 Aaron J. Seigo <aseigo@kde.org> |
| 4 | SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org> |
| 5 | SPDX-FileCopyrightText: 2007 Urs Wolfer <uwolfer @ kde.org> |
| 6 | |
| 7 | SPDX-License-Identifier: LGPL-2.0-or-later |
| 8 | */ |
| 9 | |
| 10 | #ifndef KURLNAVIGATOR_H |
| 11 | #define KURLNAVIGATOR_H |
| 12 | |
| 13 | #include "kiofilewidgets_export.h" |
| 14 | |
| 15 | #include <QByteArray> |
| 16 | #include <QUrl> |
| 17 | #include <QWidget> |
| 18 | |
| 19 | #include <memory> |
| 20 | |
| 21 | class QMouseEvent; |
| 22 | |
| 23 | class KFilePlacesModel; |
| 24 | class KUrlComboBox; |
| 25 | |
| 26 | class KUrlNavigatorPrivate; |
| 27 | |
| 28 | /*! |
| 29 | * \class KUrlNavigator |
| 30 | * \inmodule KIOFileWidgets |
| 31 | * |
| 32 | * \brief Widget that allows to navigate through the paths of an URL. |
| 33 | * |
| 34 | * The URL navigator offers two modes: |
| 35 | * \list |
| 36 | * \li Editable: The URL of the location is editable inside an editor. |
| 37 | * By pressing RETURN the URL will get activated. |
| 38 | * \li Non editable ("breadcrumb view"): The URL of the location is represented by |
| 39 | * a number of buttons, where each button represents a path |
| 40 | * of the URL. By clicking on a button the path will get |
| 41 | * activated. This mode also supports drag and drop of items. |
| 42 | * \endlist |
| 43 | * |
| 44 | * The mode can be changed by clicking on the empty area of the URL navigator. |
| 45 | * It is recommended that the application remembers the setting |
| 46 | * or allows to configure the default mode (see KUrlNavigator::setUrlEditable()). |
| 47 | * |
| 48 | * The URL navigator remembers the URL history during navigation and allows to go |
| 49 | * back and forward within this history. |
| 50 | * |
| 51 | * In the non editable mode ("breadcrumb view") it can be configured whether |
| 52 | * the full path should be shown. It is recommended that the application |
| 53 | * remembers the setting or allows to configure the default mode (see |
| 54 | * KUrlNavigator::setShowFullPath()). |
| 55 | * |
| 56 | * The typical usage of the KUrlNavigator is: |
| 57 | * \list |
| 58 | * \li Create an instance providing a places model and an URL. |
| 59 | * \li Create an instance of QAbstractItemView which shows the content of the URL |
| 60 | * given by the URL navigator. |
| 61 | * \li Connect to the signal KUrlNavigator::urlChanged() and synchronize the content of |
| 62 | * QAbstractItemView with the URL given by the URL navigator. |
| 63 | * \endlist |
| 64 | * |
| 65 | * It is recommended, that the application remembers the state of the QAbstractItemView |
| 66 | * when the URL has been changed. This allows to restore the view state when going back in history. |
| 67 | * KUrlNavigator offers support for remembering the view state: |
| 68 | * \list |
| 69 | * \li The signal urlAboutToBeChanged() will be emitted before the URL change takes places. |
| 70 | * This allows the application to store the view state by KUrlNavigator::saveLocationState(). |
| 71 | * \li The signal urlChanged() will be emitted after the URL change took place. This allows |
| 72 | * the application to restore the view state by getting the values from |
| 73 | * KUrlNavigator::locationState(). |
| 74 | * \endlist |
| 75 | */ |
| 76 | class KIOFILEWIDGETS_EXPORT KUrlNavigator : public QWidget |
| 77 | { |
| 78 | Q_OBJECT |
| 79 | |
| 80 | public: |
| 81 | /*! \since 4.5 */ |
| 82 | KUrlNavigator(QWidget *parent = nullptr); |
| 83 | |
| 84 | /*! |
| 85 | * \a placesModel Model for the places which are selectable inside a |
| 86 | * menu. A place can be a bookmark or a device. If it is 0, |
| 87 | * no places selector is displayed. |
| 88 | * |
| 89 | * \a url URL which is used for the navigation or editing. |
| 90 | * |
| 91 | * \a parent Parent widget. |
| 92 | */ |
| 93 | KUrlNavigator(KFilePlacesModel *placesModel, const QUrl &url, QWidget *parent); |
| 94 | ~KUrlNavigator() override; |
| 95 | |
| 96 | /*! |
| 97 | * Returns URL of the location given by the \a historyIndex. If \a historyIndex |
| 98 | * is smaller than 0, the URL of the current location is returned. |
| 99 | * \since 4.5 |
| 100 | */ |
| 101 | QUrl locationUrl(int historyIndex = -1) const; |
| 102 | |
| 103 | /*! |
| 104 | * Saves the location state described by \a state for the current location. It is recommended |
| 105 | * that at least the scroll position of a view is remembered and restored when traversing |
| 106 | * through the history. Saving the location state should be done when the signal |
| 107 | * KUrlNavigator::urlAboutToBeChanged() has been emitted. Restoring the location state (see |
| 108 | * KUrlNavigator::locationState()) should be done when the signal KUrlNavigator::urlChanged() |
| 109 | * has been emitted. |
| 110 | * |
| 111 | * Example: |
| 112 | * \code |
| 113 | * QByteArray state; |
| 114 | * QDataStream data(&state, QIODevice::WriteOnly); |
| 115 | * data << QPoint(x, y); |
| 116 | * data << ...; |
| 117 | * ... |
| 118 | * urlNavigator->saveLocationState(state); |
| 119 | * \endcode |
| 120 | * |
| 121 | */ |
| 122 | void saveLocationState(const QByteArray &state); |
| 123 | |
| 124 | /*! |
| 125 | * Returns Location state given by \a historyIndex. If \a historyIndex |
| 126 | * is smaller than 0, the state of the current location is returned. |
| 127 | * \sa KUrlNavigator::saveLocationState() |
| 128 | * \since 4.5 |
| 129 | */ |
| 130 | QByteArray locationState(int historyIndex = -1) const; |
| 131 | |
| 132 | /*! |
| 133 | * Goes back one step in the URL history. The signals |
| 134 | * KUrlNavigator::urlAboutToBeChanged(), KUrlNavigator::urlChanged() and |
| 135 | * KUrlNavigator::historyChanged() are emitted if true is returned. False is returned |
| 136 | * if the beginning of the history has already been reached and hence going back was |
| 137 | * not possible. The history index (see KUrlNavigator::historyIndex()) is |
| 138 | * increased by one if the operation was successful. |
| 139 | */ |
| 140 | bool goBack(); |
| 141 | |
| 142 | /*! |
| 143 | * Goes forward one step in the URL history. The signals |
| 144 | * KUrlNavigator::urlAboutToBeChanged(), KUrlNavigator::urlChanged() and |
| 145 | * KUrlNavigator::historyChanged() are emitted if true is returned. False is returned |
| 146 | * if the end of the history has already been reached and hence going forward |
| 147 | * was not possible. The history index (see KUrlNavigator::historyIndex()) is |
| 148 | * decreased by one if the operation was successful. |
| 149 | */ |
| 150 | bool goForward(); |
| 151 | |
| 152 | /*! |
| 153 | * Goes up one step of the URL path and remembers the old path |
| 154 | * in the history. The signals KUrlNavigator::urlAboutToBeChanged(), |
| 155 | * KUrlNavigator::urlChanged() and KUrlNavigator::historyChanged() are |
| 156 | * emitted if true is returned. False is returned if going up was not |
| 157 | * possible as the root has been reached. |
| 158 | */ |
| 159 | bool goUp(); |
| 160 | |
| 161 | // KDE5: Remove the home-property. It is sufficient to invoke |
| 162 | // KUrlNavigator::setLocationUrl(homeUrl) on application-side. |
| 163 | /*! |
| 164 | * Goes to the home URL and remembers the old URL in the history. |
| 165 | * The signals KUrlNavigator::urlAboutToBeChanged(), KUrlNavigator::urlChanged() |
| 166 | * and KUrlNavigator::historyChanged() are emitted. |
| 167 | * |
| 168 | * \sa setHomeUrl() |
| 169 | */ |
| 170 | void goHome(); |
| 171 | |
| 172 | // KDE5: Remove the home-property. It is sufficient to invoke |
| 173 | // KUrlNavigator::setLocationUrl(homeUrl) on application-side. |
| 174 | /*! |
| 175 | * Sets the home URL used by KUrlNavigator::goHome(). If no |
| 176 | * home URL is set, the default home path of the user is used. |
| 177 | */ |
| 178 | void setHomeUrl(const QUrl &url); |
| 179 | |
| 180 | /*! |
| 181 | * |
| 182 | */ |
| 183 | QUrl homeUrl() const; |
| 184 | |
| 185 | /*! |
| 186 | * Allows to edit the URL of the navigation bar if \a editable |
| 187 | * is true, and sets the focus accordingly. |
| 188 | * If \a editable is false, each part of |
| 189 | * the URL is presented by a button for a fast navigation ("breadcrumb view"). |
| 190 | */ |
| 191 | void setUrlEditable(bool editable); |
| 192 | |
| 193 | /*! |
| 194 | * Returns \c true, if the URL is editable within a line editor. |
| 195 | * If false is returned, each part of the URL is presented by a button |
| 196 | * for fast navigation ("breadcrumb view"). |
| 197 | */ |
| 198 | bool isUrlEditable() const; |
| 199 | |
| 200 | /*! |
| 201 | * Shows the full path of the URL even if a place represents a part of the URL. |
| 202 | * Assuming that a place called "Pictures" uses the URL /home/user/Pictures. |
| 203 | * An URL like /home/user/Pictures/2008 is shown as [Pictures] > [2008] |
| 204 | * in the breadcrumb view, if showing the full path is turned off. If |
| 205 | * showing the full path is turned on, the URL is shown |
| 206 | * as [/] > [home] > [Pictures] > [2008]. |
| 207 | */ |
| 208 | void setShowFullPath(bool show); |
| 209 | |
| 210 | /*! |
| 211 | * Returns \c true, if the full path of the URL should be shown in the breadcrumb view. |
| 212 | * \since 4.2 |
| 213 | */ |
| 214 | bool showFullPath() const; |
| 215 | |
| 216 | /*! |
| 217 | * Set the URL navigator to the active mode, if \a active |
| 218 | * is true. The active mode is default. The inactive mode only differs |
| 219 | * visually from the active mode, no change of the behavior is given. |
| 220 | * |
| 221 | * Using the URL navigator in the inactive mode is useful when having split views, |
| 222 | * where the inactive view is indicated by an inactive URL |
| 223 | * navigator visually. |
| 224 | */ |
| 225 | void setActive(bool active); |
| 226 | |
| 227 | /*! |
| 228 | * Returns \c true, if the URL navigator is in the active mode. |
| 229 | * \sa setActive() |
| 230 | */ |
| 231 | bool isActive() const; |
| 232 | |
| 233 | /*! |
| 234 | * Sets the places selector visible, if \a visible is true. |
| 235 | * The places selector allows to select the places provided |
| 236 | * by the places model passed in the constructor. Per default |
| 237 | * the places selector is visible. |
| 238 | */ |
| 239 | void setPlacesSelectorVisible(bool visible); |
| 240 | |
| 241 | /*! Returns \c true, if the places selector is visible. */ |
| 242 | bool isPlacesSelectorVisible() const; |
| 243 | |
| 244 | /*! |
| 245 | * Returns the currently entered, but not accepted URL. |
| 246 | * It is possible that the returned URL is not valid. |
| 247 | */ |
| 248 | QUrl uncommittedUrl() const; |
| 249 | |
| 250 | /*! |
| 251 | * Returns the amount of locations in the history. The data for each |
| 252 | * location can be retrieved by KUrlNavigator::locationUrl() and |
| 253 | * KUrlNavigator::locationState(). |
| 254 | */ |
| 255 | int historySize() const; |
| 256 | |
| 257 | /*! |
| 258 | * Returns the history index of the current location, where |
| 259 | * 0 <= history index < KUrlNavigator::historySize(). 0 is the most |
| 260 | * recent history entry. |
| 261 | */ |
| 262 | int historyIndex() const; |
| 263 | |
| 264 | /*! |
| 265 | * Returns the used editor when the navigator is in the edit mode |
| 266 | * \sa KUrlNavigator::setUrlEditable() |
| 267 | */ |
| 268 | KUrlComboBox *editor() const; |
| 269 | |
| 270 | /*! |
| 271 | * Set the URL schemes that the navigator should allow navigating to. |
| 272 | * |
| 273 | * If the passed list is empty, all schemes are supported. Examples for |
| 274 | * schemes are \c "file" or \c "ftp". |
| 275 | * |
| 276 | * \sa QFileDialog::setSupportedSchemes |
| 277 | * \since 5.103 |
| 278 | */ |
| 279 | void setSupportedSchemes(const QStringList &schemes); |
| 280 | |
| 281 | /*! |
| 282 | * Returns the URL schemes that the navigator should allow navigating to. |
| 283 | * |
| 284 | * If the returned list is empty, all schemes are supported. |
| 285 | * |
| 286 | * \sa QFileDialog::supportedSchemes |
| 287 | * \since 5.103 |
| 288 | */ |
| 289 | QStringList supportedSchemes() const; |
| 290 | |
| 291 | /*! |
| 292 | * The child widget that received the QDropEvent when dropping on the URL |
| 293 | * navigator. You can pass this widget to KJobWidgets::setWindow() |
| 294 | * if you need to show a drop menu with KIO::drop(). |
| 295 | * |
| 296 | * Returns Child widget that has received the last drop event, or nullptr if |
| 297 | * nothing has been dropped yet on the URL navigator. |
| 298 | * \since 5.37 |
| 299 | * \sa KIO::drop() |
| 300 | */ |
| 301 | QWidget *dropWidget() const; |
| 302 | |
| 303 | /*! |
| 304 | * Sets whether to show hidden folders in the subdirectories popup. |
| 305 | * \since 5.87 |
| 306 | */ |
| 307 | void setShowHiddenFolders(bool showHiddenFolders); |
| 308 | |
| 309 | /*! |
| 310 | * Returns whether to show hidden folders in the subdirectories popup. |
| 311 | * \since 5.87 |
| 312 | */ |
| 313 | bool showHiddenFolders() const; |
| 314 | |
| 315 | /*! |
| 316 | * Sets whether to sort hidden folders in the subdirectories popup last. |
| 317 | * \since 5.87 |
| 318 | */ |
| 319 | void setSortHiddenFoldersLast(bool sortHiddenFoldersLast); |
| 320 | |
| 321 | /*! |
| 322 | * Returns whether to sort hidden folders in the subdirectories popup last. |
| 323 | * \since 5.87 |
| 324 | */ |
| 325 | bool sortHiddenFoldersLast() const; |
| 326 | |
| 327 | /*! |
| 328 | * Puts \a widget to the right of the breadcrumb. |
| 329 | * |
| 330 | * KUrlNavigator takes ownership over \a widget. Any existing badge widget is deleted. |
| 331 | * |
| 332 | * \note There is no limit to the size of the badge widget. If your badge widget is taller than other |
| 333 | * controls in KUrlNavigator, then the whole KUrlNavigator will be resized to accommodate it. Also, |
| 334 | * KUrlNavigator has fixed minimumWidth of 100, so if your badge widget is too wide, it might be clipped |
| 335 | * when the space is tight. You might want to call KUrlNavigator::setMinimumWidth() with a larger value |
| 336 | * in that case. |
| 337 | * In general, it is recommended to keep the badge widget small and not expanding, to avoid layout issues. |
| 338 | * \since 6.2 |
| 339 | */ |
| 340 | void setBadgeWidget(QWidget *widget); |
| 341 | |
| 342 | /*! |
| 343 | * Returns the badge widget set by setBadgeWidget(). If setBadgeWidget() hasn't been called, returns nullptr. |
| 344 | * \since 6.2 |
| 345 | */ |
| 346 | QWidget *badgeWidget() const; |
| 347 | |
| 348 | /*! |
| 349 | * Sets the background painting enabled or disabled for the buttons layout. |
| 350 | * |
| 351 | * In frameless styles, its recommended to set the background to disabled. |
| 352 | * |
| 353 | * Does not affect the input mode. |
| 354 | * \since 6.14 |
| 355 | */ |
| 356 | void setBackgroundEnabled(bool enabled); |
| 357 | |
| 358 | /*! |
| 359 | * Returns true if the background of the buttons layout is being painted. |
| 360 | * |
| 361 | * Does not represent the input mode background. |
| 362 | * |
| 363 | * \since 6.14 |
| 364 | */ |
| 365 | bool isBackgroundEnabled() const; |
| 366 | |
| 367 | public Q_SLOTS: |
| 368 | /*! |
| 369 | * Sets the location to \a url. The old URL is added to the history. |
| 370 | * The signals KUrlNavigator::urlAboutToBeChanged(), KUrlNavigator::urlChanged() |
| 371 | * and KUrlNavigator::historyChanged() are emitted. Use |
| 372 | * KUrlNavigator::locationUrl() to read the location. |
| 373 | */ |
| 374 | void setLocationUrl(const QUrl &url); |
| 375 | |
| 376 | /*! |
| 377 | * Activates the URL navigator (KUrlNavigator::isActive() will return true) |
| 378 | * and emits the signal KUrlNavigator::activated(). |
| 379 | * \sa setActive() |
| 380 | */ |
| 381 | void requestActivation(); |
| 382 | |
| 383 | // KDE5: Remove and listen for focus-signal instead |
| 384 | void setFocus(); |
| 385 | |
| 386 | Q_SIGNALS: |
| 387 | /*! |
| 388 | * Is emitted, if the URL navigator has been activated by |
| 389 | * an user interaction |
| 390 | * \sa setActive() |
| 391 | */ |
| 392 | void activated(); |
| 393 | |
| 394 | /*! |
| 395 | * Is emitted, if the location URL has been changed e. g. by |
| 396 | * the user. |
| 397 | * \sa setUrl() |
| 398 | */ |
| 399 | void urlChanged(const QUrl &url); |
| 400 | |
| 401 | /*! |
| 402 | * Is emitted, before the location URL is going to be changed to \a newUrl. |
| 403 | * The signal KUrlNavigator::urlChanged() will be emitted after the change |
| 404 | * has been done. Connecting to this signal is useful to save the state |
| 405 | * of a view with KUrlNavigator::saveLocationState(). |
| 406 | */ |
| 407 | void urlAboutToBeChanged(const QUrl &newUrl); |
| 408 | |
| 409 | /*! |
| 410 | * Is emitted, if the editable state for the URL has been changed |
| 411 | * (see KUrlNavigator::setUrlEditable()). |
| 412 | */ |
| 413 | void editableStateChanged(bool editable); |
| 414 | |
| 415 | /*! |
| 416 | * Is emitted, if the history has been changed. Usually |
| 417 | * the history is changed if a new URL has been selected. |
| 418 | */ |
| 419 | void historyChanged(); |
| 420 | |
| 421 | /*! |
| 422 | * Is emitted if a dropping has been done above the destination |
| 423 | * \a destination. The receiver must accept the drop event if |
| 424 | * the dropped data can be handled. |
| 425 | */ |
| 426 | void urlsDropped(const QUrl &destination, QDropEvent *event); |
| 427 | |
| 428 | /*! |
| 429 | * This signal is emitted when the Return or Enter key is pressed. |
| 430 | */ |
| 431 | void returnPressed(); |
| 432 | |
| 433 | /*! |
| 434 | * Is emitted if the URL \a url should be opened in a new inactive tab because |
| 435 | * the user clicked on a breadcrumb with the middle mouse button or |
| 436 | * left-clicked with the ctrl modifier pressed or pressed return with |
| 437 | * the alt modifier pressed. |
| 438 | */ |
| 439 | void tabRequested(const QUrl &url); |
| 440 | |
| 441 | /*! |
| 442 | * Is emitted if the URL \a url should be opened in a new active tab because |
| 443 | * the user clicked on a breadcrumb with the middle mouse button with |
| 444 | * the shift modifier pressed or left-clicked with both the ctrl and shift |
| 445 | * modifiers pressed or pressed return with both the alt and shift modifiers |
| 446 | * pressed. |
| 447 | * \since 5.89 |
| 448 | */ |
| 449 | void activeTabRequested(const QUrl &url); |
| 450 | |
| 451 | /*! |
| 452 | * Is emitted if the URL \a url should be opened in a new window because |
| 453 | * the user left-clicked on a breadcrumb with the shift modifier pressed |
| 454 | * or pressed return with the shift modifier pressed. |
| 455 | * \since 5.89 |
| 456 | */ |
| 457 | void newWindowRequested(const QUrl &url); |
| 458 | |
| 459 | /*! |
| 460 | * When the URL is changed and the new URL (e.g.\ /home/user1/) |
| 461 | * is a parent of the previous URL (e.g.\ /home/user1/data/stuff), |
| 462 | * then this signal is emitted and \a url is set to the child |
| 463 | * directory of the new URL which is an ancestor of the old URL |
| 464 | * (in the example paths this would be /home/user1/data/). |
| 465 | * This signal allows file managers to pre-select the directory |
| 466 | * that the user is navigating up from. |
| 467 | * \since 5.37.0 |
| 468 | */ |
| 469 | void urlSelectionRequested(const QUrl &url); |
| 470 | |
| 471 | /*! |
| 472 | * The internal layout and graphical representation of components has changed, |
| 473 | * either after an url change or after a switch between editable mode and |
| 474 | * breadcrumb mode |
| 475 | * \since 6.11 |
| 476 | */ |
| 477 | void layoutChanged(); |
| 478 | |
| 479 | protected: |
| 480 | /* |
| 481 | * If the Escape key is pressed, the navigation bar should switch |
| 482 | * to the breadcrumb view. |
| 483 | */ |
| 484 | void keyPressEvent(QKeyEvent *event) override; |
| 485 | |
| 486 | void keyReleaseEvent(QKeyEvent *event) override; |
| 487 | |
| 488 | /* |
| 489 | * Paste the clipboard content as URL, if the middle mouse |
| 490 | * button has been clicked. |
| 491 | */ |
| 492 | void mouseReleaseEvent(QMouseEvent *event) override; |
| 493 | |
| 494 | /* |
| 495 | * Reimplemented to activate on middle mousse button click |
| 496 | */ |
| 497 | void mousePressEvent(QMouseEvent *event) override; |
| 498 | |
| 499 | void resizeEvent(QResizeEvent *event) override; |
| 500 | |
| 501 | void wheelEvent(QWheelEvent *event) override; |
| 502 | |
| 503 | void showEvent(QShowEvent *event) override; |
| 504 | |
| 505 | bool eventFilter(QObject *watched, QEvent *event) override; |
| 506 | |
| 507 | void paintEvent(QPaintEvent *event) override; |
| 508 | |
| 509 | private: |
| 510 | friend class KUrlNavigatorPrivate; |
| 511 | std::unique_ptr<KUrlNavigatorPrivate> const d; |
| 512 | |
| 513 | Q_DISABLE_COPY(KUrlNavigator) |
| 514 | }; |
| 515 | |
| 516 | #endif |
| 517 | |