File indexing completed on 2023-12-03 05:56:30
0001 /* 0002 kfindtreeview.cpp 0003 SPDX-FileCopyrightText: 2009 Dario Andres Rodriguez <andresbajotierra@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 0007 */ 0008 0009 #include "kfindtreeview.h" 0010 #include "kfinddlg.h" 0011 0012 #include <QApplication> 0013 #include <QClipboard> 0014 #include <QFileDialog> 0015 #include <QFileInfo> 0016 #include <QHeaderView> 0017 #include <QMenu> 0018 #include <QMimeData> 0019 #include <QScrollBar> 0020 #include <QTextCodec> 0021 #include <QTextStream> 0022 0023 #include <KActionCollection> 0024 #include <KFileItemActions> 0025 #include <KFileItemListProperties> 0026 #include <KJobWidgets> 0027 #include <KLocalizedString> 0028 #include <KMessageBox> 0029 #include <KPropertiesDialog> 0030 0031 #include <KIO/CopyJob> 0032 #include <KIO/DeleteJob> 0033 #include <kio_version.h> 0034 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) 0035 #include <KIO/JobUiDelegateFactory> 0036 #endif 0037 #include <KIO/JobUiDelegate> 0038 #include <KIO/OpenFileManagerWindowJob> 0039 #include <KIO/OpenUrlJob> 0040 #if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0041 #include <KIO/DeleteOrTrashJob> 0042 #endif 0043 0044 // Permission strings 0045 #include <ki18n_version.h> 0046 #include <KLazyLocalizedString> 0047 0048 const KLazyLocalizedString perm[4] = { 0049 kli18n("Read-write"), 0050 kli18n("Read-only"), 0051 kli18n("Write-only"), 0052 kli18n("Inaccessible") 0053 }; 0054 #define RW 0 0055 #define RO 1 0056 #define WO 2 0057 #define NA 3 0058 0059 //BEGIN KFindItemModel 0060 0061 KFindItemModel::KFindItemModel(KFindTreeView *parentView) 0062 : QAbstractTableModel(parentView) 0063 { 0064 m_view = parentView; 0065 } 0066 0067 QVariant KFindItemModel::headerData(int section, Qt::Orientation orientation, int role) const 0068 { 0069 if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { 0070 switch (section) { 0071 case 0: 0072 return i18nc("file name column", "Name"); 0073 case 1: 0074 return i18nc("name of the containing folder", "In Subfolder"); 0075 case 2: 0076 return i18nc("file size column", "Size"); 0077 case 3: 0078 return i18nc("modified date column", "Modified"); 0079 case 4: 0080 return i18nc("file permissions column", "Permissions"); 0081 case 5: 0082 return i18nc("first matching line of the query string in this file", "First Matching Line"); 0083 default: 0084 return QVariant(); 0085 } 0086 } 0087 return QVariant(); 0088 } 0089 0090 void KFindItemModel::insertFileItems(const QList<QPair<KFileItem, QString>> &pairs) 0091 { 0092 if (!pairs.isEmpty()) { 0093 beginInsertRows(QModelIndex(), m_itemList.size(), m_itemList.size()+pairs.size()-1); 0094 0095 for (const auto &[item, dir] : pairs) { 0096 const QString subDir = m_view->reducedDir(item.url().adjusted(QUrl::RemoveFilename).path()); 0097 m_itemList.append(KFindItem(item, subDir, dir)); 0098 } 0099 0100 endInsertRows(); 0101 } 0102 } 0103 0104 int KFindItemModel::rowCount(const QModelIndex &parent) const 0105 { 0106 if (!parent.isValid()) { 0107 return m_itemList.count(); //Return itemcount for toplevel 0108 } else { 0109 return 0; 0110 } 0111 } 0112 0113 KFindItem KFindItemModel::itemAtIndex(const QModelIndex &index) const 0114 { 0115 if (index.isValid() && m_itemList.size() >= index.row()) { 0116 return m_itemList.at(index.row()); 0117 } 0118 0119 return KFindItem(); 0120 } 0121 0122 QList<KFindItem> KFindItemModel::getItemList() const 0123 { 0124 return m_itemList; 0125 } 0126 0127 QVariant KFindItemModel::data(const QModelIndex &index, int role) const 0128 { 0129 if (!index.isValid()) { 0130 return QVariant(); 0131 } 0132 0133 if (index.column() > 6 || index.row() >= m_itemList.count()) { 0134 return QVariant(); 0135 } 0136 0137 switch (role) { 0138 case Qt::DisplayRole: 0139 case Qt::DecorationRole: 0140 case Qt::UserRole: 0141 return m_itemList.at(index.row()).data(index.column(), role); 0142 default: 0143 return QVariant(); 0144 } 0145 return QVariant(); 0146 } 0147 0148 void KFindItemModel::removeItem(const QUrl &url) 0149 { 0150 const int itemCount = m_itemList.size(); 0151 for (int i = 0; i < itemCount; i++) { 0152 KFindItem item = m_itemList.at(i); 0153 if (item.getFileItem().url() == url) { 0154 beginRemoveRows(QModelIndex(), i, i); 0155 m_itemList.removeAt(i); 0156 endRemoveRows(); 0157 return; 0158 } 0159 } 0160 } 0161 0162 bool KFindItemModel::isInserted(const QUrl &url) 0163 { 0164 const int itemCount = m_itemList.size(); 0165 for (int i = 0; i < itemCount; i++) { 0166 KFindItem item = m_itemList.at(i); 0167 if (item.getFileItem().url() == url) { 0168 return true; 0169 } 0170 } 0171 return false; 0172 } 0173 0174 void KFindItemModel::clear() 0175 { 0176 if (!m_itemList.isEmpty()) { 0177 beginRemoveRows(QModelIndex(), 0, m_itemList.size()); 0178 m_itemList.clear(); 0179 endRemoveRows(); 0180 } 0181 } 0182 0183 Qt::DropActions KFindItemModel::supportedDropActions() const 0184 { 0185 return Qt::CopyAction | Qt::MoveAction; 0186 } 0187 0188 Qt::ItemFlags KFindItemModel::flags(const QModelIndex &index) const 0189 { 0190 const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; 0191 if (index.isValid()) { 0192 return Qt::ItemIsDragEnabled | defaultFlags; 0193 } 0194 return defaultFlags; 0195 } 0196 0197 QMimeData *KFindItemModel::mimeData(const QModelIndexList &indexes) const 0198 { 0199 QList<QUrl> uris; 0200 0201 for (const QModelIndex &index : indexes) { 0202 if (index.isValid()) { 0203 if (index.column() == 0) { //Only use the first column item 0204 uris.append(m_itemList.at(index.row()).getFileItem().url()); 0205 } 0206 } 0207 } 0208 0209 if (uris.isEmpty()) { 0210 return nullptr; 0211 } 0212 0213 QMimeData *mimeData = new QMimeData(); 0214 mimeData->setUrls(uris); 0215 0216 return mimeData; 0217 } 0218 0219 int KFindItemModel::columnCount(const QModelIndex &parent) const 0220 { 0221 Q_UNUSED(parent); 0222 return 6; 0223 } 0224 0225 //END KFindItemModel 0226 0227 //BEGIN KFindItem 0228 0229 KFindItem::KFindItem(const KFileItem &_fileItem, const QString &subDir, const QString &matchingLine) 0230 { 0231 m_fileItem = _fileItem; 0232 m_subDir = subDir; 0233 m_matchingLine = matchingLine; 0234 0235 //TODO more caching ? 0236 if (!m_fileItem.isNull() && m_fileItem.isLocalFile()) { 0237 QFileInfo fileInfo(m_fileItem.url().toLocalFile()); 0238 0239 int perm_index; 0240 if (fileInfo.isReadable()) { 0241 perm_index = fileInfo.isWritable() ? RW : RO; 0242 } else { 0243 perm_index = fileInfo.isWritable() ? WO : NA; 0244 } 0245 m_permission = KLocalizedString(perm[perm_index]).toString(); 0246 0247 m_icon = QIcon::fromTheme(m_fileItem.iconName()); 0248 } 0249 } 0250 0251 QVariant KFindItem::data(int column, int role) const 0252 { 0253 if (m_fileItem.isNull()) { 0254 return QVariant(); 0255 } 0256 0257 if (role == Qt::DecorationRole) { 0258 if (column == 0) { 0259 return m_icon; 0260 } else { 0261 return QVariant(); 0262 } 0263 } 0264 0265 if (role == Qt::DisplayRole) { 0266 switch (column) { 0267 case 0: 0268 return m_fileItem.url().fileName(); 0269 case 1: 0270 return m_subDir; 0271 case 2: 0272 return KIO::convertSize(m_fileItem.size()); 0273 case 3: 0274 return m_fileItem.timeString(KFileItem::ModificationTime); 0275 case 4: 0276 return m_permission; 0277 case 5: 0278 return m_matchingLine; 0279 default: 0280 return QVariant(); 0281 } 0282 } 0283 0284 if (role == Qt::UserRole) { 0285 switch (column) { 0286 case 2: 0287 return m_fileItem.size(); 0288 case 3: 0289 return m_fileItem.time(KFileItem::ModificationTime).toSecsSinceEpoch(); 0290 default: 0291 return QVariant(); 0292 } 0293 } 0294 0295 return QVariant(); 0296 } 0297 0298 KFileItem KFindItem::getFileItem() const 0299 { 0300 return m_fileItem; 0301 } 0302 0303 bool KFindItem::isValid() const 0304 { 0305 return !m_fileItem.isNull(); 0306 } 0307 0308 //END KFindItem 0309 0310 //BEGIN KFindSortFilterProxyModel 0311 0312 bool KFindSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const 0313 { 0314 //Order by UserData size in bytes or unix date 0315 if (left.column() == 2 || left.column() == 3) { 0316 qulonglong leftData = sourceModel()->data(left, Qt::UserRole).toULongLong(); 0317 qulonglong rightData = sourceModel()->data(right, Qt::UserRole).toULongLong(); 0318 return leftData < rightData; 0319 } 0320 // Default sorting rules for string values 0321 else { 0322 return QSortFilterProxyModel::lessThan(left, right); 0323 } 0324 } 0325 0326 //END KFindSortFilterProxyModel 0327 0328 //BEGIN KFindTreeView 0329 0330 KFindTreeView::KFindTreeView(QWidget *parent, KfindDlg *findDialog) 0331 : QTreeView(parent) 0332 , m_model(new KFindItemModel(this)) 0333 , m_proxyModel(new KFindSortFilterProxyModel(this)) 0334 , m_kfindDialog(findDialog) 0335 { 0336 m_proxyModel->setSourceModel(m_model); 0337 setModel(m_proxyModel); 0338 0339 //Configure QTreeView 0340 setRootIsDecorated(false); 0341 setSelectionMode(QAbstractItemView::ExtendedSelection); 0342 setSortingEnabled(true); 0343 setDragEnabled(true); 0344 setContextMenuPolicy(Qt::CustomContextMenu); 0345 0346 connect(this, &KFindTreeView::customContextMenuRequested, this, &KFindTreeView::contextMenuRequested); 0347 0348 //Mouse single/double click settings 0349 reconfigureMouseSettings(); 0350 0351 // TODO: this is a workaround until Qt-issue 176832 has been fixed (from Dolphin) 0352 connect(this, &KFindTreeView::pressed, this, &KFindTreeView::updateMouseButtons); 0353 0354 //Generate popup menu actions 0355 m_actionCollection = new KActionCollection(this); 0356 m_actionCollection->addAssociatedWidget(this); 0357 0358 QAction *open = KStandardAction::open(this, SLOT(slotExecuteSelected()), this); 0359 m_actionCollection->addAction(QStringLiteral("file_open"), open); 0360 0361 QAction *copy = KStandardAction::copy(this, SLOT(copySelection()), this); 0362 m_actionCollection->addAction(QStringLiteral("edit_copy"), copy); 0363 0364 QAction *copyPathAction = m_actionCollection->addAction(QStringLiteral("copy_location")); 0365 copyPathAction->setText(i18nc("@action:incontextmenu", "Copy Location")); 0366 copyPathAction->setWhatsThis(i18nc("@info:whatsthis copy_location", "This will copy the path of the first selected item into the clipboard.")); 0367 copyPathAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy-path"))); 0368 m_actionCollection->setDefaultShortcuts(copyPathAction, {Qt::CTRL | Qt::ALT | Qt::Key_C}); 0369 connect(copyPathAction, &QAction::triggered, this, &KFindTreeView::copySelectionPath); 0370 0371 QAction *openFolder = new QAction(QIcon::fromTheme(QStringLiteral("window-new")), i18n("&Open containing folder(s)"), this); 0372 connect(openFolder, &QAction::triggered, this, &KFindTreeView::openContainingFolder); 0373 m_actionCollection->addAction(QStringLiteral("openfolder"), openFolder); 0374 0375 QAction *del = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("&Delete"), this); 0376 connect(del, &QAction::triggered, this, &KFindTreeView::deleteSelectedFiles); 0377 m_actionCollection->setDefaultShortcut(del, Qt::SHIFT | Qt::Key_Delete); 0378 0379 QAction *trash = new QAction(QIcon::fromTheme(QStringLiteral("user-trash")), i18n("&Move to Trash"), this); 0380 connect(trash, &QAction::triggered, this, &KFindTreeView::moveToTrashSelectedFiles); 0381 m_actionCollection->setDefaultShortcut(trash, Qt::Key_Delete); 0382 m_actionCollection->addAction(QStringLiteral("trash"), trash); 0383 0384 header()->setStretchLastSection(true); 0385 0386 sortByColumn(0, Qt::AscendingOrder); 0387 } 0388 0389 KFindTreeView::~KFindTreeView() 0390 { 0391 delete m_model; 0392 delete m_proxyModel; 0393 delete m_actionCollection; 0394 } 0395 0396 void KFindTreeView::resizeToContents() 0397 { 0398 resizeColumnToContents(0); 0399 resizeColumnToContents(1); 0400 resizeColumnToContents(2); 0401 resizeColumnToContents(3); 0402 } 0403 0404 QString KFindTreeView::reducedDir(const QString &fullDir) 0405 { 0406 QString relDir = m_baseDir.relativeFilePath(fullDir); 0407 if (!relDir.startsWith(QLatin1String(".."))) { 0408 return relDir; 0409 } 0410 return fullDir; 0411 } 0412 0413 int KFindTreeView::itemCount() const 0414 { 0415 return m_model->rowCount(); 0416 } 0417 0418 void KFindTreeView::beginSearch(const QUrl &baseUrl) 0419 { 0420 m_baseDir = QDir(baseUrl.toLocalFile()); 0421 m_model->clear(); 0422 } 0423 0424 void KFindTreeView::endSearch() 0425 { 0426 resizeToContents(); 0427 } 0428 0429 QList<QPersistentModelIndex> KFindTreeView::selectedVisibleIndexes() { 0430 QModelIndexList selected = selectedIndexes(); 0431 if (selected.empty()) { 0432 return QList<QPersistentModelIndex>(); 0433 } 0434 QModelIndex index = indexAt(QPoint(0, 0)); 0435 QModelIndex bottomIndex = indexAt(viewport()->rect().bottomLeft()); 0436 QList<QPersistentModelIndex> result; 0437 while (index.isValid()) { 0438 if (selected.contains(index)) { 0439 result.append(QPersistentModelIndex(index)); 0440 } 0441 if (index == bottomIndex) { 0442 break; 0443 } 0444 index = indexBelow(index); 0445 } 0446 return result; 0447 } 0448 0449 void KFindTreeView::insertItems(const QList< QPair<KFileItem, QString> > &pairs) 0450 { 0451 auto hScroll = horizontalScrollBar()->value(); 0452 QPersistentModelIndex topIndex(indexAt(rect().topLeft())); 0453 QList<QPersistentModelIndex> selectedVisible = selectedVisibleIndexes(); 0454 0455 m_model->insertFileItems(pairs); 0456 0457 if (topIndex.isValid()) { 0458 if (verticalScrollBar()->value() > 0) { 0459 scrollTo(topIndex, QAbstractItemView::PositionAtTop); 0460 } 0461 } 0462 if (!selectedVisible.empty()) { 0463 scrollTo(selectedVisible.last()); 0464 } 0465 horizontalScrollBar()->setValue(hScroll); 0466 } 0467 0468 void KFindTreeView::removeItem(const QUrl &url) 0469 { 0470 QList<QUrl> list = selectedUrls(); 0471 if (list.contains(url)) { 0472 //Close menu 0473 delete m_contextMenu; 0474 m_contextMenu = nullptr; 0475 } 0476 m_model->removeItem(url); 0477 } 0478 0479 bool KFindTreeView::isInserted(const QUrl &url) const 0480 { 0481 return m_model->isInserted(url); 0482 } 0483 0484 // copy to clipboard 0485 void KFindTreeView::copySelection() 0486 { 0487 QMimeData *mime = m_model->mimeData(m_proxyModel->mapSelectionToSource(selectionModel()->selection()).indexes()); 0488 if (mime) { 0489 QClipboard *cb = qApp->clipboard(); 0490 cb->setMimeData(mime); 0491 } 0492 } 0493 0494 void KFindTreeView::copySelectionPath() 0495 { 0496 const auto selectedIndexes = m_proxyModel->mapSelectionToSource(selectionModel()->selection()).indexes(); 0497 if (selectedIndexes.isEmpty()) { 0498 return; 0499 } 0500 0501 const auto item = m_model->itemAtIndex(selectedIndexes.at(0)).getFileItem(); 0502 0503 QString path = item.localPath(); 0504 if (path.isEmpty()) { 0505 path = item.url().toDisplayString(); 0506 } 0507 0508 QClipboard *clipboard = QApplication::clipboard(); 0509 if (!clipboard) { 0510 return; 0511 } 0512 clipboard->setText(path); 0513 } 0514 0515 void KFindTreeView::saveResults() 0516 { 0517 QFileDialog dialog; 0518 dialog.setAcceptMode(QFileDialog::AcceptSave); 0519 dialog.setWindowTitle(i18nc("@title:window", "Save Results As")); 0520 dialog.setMimeTypeFilters({ 0521 QStringLiteral("text/html"), 0522 QStringLiteral("text/plain") 0523 }); 0524 0525 if (!dialog.exec()) { 0526 return; 0527 } 0528 0529 if (dialog.selectedUrls().isEmpty()) { 0530 return; 0531 } 0532 0533 const QUrl u = dialog.selectedUrls().constFirst(); 0534 if (!u.isValid() || !u.isLocalFile()) { 0535 return; 0536 } 0537 0538 QString filename = u.toLocalFile(); 0539 0540 QFile file(filename); 0541 0542 if (!file.open(QIODevice::WriteOnly)) { 0543 KMessageBox::error(parentWidget(), 0544 i18n("Unable to save results.")); 0545 } else { 0546 QTextStream stream(&file); 0547 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0548 stream.setEncoding(QStringConverter::System); 0549 #else 0550 stream.setCodec(QTextCodec::codecForLocale()); 0551 #endif 0552 0553 const QList<KFindItem> itemList = m_model->getItemList(); 0554 if (dialog.selectedMimeTypeFilter() == QLatin1String("text/html")) { 0555 stream << QString::fromLatin1("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" 0556 "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\">\n" 0557 "<head>\n" 0558 "<title>%2</title></head>\n" 0559 "<meta charset=\"%1\">\n" 0560 "<body>\n<h1>%2</h1>\n" 0561 "<dl>\n") 0562 .arg(QString::fromLatin1(QTextCodec::codecForLocale()->name()), i18n("KFind Results File")); 0563 0564 for (const KFindItem &item : itemList) { 0565 const KFileItem fileItem = item.getFileItem(); 0566 stream << QStringLiteral("<dt><a href=\"%1\">%2</a></dt>\n").arg( 0567 fileItem.url().url(), fileItem.url().toDisplayString()); 0568 } 0569 stream << QStringLiteral("</dl>\n</body>\n</html>\n"); 0570 } else { 0571 for (const KFindItem &item : itemList) { 0572 stream << item.getFileItem().url().url() << Qt::endl; 0573 } 0574 } 0575 0576 file.close(); 0577 m_kfindDialog->setStatusMsg(i18nc("%1=filename", "Results were saved to: %1", filename)); 0578 } 0579 } 0580 0581 void KFindTreeView::openContainingFolder() 0582 { 0583 KIO::highlightInFileManager(selectedUrls()); 0584 } 0585 0586 void KFindTreeView::slotExecuteSelected() 0587 { 0588 const QModelIndexList selected = m_proxyModel->mapSelectionToSource(selectionModel()->selection()).indexes(); 0589 if (selected.isEmpty()) { 0590 return; 0591 } 0592 0593 //TODO if >X add a warn ? 0594 for (const QModelIndex &index : selected) { 0595 if (index.column() == 0) { 0596 KFindItem item = m_model->itemAtIndex(index); 0597 if (item.isValid()) { 0598 auto *job = new KIO::OpenUrlJob(item.getFileItem().targetUrl()); 0599 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) 0600 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); 0601 #else 0602 job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); 0603 #endif 0604 job->start(); 0605 } 0606 } 0607 } 0608 } 0609 0610 void KFindTreeView::slotExecute(const QModelIndex &index) 0611 { 0612 if ((m_mouseButtons & Qt::LeftButton) && QApplication::keyboardModifiers() == Qt::NoModifier) { 0613 if (!index.isValid()) { 0614 return; 0615 } 0616 0617 QModelIndex realIndex = m_proxyModel->mapToSource(index); 0618 if (!realIndex.isValid()) { 0619 return; 0620 } 0621 0622 const KFindItem item = m_model->itemAtIndex(realIndex); 0623 if (item.isValid()) { 0624 auto *job = new KIO::OpenUrlJob(item.getFileItem().targetUrl()); 0625 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) 0626 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); 0627 #else 0628 job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); 0629 #endif 0630 job->start(); 0631 } 0632 } 0633 } 0634 0635 void KFindTreeView::contextMenuRequested(const QPoint &p) 0636 { 0637 KFileItemList fileList; 0638 0639 const QModelIndexList selected = m_proxyModel->mapSelectionToSource(selectionModel()->selection()).indexes(); 0640 if (selected.isEmpty()) { 0641 return; 0642 } 0643 0644 for (const QModelIndex &index : selected) { 0645 if (index.column() == 0) { 0646 const KFindItem item = m_model->itemAtIndex(index); 0647 if (item.isValid()) { 0648 fileList.append(item.getFileItem()); 0649 } 0650 } 0651 } 0652 0653 delete m_contextMenu; 0654 m_contextMenu = new QMenu(this); 0655 m_contextMenu->addAction(m_actionCollection->action(QStringLiteral("file_open"))); 0656 m_contextMenu->addAction(m_actionCollection->action(QStringLiteral("openfolder"))); 0657 m_contextMenu->addAction(m_actionCollection->action(QStringLiteral("edit_copy"))); 0658 0659 QAction *copyLocationAction = m_actionCollection->action(QStringLiteral("copy_location")); 0660 // It's not worth it to track the selection and update the action live. 0661 copyLocationAction->setEnabled(fileList.count() == 1); 0662 m_contextMenu->addAction(copyLocationAction); 0663 0664 //m_contextMenu->addAction(m_actionCollection->action(QLatin1String("del"))); 0665 m_contextMenu->addAction(m_actionCollection->action(QStringLiteral("trash"))); 0666 m_contextMenu->addSeparator(); 0667 0668 // Open With... 0669 KFileItemActions menuActions; 0670 KFileItemListProperties fileProperties(fileList); 0671 menuActions.setItemListProperties(fileProperties); 0672 menuActions.insertOpenWithActionsTo(nullptr, m_contextMenu, QStringList()); 0673 // 'Actions' submenu 0674 menuActions.addActionsTo(m_contextMenu); 0675 0676 m_contextMenu->addSeparator(); 0677 0678 // Properties 0679 if (KPropertiesDialog::canDisplay(fileList)) { 0680 QAction *act = new QAction(m_contextMenu); 0681 act->setText(i18n("&Properties")); 0682 QObject::connect(act, &QAction::triggered, [this, fileList]() { 0683 KPropertiesDialog::showDialog(fileList, this, false /*non modal*/); 0684 }); 0685 m_contextMenu->addAction(act); 0686 } 0687 0688 m_contextMenu->exec(this->mapToGlobal(p)); 0689 } 0690 0691 QList<QUrl> KFindTreeView::selectedUrls() const 0692 { 0693 QList<QUrl> uris; 0694 0695 const QModelIndexList indexes = m_proxyModel->mapSelectionToSource(selectionModel()->selection()).indexes(); 0696 for (const QModelIndex &index : indexes) { 0697 if (index.column() == 0 && index.isValid()) { 0698 KFindItem item = m_model->itemAtIndex(index); 0699 if (item.isValid()) { 0700 uris.append(item.getFileItem().url()); 0701 } 0702 } 0703 } 0704 0705 return uris; 0706 } 0707 0708 void KFindTreeView::deleteSelectedFiles() 0709 { 0710 QList<QUrl> uris = selectedUrls(); 0711 if (uris.isEmpty()) { 0712 return; 0713 } 0714 0715 #if KIO_VERSION < QT_VERSION_CHECK(5, 100, 0) 0716 KIO::JobUiDelegate uiDelegate; 0717 uiDelegate.setWindow(this); 0718 if (uiDelegate.askDeleteConfirmation(uris, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::ForceConfirmation)) { 0719 KJob *deleteJob = KIO::del(uris); 0720 KJobWidgets::setWindow(deleteJob, this); 0721 deleteJob->uiDelegate()->setAutoErrorHandlingEnabled(true); 0722 } 0723 #else 0724 using Iface = KIO::AskUserActionInterface; 0725 auto *trashJob = new KIO::DeleteOrTrashJob(uris, Iface::Delete, Iface::ForceConfirmation, this); 0726 trashJob->start(); 0727 #endif 0728 } 0729 0730 void KFindTreeView::moveToTrashSelectedFiles() 0731 { 0732 QList<QUrl> uris = selectedUrls(); 0733 if (uris.isEmpty()) { 0734 return; 0735 } 0736 0737 #if KIO_VERSION < QT_VERSION_CHECK(5, 100, 0) 0738 KIO::JobUiDelegate uiDelegate; 0739 uiDelegate.setWindow(this); 0740 if (uiDelegate.askDeleteConfirmation(uris, KIO::JobUiDelegate::Trash, KIO::JobUiDelegate::ForceConfirmation)) { 0741 KJob *trashJob = KIO::trash(uris); 0742 KJobWidgets::setWindow(trashJob, this); 0743 trashJob->uiDelegate()->setAutoErrorHandlingEnabled(true); 0744 } 0745 #else 0746 using Iface = KIO::AskUserActionInterface; 0747 auto *trashJob = new KIO::DeleteOrTrashJob(uris, Iface::Trash, Iface::ForceConfirmation, this); 0748 trashJob->start(); 0749 #endif 0750 } 0751 0752 void KFindTreeView::reconfigureMouseSettings() 0753 { 0754 disconnect(this, &KFindTreeView::clicked, this, &KFindTreeView::slotExecute); 0755 disconnect(this, &KFindTreeView::doubleClicked, this, &KFindTreeView::slotExecute); 0756 0757 if (m_kfindDialog->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) { 0758 connect(this, &KFindTreeView::clicked, this, &KFindTreeView::slotExecute); 0759 } else { 0760 connect(this, &KFindTreeView::doubleClicked, this, &KFindTreeView::slotExecute); 0761 } 0762 } 0763 0764 void KFindTreeView::updateMouseButtons() 0765 { 0766 m_mouseButtons = QApplication::mouseButtons(); 0767 } 0768 0769 void KFindTreeView::dragMoveEvent(QDragMoveEvent *e) 0770 { 0771 e->accept(); 0772 } 0773 0774 //END KFindTreeView 0775 0776 #include "moc_kfindtreeview.cpp"