Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsidebar.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsidebar_p.h"
5
6#include <qaction.h>
7#include <qurl.h>
8#if QT_CONFIG(menu)
9#include <qmenu.h>
10#endif
11#include <qmimedata.h>
12#include <qevent.h>
13#include <qdebug.h>
14#include <qfilesystemmodel.h>
16#include <qfiledialog.h>
17
19
20using namespace Qt::StringLiterals;
21
22void QSideBarDelegate::initStyleOption(QStyleOptionViewItem *option,
23 const QModelIndex &index) const
24{
27 if (value.isValid()) {
28 //If the bookmark/entry is not enabled then we paint it in gray
29 if (!qvariant_cast<bool>(value))
30 option->state &= ~QStyle::State_Enabled;
31 }
32}
33
42QUrlModel::QUrlModel(QObject *parent) : QStandardItemModel(parent), showFullPath(false), fileSystemModel(nullptr)
43{
44}
45
47{
48 for (const auto &conn : std::as_const(modelConnections))
49 disconnect(conn);
50}
51
56{
57 return QStringList("text/uri-list"_L1);
58}
59
63Qt::ItemFlags QUrlModel::flags(const QModelIndex &index) const
64{
65 Qt::ItemFlags flags = QStandardItemModel::flags(index);
66 if (index.isValid()) {
67 flags &= ~Qt::ItemIsEditable;
68 // ### some future version could support "moving" urls onto a folder
69 flags &= ~Qt::ItemIsDropEnabled;
70 }
71
72 if (index.data(Qt::DecorationRole).isNull())
73 flags &= ~Qt::ItemIsEnabled;
74
75 return flags;
76}
77
82{
83 QList<QUrl> list;
84 for (const auto &index : indexes) {
85 if (index.column() == 0)
86 list.append(index.data(UrlRole).toUrl());
87 }
88 QMimeData *data = new QMimeData();
89 data->setUrls(list);
90 return data;
91}
92
93#if QT_CONFIG(draganddrop)
94
100bool QUrlModel::canDrop(QDragEnterEvent *event)
101{
102 if (!event->mimeData()->formats().contains(mimeTypes().constFirst()))
103 return false;
104
105 const QList<QUrl> list = event->mimeData()->urls();
106 for (const auto &url : list) {
107 const QModelIndex idx = fileSystemModel->index(url.toLocalFile());
108 if (!fileSystemModel->isDir(idx))
109 return false;
110 }
111 return true;
112}
113
118 int row, int column, const QModelIndex &parent)
119{
120 if (!data->formats().contains(mimeTypes().constFirst()))
121 return false;
122 Q_UNUSED(action);
125 addUrls(data->urls(), row);
126 return true;
127}
128
129#endif // QT_CONFIG(draganddrop)
130
136bool QUrlModel::setData(const QModelIndex &index, const QVariant &value, int role)
137{
138 if (value.userType() == QMetaType::QUrl) {
139 QUrl url = value.toUrl();
140 QModelIndex dirIndex = fileSystemModel->index(url.toLocalFile());
141 //On windows the popup display the "C:\", convert to nativeSeparators
142 if (showFullPath)
144 else {
146 QStandardItemModel::setData(index, fileSystemModel->data(dirIndex).toString());
147 }
148 QStandardItemModel::setData(index, fileSystemModel->data(dirIndex, Qt::DecorationRole),
151 return true;
152 }
154}
155
156void QUrlModel::setUrl(const QModelIndex &index, const QUrl &url, const QModelIndex &dirIndex)
157{
159 if (url.path().isEmpty()) {
160 setData(index, fileSystemModel->myComputer());
162 } else {
163 QString newName;
164 if (showFullPath) {
165 //On windows the popup display the "C:\", convert to nativeSeparators
166 newName = QDir::toNativeSeparators(dirIndex.data(QFileSystemModel::FilePathRole).toString());
167 } else {
168 newName = dirIndex.data().toString();
169 }
170
171 QIcon newIcon = qvariant_cast<QIcon>(dirIndex.data(Qt::DecorationRole));
172 if (!dirIndex.isValid()) {
173 const QAbstractFileIconProvider *provider = fileSystemModel->iconProvider();
174 if (provider)
175 newIcon = provider->icon(QAbstractFileIconProvider::Folder);
176 newName = QFileInfo(url.toLocalFile()).fileName();
177 if (!invalidUrls.contains(url))
178 invalidUrls.append(url);
179 //The bookmark is invalid then we set to false the EnabledRole
180 setData(index, false, EnabledRole);
181 } else {
182 //The bookmark is valid then we set to true the EnabledRole
183 setData(index, true, EnabledRole);
184 }
185
186 // newIcon could be null if fileSystemModel->iconProvider() returns null
187 if (!newIcon.isNull()) {
188 // Make sure that we have at least 32x32 images
189 const QSize size = newIcon.actualSize(QSize(32,32));
190 if (size.width() < 32) {
191 QPixmap smallPixmap = newIcon.pixmap(QSize(32, 32));
192 newIcon.addPixmap(smallPixmap.scaledToWidth(32, Qt::SmoothTransformation));
193 }
194 }
195
196 if (index.data().toString() != newName)
197 setData(index, newName);
198 QIcon oldIcon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
199 if (oldIcon.cacheKey() != newIcon.cacheKey())
201 }
202}
203
204void QUrlModel::setUrls(const QList<QUrl> &list)
205{
206 removeRows(0, rowCount());
207 invalidUrls.clear();
208 watching.clear();
209 addUrls(list, 0);
210}
211
218void QUrlModel::addUrls(const QList<QUrl> &list, int row, bool move)
219{
220 if (row == -1)
221 row = rowCount();
222 row = qMin(row, rowCount());
223 const auto rend = list.crend();
224 for (auto it = list.crbegin(); it != rend; ++it) {
225 QUrl url = *it;
226 if (!url.isValid() || url.scheme() != "file"_L1)
227 continue;
228 //this makes sure the url is clean
229 const QString cleanUrl = QDir::cleanPath(url.toLocalFile());
230 if (!cleanUrl.isEmpty())
231 url = QUrl::fromLocalFile(cleanUrl);
232
233 for (int j = 0; move && j < rowCount(); ++j) {
234 QString local = index(j, 0).data(UrlRole).toUrl().toLocalFile();
235#if defined(Q_OS_WIN)
237#else
239#endif
240 if (!cleanUrl.compare(local, cs)) {
241 removeRow(j);
242 if (j <= row)
243 row--;
244 break;
245 }
246 }
247 row = qMax(row, 0);
248 QModelIndex idx = fileSystemModel->index(cleanUrl);
249 if (!fileSystemModel->isDir(idx))
250 continue;
251 insertRows(row, 1);
252 setUrl(index(row, 0), url, idx);
253 watching.append({idx, cleanUrl});
254 }
255}
256
260QList<QUrl> QUrlModel::urls() const
261{
262 QList<QUrl> list;
263 const int numRows = rowCount();
264 list.reserve(numRows);
265 for (int i = 0; i < numRows; ++i)
266 list.append(data(index(i, 0), UrlRole).toUrl());
267 return list;
268}
269
274{
275 if (model == fileSystemModel)
276 return;
277 if (fileSystemModel != nullptr) {
278 for (const auto &conn : std::as_const(modelConnections))
279 disconnect(conn);
280 }
281 fileSystemModel = model;
282 if (fileSystemModel != nullptr) {
283 modelConnections = {
285 this, &QUrlModel::dataChanged),
287 this, &QUrlModel::layoutChanged),
289 this, &QUrlModel::layoutChanged),
290 };
291 }
292 clear();
293 insertColumns(0, 1);
294}
295
296/*
297 If one of the index's we are watching has changed update our internal data
298*/
299void QUrlModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
300{
301 QModelIndex parent = topLeft.parent();
302 for (int i = 0; i < watching.size(); ++i) {
303 QModelIndex index = watching.at(i).index;
304 if (index.model() && topLeft.model()) {
305 Q_ASSERT(index.model() == topLeft.model());
306 }
307 if ( index.row() >= topLeft.row()
308 && index.row() <= bottomRight.row()
309 && index.column() >= topLeft.column()
310 && index.column() <= bottomRight.column()
311 && index.parent() == parent) {
312 changed(watching.at(i).path);
313 }
314 }
315}
316
320void QUrlModel::layoutChanged()
321{
323 paths.reserve(watching.size());
324 for (const WatchItem &item : std::as_const(watching))
326 watching.clear();
327 for (const auto &path : paths) {
328 QModelIndex newIndex = fileSystemModel->index(path);
329 watching.append({newIndex, path});
330 if (newIndex.isValid())
331 changed(path);
332 }
333}
334
340void QUrlModel::changed(const QString &path)
341{
342 for (int i = 0; i < rowCount(); ++i) {
343 QModelIndex idx = index(i, 0);
344 if (idx.data(UrlRole).toUrl().toLocalFile() == path) {
345 setData(idx, idx.data(UrlRole).toUrl());
346 }
347 }
348}
349
351{
352}
353
354void QSidebar::setModelAndUrls(QFileSystemModel *model, const QList<QUrl> &newUrls)
355{
357 urlModel = new QUrlModel(this);
358 urlModel->setFileSystemModel(model);
359 setModel(urlModel);
361
363 this, &QSidebar::clicked);
364#if QT_CONFIG(draganddrop)
365 setDragDropMode(QAbstractItemView::DragDrop);
366#endif
367#if QT_CONFIG(menu)
368 setContextMenuPolicy(Qt::CustomContextMenu);
369 connect(this, &QSidebar::customContextMenuRequested,
370 this, &QSidebar::showContextMenu);
371#endif
372 urlModel->setUrls(newUrls);
373 setCurrentIndex(this->model()->index(0,0));
374}
375
379
380#if QT_CONFIG(draganddrop)
381void QSidebar::dragEnterEvent(QDragEnterEvent *event)
382{
383 if (urlModel->canDrop(event))
384 QListView::dragEnterEvent(event);
385}
386#endif // QT_CONFIG(draganddrop)
387
389{
390 if (model())
391 return QListView::sizeHintForIndex(model()->index(0, 0)) + QSize(2 * frameWidth(), 2 * frameWidth());
392 return QListView::sizeHint();
393}
394
396{
398 this, &QSidebar::clicked);
399
401 for (int i = 0; i < model()->rowCount(); ++i) {
402 if (model()->index(i, 0).data(QUrlModel::UrlRole).toUrl() == url) {
404 break;
405 }
406 }
407
409 this, &QSidebar::clicked);
410}
411
412#if QT_CONFIG(menu)
418void QSidebar::showContextMenu(const QPoint &position)
419{
420 QList<QAction *> actions;
421 if (indexAt(position).isValid()) {
422 QAction *action = new QAction(QFileDialog::tr("Remove"), this);
423 if (indexAt(position).data(QUrlModel::UrlRole).toUrl().path().isEmpty())
424 action->setEnabled(false);
425 connect(action, &QAction::triggered, this, &QSidebar::removeEntry);
426 actions.append(action);
427 }
428 if (actions.size() > 0)
429 QMenu::exec(actions, mapToGlobal(position));
430}
431#endif // QT_CONFIG(menu)
432
438void QSidebar::removeEntry()
439{
440 const QList<QModelIndex> idxs = selectionModel()->selectedIndexes();
441 // Create a list of QPersistentModelIndex as the removeRow() calls below could
442 // invalidate the indexes in "idxs"
443 const QList<QPersistentModelIndex> persIndexes(idxs.cbegin(), idxs.cend());
444 for (const QPersistentModelIndex &persistent : persIndexes) {
445 if (!persistent.data(QUrlModel::UrlRole).toUrl().path().isEmpty())
446 model()->removeRow(persistent.row());
447 }
448}
449
455void QSidebar::clicked(const QModelIndex &index)
456{
457 QUrl url = model()->index(index.row(), 0).data(QUrlModel::UrlRole).toUrl();
459 selectUrl(url);
460}
461
467{
468 QAbstractScrollArea::focusInEvent(event);
469 viewport()->update();
470}
471
476{
477 if (event->type() == QEvent::KeyRelease) {
478 QKeyEvent *ke = static_cast<QKeyEvent *>(event);
479 if (ke->key() == Qt::Key_Delete) {
480 removeEntry();
481 return true;
482 }
483 }
484 return QListView::event(event);
485}
486
488
489#include "moc_qsidebar_p.cpp"
virtual QIcon icon(IconType) const
Returns an icon set for the given type, using the current icon theme.
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
Handles the data supplied by a drag and drop operation that ended with the given action.
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles=QList< int >())
This signal is emitted whenever the data in an existing item changes.
virtual Q_INVOKABLE int rowCount(const QModelIndex &parent=QModelIndex()) const =0
Returns the number of rows under the given parent.
void layoutChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
virtual Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const =0
Returns the index of the item in the model specified by the given row, column and parent index.
void rowsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after rows have been removed from the model.
QAbstractItemModel * model() const
Returns the model that this view is presenting.
void setCurrentIndex(const QModelIndex &index)
Sets the current item to be the item at index.
void setItemDelegate(QAbstractItemDelegate *delegate)
Sets the item delegate for this view and its model to delegate.
virtual void setModel(QAbstractItemModel *model)
Sets the model for the view to present.
QSize sizeHintForIndex(const QModelIndex &index) const
Returns the size hint for the item with the specified index or an invalid size for invalid indexes.
QItemSelectionModel * selectionModel() const
Returns the current selection model.
The QAction class provides an abstraction for user commands that can be added to different user inter...
Definition qaction.h:30
void triggered(bool checked=false)
This signal is emitted when an action is activated by the user; for example, when the user clicks a m...
void setEnabled(bool)
Definition qaction.cpp:927
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
Definition qdir.cpp:2398
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
\inmodule QtCore
Definition qcoreevent.h:45
@ KeyRelease
Definition qcoreevent.h:65
QString fileName() const
The QFileSystemModel class provides a data model for the local filesystem.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
\reimp
QVariant myComputer(int role=Qt::DisplayRole) const
Returns the data stored under the given role for the item "My Computer".
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
\reimp
QAbstractFileIconProvider * iconProvider() const
Returns the file icon provider for this directory model.
bool isDir(const QModelIndex &index) const
Returns true if the model item index represents a directory; otherwise returns false.
The QFocusEvent class contains event parameters for widget focus events.
Definition qevent.h:470
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
void currentChanged(const QModelIndex &current, const QModelIndex &previous)
This signal is emitted whenever the current item changes.
QModelIndexList selectedIndexes
virtual void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
Selects the model item index using the specified command, and emits selectionChanged().
virtual void clear()
Clears the selection model.
The QKeyEvent class describes a key event.
Definition qevent.h:424
The QListView class provides a list or icon view onto a model.
Definition qlistview.h:17
bool event(QEvent *e) override
\reimp
void setUniformItemSizes(bool enable)
QModelIndex indexAt(const QPoint &p) const override
\reimp
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
const_reverse_iterator crbegin() const noexcept
Definition qlist.h:638
void reserve(qsizetype size)
Definition qlist.h:753
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
const_reverse_iterator crend() const noexcept
Definition qlist.h:639
QAction * exec()
Executes this menu synchronously.
Definition qmenu.cpp:2613
\inmodule QtCore
Definition qmimedata.h:16
\inmodule QtCore
QVariant data(int role=Qt::DisplayRole) const
Returns the data for the given role for the item referred to by the index.
constexpr int row() const noexcept
Returns the row this model index refers to.
QModelIndex parent() const
Returns the parent of the model index, or QModelIndex() if it has no parent.
constexpr const QAbstractItemModel * model() const noexcept
Returns a pointer to the model containing the item that this index refers to.
constexpr int column() const noexcept
Returns the column this model index refers to.
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
\inmodule QtCore\reentrant
Definition qpoint.h:25
void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override
Initialize option with the values using the index index.
Definition qsidebar.cpp:22
void focusInEvent(QFocusEvent *event) override
\reimp Don't automatically select something
Definition qsidebar.cpp:466
QSize sizeHint() const override
Definition qsidebar.cpp:388
void goToUrl(const QUrl &url)
void setModelAndUrls(QFileSystemModel *model, const QList< QUrl > &newUrls)
Definition qsidebar.cpp:354
void selectUrl(const QUrl &url)
Definition qsidebar.cpp:395
bool event(QEvent *e) override
\reimp
Definition qsidebar.cpp:475
QSidebar(QWidget *parent=nullptr)
Definition qsidebar.cpp:350
\inmodule QtCore
Definition qsize.h:25
The QStandardItemModel class provides a generic model for storing custom data.
void clear()
Removes all items (including header items) from the model and sets the number of rows and columns to ...
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
\reimp
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
\reimp
bool insertColumns(int column, int count, const QModelIndex &parent=QModelIndex()) override
\reimp
Qt::ItemFlags flags(const QModelIndex &index) const override
\reimp
int rowCount(const QModelIndex &parent=QModelIndex()) const override
\reimp
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
\reimp
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
Initialize option with the values using the index index.
void setUrls(const QList< QUrl > &list)
Definition qsidebar.cpp:204
void addUrls(const QList< QUrl > &urls, int row=-1, bool move=true)
Add urls list into the list at row.
Definition qsidebar.cpp:218
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
\reimp
Definition qsidebar.cpp:136
QMimeData * mimeData(const QModelIndexList &indexes) const override
\reimp
Definition qsidebar.cpp:81
bool showFullPath
Definition qsidebar_p.h:65
QStringList mimeTypes() const override
\reimp
Definition qsidebar.cpp:55
QList< QUrl > urls() const
Return the complete list of urls in a QList.
Definition qsidebar.cpp:260
void setFileSystemModel(QFileSystemModel *model)
QFileSystemModel to get index's from, clears existing rows.
Definition qsidebar.cpp:273
Qt::ItemFlags flags(const QModelIndex &index) const override
\reimp
Definition qsidebar.cpp:63
QUrlModel(QObject *parent=nullptr)
Definition qsidebar.cpp:42
\inmodule QtCore
Definition qurl.h:94
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3368
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1882
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1991
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
Definition qurl.cpp:3425
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2468
\inmodule QtCore
Definition qvariant.h:65
void * data()
Returns a pointer to the contained object as a generic void* that can be written to.
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
QUrl toUrl() const
Returns the variant as a QUrl if the variant has userType() \l QMetaType::QUrl; otherwise returns an ...
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
list append(new Employee("Blackpool", "Stephen"))
QSet< QString >::iterator it
Combined button and popup list for selecting options.
Definition qcompare.h:63
@ SmoothTransformation
@ DecorationRole
@ ToolTipRole
@ Key_Delete
Definition qnamespace.h:670
CaseSensitivity
@ CaseInsensitive
@ CaseSensitive
DropAction
@ CustomContextMenu
QList< QString > QStringList
Constructs a string list that contains the given string, str.
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei const GLuint * paths
GLbitfield flags
GLenum GLenum GLsizei void GLsizei void * column
struct _cl_event * event
GLsizei const GLchar *const * path
GLenum GLenum GLsizei void * row
GLuint GLenum option
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
#define Q_UNUSED(x)
QSqlQueryModel * model
[16]
QList< int > list
[14]
QUrl url("example.com")
[constructor-url-reference]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QObject::connect nullptr
myObject disconnect()
[26]
QGraphicsItem * item
view viewport() -> scroll(dx, dy, deviceRect)
flay removeRow(2)
bool contains(const AT &t) const noexcept
Definition qlist.h:45