File indexing completed on 2024-05-12 09:54:30
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2010 Thomas Fjellstrom <thomas@fjellstrom.ca> 0003 SPDX-FileCopyrightText: 2014 Joseph Wenninger <jowenn@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 // BEGIN Includes 0009 #include "katefiletree.h" 0010 0011 #include "filehistorywidget.h" 0012 #include "katefileactions.h" 0013 #include "katefiletreemodel.h" 0014 #include "katefiletreeproxymodel.h" 0015 0016 #include <ktexteditor/application.h> 0017 #include <ktexteditor/document.h> 0018 #include <ktexteditor/editor.h> 0019 0020 #include <KIO/CopyJob> 0021 #include <KIO/DeleteJob> 0022 #include <KIO/OpenFileManagerWindowJob> 0023 #include <KLocalizedString> 0024 #include <KMessageBox> 0025 #include <KStandardAction> 0026 #include <KTextEditor/MainWindow> 0027 0028 #include <QActionGroup> 0029 #include <QApplication> 0030 #include <QClipboard> 0031 #include <QContextMenuEvent> 0032 #include <QDir> 0033 #include <QHeaderView> 0034 #include <QInputDialog> 0035 #include <QLineEdit> 0036 #include <QMenu> 0037 #include <QMimeDatabase> 0038 #include <QStyledItemDelegate> 0039 // END Includes 0040 0041 namespace 0042 { 0043 KTextEditor::Document *docFromIndex(const QModelIndex &index) 0044 { 0045 return index.data(KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>(); 0046 } 0047 0048 QList<KTextEditor::Document *> docTreeFromIndex(const QModelIndex &index) 0049 { 0050 return index.data(KateFileTreeModel::DocumentTreeRole).value<QList<KTextEditor::Document *>>(); 0051 } 0052 0053 bool closeDocs(const QList<KTextEditor::Document *> &docs) 0054 { 0055 return KTextEditor::Editor::instance()->application()->closeDocuments(docs); 0056 } 0057 0058 class CloseIconStyleDelegate : public QStyledItemDelegate 0059 { 0060 public: 0061 explicit CloseIconStyleDelegate(QObject *parent = nullptr) 0062 : QStyledItemDelegate(parent) 0063 { 0064 } 0065 0066 void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override 0067 { 0068 QStyledItemDelegate::paint(painter, option, index); 0069 0070 if (!m_showCloseBtn) { 0071 return; 0072 } 0073 0074 if (index.column() == 1 && option.state & QStyle::State_Enabled && option.state & QStyle::State_MouseOver) { 0075 const QIcon icon = QIcon::fromTheme(QStringLiteral("tab-close")); 0076 const int w = option.decorationSize.width(); 0077 QRect iconRect(option.rect.right() - w, option.rect.top(), w, option.rect.height()); 0078 icon.paint(painter, iconRect, Qt::AlignRight | Qt::AlignVCenter); 0079 } 0080 } 0081 0082 void setShowCloseButton(bool s) 0083 { 0084 m_showCloseBtn = s; 0085 } 0086 0087 private: 0088 bool m_showCloseBtn = false; 0089 }; 0090 } // namespace 0091 0092 // BEGIN KateFileTree 0093 0094 KateFileTree::KateFileTree(KTextEditor::MainWindow *mainWindow, QWidget *parent) 0095 : QTreeView(parent) 0096 , m_mainWindow(mainWindow) 0097 { 0098 setIndentation(12); 0099 setAllColumnsShowFocus(true); 0100 setFocusPolicy(Qt::NoFocus); 0101 setSelectionBehavior(QAbstractItemView::SelectRows); 0102 // for hover close button 0103 viewport()->setAttribute(Qt::WA_Hover); 0104 0105 // DND 0106 setDefaultDropAction(Qt::MoveAction); 0107 setDragDropMode(QAbstractItemView::InternalMove); 0108 setDragDropOverwriteMode(false); 0109 setAcceptDrops(true); 0110 setDropIndicatorShown(true); 0111 setDragEnabled(true); 0112 setUniformRowHeights(true); 0113 0114 setItemDelegate(new CloseIconStyleDelegate(this)); 0115 0116 // handle activated (e.g. for pressing enter) + clicked (to avoid to need to do double-click e.g. on Windows) 0117 connect(this, &KateFileTree::activated, this, &KateFileTree::mouseClicked); 0118 connect(this, &KateFileTree::clicked, this, &KateFileTree::mouseClicked); 0119 0120 m_filelistReloadDocument = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18nc("@action:inmenu", "Reloa&d"), this); 0121 connect(m_filelistReloadDocument, &QAction::triggered, this, &KateFileTree::slotDocumentReload); 0122 m_filelistReloadDocument->setWhatsThis(i18n("Reload selected document(s) from disk.")); 0123 0124 m_filelistCloseDocument = new QAction(QIcon::fromTheme(QStringLiteral("document-close")), i18nc("@action:inmenu", "Close"), this); 0125 connect(m_filelistCloseDocument, &QAction::triggered, this, &KateFileTree::slotDocumentClose); 0126 m_filelistCloseDocument->setWhatsThis(i18n("Close the current document.")); 0127 0128 m_filelistExpandRecursive = new QAction(QIcon::fromTheme(QStringLiteral("view-list-tree")), i18nc("@action:inmenu", "Expand Recursively"), this); 0129 connect(m_filelistExpandRecursive, &QAction::triggered, this, &KateFileTree::slotExpandRecursive); 0130 m_filelistExpandRecursive->setWhatsThis(i18n("Expand the file list sub tree recursively.")); 0131 0132 m_filelistCollapseRecursive = new QAction(QIcon::fromTheme(QStringLiteral("view-list-tree")), i18nc("@action:inmenu", "Collapse Recursively"), this); 0133 connect(m_filelistCollapseRecursive, &QAction::triggered, this, &KateFileTree::slotCollapseRecursive); 0134 m_filelistCollapseRecursive->setWhatsThis(i18n("Collapse the file list sub tree recursively.")); 0135 0136 m_filelistCloseOtherDocument = new QAction(QIcon::fromTheme(QStringLiteral("document-close")), i18nc("@action:inmenu", "Close Other"), this); 0137 connect(m_filelistCloseOtherDocument, &QAction::triggered, this, &KateFileTree::slotDocumentCloseOther); 0138 m_filelistCloseOtherDocument->setWhatsThis(i18n("Close other documents in this folder.")); 0139 0140 m_filelistOpenContainingFolder = 0141 new QAction(QIcon::fromTheme(QStringLiteral("document-open-folder")), i18nc("@action:inmenu", "Open Containing Folder"), this); 0142 connect(m_filelistOpenContainingFolder, &QAction::triggered, this, &KateFileTree::slotOpenContainingFolder); 0143 m_filelistOpenContainingFolder->setWhatsThis(i18n("Open the folder this file is located in.")); 0144 0145 m_filelistCopyFilename = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy-path")), i18nc("@action:inmenu", "Copy Location"), this); 0146 connect(m_filelistCopyFilename, &QAction::triggered, this, &KateFileTree::slotCopyFilename); 0147 m_filelistCopyFilename->setWhatsThis(i18n("Copy path and filename to the clipboard.")); 0148 0149 m_filelistRenameFile = new QAction(QIcon::fromTheme(QStringLiteral("edit-rename")), i18nc("@action:inmenu", "Rename..."), this); 0150 connect(m_filelistRenameFile, &QAction::triggered, this, &KateFileTree::slotRenameFile); 0151 m_filelistRenameFile->setWhatsThis(i18n("Rename the selected file.")); 0152 0153 m_filelistPrintDocument = KStandardAction::print(this, &KateFileTree::slotPrintDocument, this); 0154 m_filelistPrintDocument->setWhatsThis(i18n("Print selected document.")); 0155 0156 m_filelistPrintDocumentPreview = KStandardAction::printPreview(this, &KateFileTree::slotPrintDocumentPreview, this); 0157 m_filelistPrintDocumentPreview->setWhatsThis(i18n("Show print preview of current document")); 0158 0159 m_filelistDeleteDocument = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@action:inmenu", "Delete"), this); 0160 connect(m_filelistDeleteDocument, &QAction::triggered, this, &KateFileTree::slotDocumentDelete); 0161 m_filelistDeleteDocument->setWhatsThis(i18n("Close and delete selected file from storage.")); 0162 0163 setupContextMenuActionGroups(); 0164 0165 m_resetHistory = new QAction(QIcon::fromTheme(QStringLiteral("edit-clear-history")), i18nc("@action:inmenu", "Clear History"), this); 0166 connect(m_resetHistory, &QAction::triggered, this, &KateFileTree::slotResetHistory); 0167 m_resetHistory->setWhatsThis(i18n("Clear edit/view history.")); 0168 0169 QPalette p = palette(); 0170 p.setColor(QPalette::Inactive, QPalette::Highlight, p.color(QPalette::Active, QPalette::Highlight)); 0171 p.setColor(QPalette::Inactive, QPalette::HighlightedText, p.color(QPalette::Active, QPalette::HighlightedText)); 0172 setPalette(p); 0173 } 0174 0175 KateFileTree::~KateFileTree() = default; 0176 0177 void KateFileTree::setModel(QAbstractItemModel *model) 0178 { 0179 m_proxyModel = static_cast<KateFileTreeProxyModel *>(model); 0180 Q_ASSERT(m_proxyModel); // we don't really work with anything else 0181 QTreeView::setModel(model); 0182 m_sourceModel = static_cast<KateFileTreeModel *>(m_proxyModel->sourceModel()); 0183 0184 header()->hide(); 0185 header()->setStretchLastSection(false); 0186 header()->setSectionResizeMode(0, QHeaderView::Stretch); 0187 0188 const int minSize = m_hasCloseButton ? 16 : 1; 0189 header()->setMinimumSectionSize(minSize); 0190 header()->setSectionResizeMode(1, QHeaderView::Fixed); 0191 header()->resizeSection(1, minSize); 0192 0193 // proxy never emits rowsMoved 0194 connect(m_proxyModel->sourceModel(), &QAbstractItemModel::rowsMoved, this, &KateFileTree::onRowsMoved); 0195 } 0196 0197 void KateFileTree::onRowsMoved(const QModelIndex &, int, int, const QModelIndex &destination, int row) 0198 { 0199 QModelIndex movedIndex = m_proxyModel->mapFromSource(m_sourceModel->index(row, 0, destination)); 0200 // We moved stuff, make sure if child was expanded, we expand all parents too. 0201 if (movedIndex.isValid() && isExpanded(movedIndex) && !isExpanded(movedIndex.parent())) { 0202 QModelIndex movedParent = movedIndex.parent(); 0203 while (movedParent.isValid() && !isExpanded(movedParent)) { 0204 expand(movedParent); 0205 movedParent = movedParent.parent(); 0206 } 0207 } 0208 } 0209 0210 void KateFileTree::setShowCloseButton(bool show) 0211 { 0212 m_hasCloseButton = show; 0213 static_cast<CloseIconStyleDelegate *>(itemDelegate())->setShowCloseButton(show); 0214 0215 if (!header()) 0216 return; 0217 0218 const int minSize = show ? 16 : 1; 0219 header()->setMinimumSectionSize(minSize); 0220 header()->resizeSection(1, minSize); 0221 header()->viewport()->update(); 0222 } 0223 0224 void KateFileTree::setupContextMenuActionGroups() 0225 { 0226 QActionGroup *modeGroup = new QActionGroup(this); 0227 0228 m_treeModeAction = setupOption(modeGroup, 0229 QIcon::fromTheme(QStringLiteral("view-list-tree")), 0230 i18nc("@action:inmenu", "Tree Mode"), 0231 i18n("Set view style to Tree Mode"), 0232 &KateFileTree::slotTreeMode, 0233 Qt::Checked); 0234 0235 m_listModeAction = setupOption(modeGroup, 0236 QIcon::fromTheme(QStringLiteral("view-list-text")), 0237 i18nc("@action:inmenu", "List Mode"), 0238 i18n("Set view style to List Mode"), 0239 &KateFileTree::slotListMode); 0240 0241 QActionGroup *sortGroup = new QActionGroup(this); 0242 0243 m_sortByFile = setupOption(sortGroup, 0244 QIcon(), 0245 i18nc("@action:inmenu sorting option", "Document Name"), 0246 i18n("Sort by Document Name"), 0247 &KateFileTree::slotSortName, 0248 Qt::Checked); 0249 0250 m_sortByPath = 0251 setupOption(sortGroup, QIcon(), i18nc("@action:inmenu sorting option", "Document Path"), i18n("Sort by Document Path"), &KateFileTree::slotSortPath); 0252 0253 m_sortByOpeningOrder = setupOption(sortGroup, 0254 QIcon(), 0255 i18nc("@action:inmenu sorting option", "Opening Order"), 0256 i18n("Sort by Opening Order"), 0257 &KateFileTree::slotSortOpeningOrder); 0258 0259 m_customSorting = new QAction(QIcon(), i18n("Custom Sorting"), this); 0260 m_customSorting->setCheckable(true); 0261 m_customSorting->setActionGroup(sortGroup); 0262 connect(m_customSorting, &QAction::triggered, this, [this] { 0263 Q_EMIT sortRoleChanged(CustomSorting); 0264 }); 0265 } 0266 0267 QAction *KateFileTree::setupOption(QActionGroup *group, 0268 const QIcon &icon, 0269 const QString &text, 0270 const QString &whatsThis, 0271 const Func &slot, 0272 Qt::CheckState checked /* = Qt::Unchecked */) 0273 { 0274 QAction *new_action = new QAction(icon, text, this); 0275 new_action->setWhatsThis(whatsThis); 0276 new_action->setActionGroup(group); 0277 new_action->setCheckable(true); 0278 new_action->setChecked(checked == Qt::Checked); 0279 connect(new_action, &QAction::triggered, this, slot); 0280 return new_action; 0281 } 0282 0283 void KateFileTree::slotListMode() 0284 { 0285 Q_EMIT viewModeChanged(true); 0286 } 0287 0288 void KateFileTree::slotTreeMode() 0289 { 0290 Q_EMIT viewModeChanged(false); 0291 } 0292 0293 void KateFileTree::slotSortName() 0294 { 0295 Q_EMIT sortRoleChanged(Qt::DisplayRole); 0296 } 0297 0298 void KateFileTree::slotSortPath() 0299 { 0300 Q_EMIT sortRoleChanged(KateFileTreeModel::PathRole); 0301 } 0302 0303 void KateFileTree::slotSortOpeningOrder() 0304 { 0305 Q_EMIT sortRoleChanged(KateFileTreeModel::OpeningOrderRole); 0306 } 0307 0308 void KateFileTree::slotCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous) 0309 { 0310 Q_UNUSED(previous); 0311 if (!current.isValid()) { 0312 return; 0313 } 0314 0315 KTextEditor::Document *doc = m_proxyModel->docFromIndex(current); 0316 if (doc) { 0317 m_previouslySelected = current; 0318 } 0319 } 0320 0321 void KateFileTree::closeClicked(const QModelIndex &index) 0322 { 0323 if (m_proxyModel->isDir(index)) { 0324 const QList<KTextEditor::Document *> list = m_proxyModel->docTreeFromIndex(index); 0325 closeDocs(list); 0326 return; 0327 } else if (m_proxyModel->isWidgetDir(index)) { 0328 const auto idx = index.siblingAtColumn(0); 0329 const auto count = m_proxyModel->rowCount(idx); 0330 QWidgetList widgets; 0331 widgets.reserve(count); 0332 for (int i = 0; i < count; ++i) { 0333 widgets << m_proxyModel->index(i, 0, idx).data(KateFileTreeModel::WidgetRole).value<QWidget *>(); 0334 } 0335 0336 for (const auto &w : widgets) { 0337 closeWidget(w); 0338 } 0339 } 0340 0341 if (auto *doc = m_proxyModel->docFromIndex(index)) { 0342 closeDocs({doc}); 0343 } else if (auto *w = index.data(KateFileTreeModel::WidgetRole).value<QWidget *>()) { 0344 Q_EMIT closeWidget(w); 0345 } 0346 } 0347 0348 void KateFileTree::mouseClicked(const QModelIndex &index) 0349 { 0350 if (m_hasCloseButton && index.column() == 1) { 0351 closeClicked(index); 0352 return; 0353 } 0354 0355 if (auto *doc = m_proxyModel->docFromIndex(index)) { 0356 Q_EMIT activateDocument(doc); 0357 } else if (auto *w = index.data(KateFileTreeModel::WidgetRole).value<QWidget *>()) { 0358 Q_EMIT activateWidget(w); 0359 } 0360 } 0361 0362 void KateFileTree::contextMenuEvent(QContextMenuEvent *event) 0363 { 0364 m_indexContextMenu = indexAt(event->pos()); 0365 if (m_indexContextMenu.isValid()) { 0366 selectionModel()->setCurrentIndex(m_indexContextMenu, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); 0367 } 0368 0369 const bool listMode = m_sourceModel->listMode(); 0370 m_treeModeAction->setChecked(!listMode); 0371 m_listModeAction->setChecked(listMode); 0372 0373 const int sortRole = m_proxyModel->sortRole(); 0374 m_sortByFile->setChecked(sortRole == Qt::DisplayRole); 0375 m_sortByPath->setChecked(sortRole == KateFileTreeModel::PathRole); 0376 m_sortByOpeningOrder->setChecked(sortRole == KateFileTreeModel::OpeningOrderRole); 0377 m_customSorting->setChecked(sortRole == CustomSorting); 0378 0379 KTextEditor::Document *doc = docFromIndex(m_indexContextMenu); 0380 0381 bool isDir = m_proxyModel->isDir(m_indexContextMenu); 0382 bool isWidgetDir = m_proxyModel->isWidgetDir(m_indexContextMenu); 0383 bool isWidget = m_indexContextMenu.data(KateFileTreeModel::WidgetRole).value<QWidget *>() != nullptr; 0384 0385 QMenu menu(this); 0386 if (doc) { 0387 if (doc->url().isValid()) { 0388 QMenu *openWithMenu = menu.addMenu(i18nc("@action:inmenu", "Open With")); 0389 openWithMenu->setIcon(QIcon::fromTheme(QStringLiteral("system-run"))); 0390 connect(openWithMenu, &QMenu::aboutToShow, this, [this, openWithMenu]() { 0391 slotFixOpenWithMenu(openWithMenu); 0392 }); 0393 connect(openWithMenu, &QMenu::triggered, this, &KateFileTree::slotOpenWithMenuAction); 0394 0395 menu.addSeparator(); 0396 menu.addAction(m_filelistCopyFilename); 0397 menu.addAction(m_filelistRenameFile); 0398 menu.addAction(m_filelistDeleteDocument); 0399 menu.addAction(m_filelistReloadDocument); 0400 0401 if (doc->url().isLocalFile()) { 0402 auto a = menu.addAction(i18n("Show File Git History")); 0403 connect(a, &QAction::triggered, this, [doc] { 0404 auto url = doc->url(); 0405 if (url.isValid() && url.isLocalFile()) { 0406 FileHistory::showFileHistory(url.toLocalFile()); 0407 } 0408 }); 0409 } 0410 0411 menu.addSeparator(); 0412 menu.addAction(m_filelistOpenContainingFolder); 0413 0414 menu.addSeparator(); 0415 menu.addAction(m_filelistCloseDocument); 0416 menu.addAction(m_filelistCloseOtherDocument); 0417 0418 menu.addSeparator(); 0419 menu.addAction(m_filelistPrintDocument); 0420 menu.addAction(m_filelistPrintDocumentPreview); 0421 } else { 0422 // untitled documents 0423 menu.addAction(m_filelistCloseDocument); 0424 0425 menu.addSeparator(); 0426 } 0427 } else if (isDir || isWidgetDir || isWidget) { 0428 if (isDir) { 0429 menu.addAction(m_filelistReloadDocument); 0430 } 0431 0432 menu.addSeparator(); 0433 menu.addAction(m_filelistCloseDocument); 0434 0435 menu.addSeparator(); 0436 menu.addAction(m_filelistExpandRecursive); 0437 menu.addAction(m_filelistCollapseRecursive); 0438 } 0439 0440 menu.addSeparator(); 0441 QMenu *view_menu = menu.addMenu(i18nc("@action:inmenu", "View Mode")); 0442 view_menu->addAction(m_treeModeAction); 0443 view_menu->addAction(m_listModeAction); 0444 0445 QMenu *sort_menu = menu.addMenu(QIcon::fromTheme(QStringLiteral("view-sort")), i18nc("@action:inmenu", "Sort By")); 0446 sort_menu->addAction(m_sortByFile); 0447 sort_menu->addAction(m_sortByPath); 0448 sort_menu->addAction(m_sortByOpeningOrder); 0449 sort_menu->addAction(m_customSorting); 0450 0451 m_filelistCloseDocument->setEnabled(m_indexContextMenu.isValid()); 0452 0453 menu.addAction(m_resetHistory); 0454 0455 menu.exec(viewport()->mapToGlobal(event->pos())); 0456 0457 if (m_previouslySelected.isValid()) { 0458 selectionModel()->setCurrentIndex(m_previouslySelected, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); 0459 } 0460 0461 event->accept(); 0462 } 0463 0464 void KateFileTree::slotFixOpenWithMenu(QMenu *menu) 0465 { 0466 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_indexContextMenu); 0467 if (!doc) { 0468 return; 0469 } 0470 0471 KateFileActions::prepareOpenWithMenu(doc->url(), menu); 0472 } 0473 0474 void KateFileTree::slotOpenWithMenuAction(QAction *a) 0475 { 0476 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_indexContextMenu); 0477 if (!doc) { 0478 return; 0479 } 0480 0481 KateFileActions::showOpenWithMenu(m_mainWindow->window(), doc->url(), a); 0482 } 0483 0484 void KateFileTree::slotDocumentClose() 0485 { 0486 m_previouslySelected = QModelIndex(); 0487 if (!m_indexContextMenu.isValid()) { 0488 return; 0489 } 0490 const auto closeColumnIndex = m_indexContextMenu.sibling(m_indexContextMenu.row(), 1); 0491 closeClicked(closeColumnIndex); 0492 } 0493 0494 void KateFileTree::addChildrenTolist(const QModelIndex &index, QList<QPersistentModelIndex> *worklist) 0495 { 0496 const int count = m_proxyModel->rowCount(index); 0497 worklist->reserve(worklist->size() + count); 0498 for (int i = 0; i < count; ++i) { 0499 worklist->append(m_proxyModel->index(i, 0, index)); 0500 } 0501 } 0502 0503 void KateFileTree::slotExpandRecursive() 0504 { 0505 if (!m_indexContextMenu.isValid()) { 0506 return; 0507 } 0508 0509 // Work list for DFS walk over sub tree 0510 QList<QPersistentModelIndex> worklist = {m_indexContextMenu}; 0511 0512 while (!worklist.isEmpty()) { 0513 QPersistentModelIndex index = worklist.takeLast(); 0514 0515 // Expand current item 0516 expand(index); 0517 0518 // Append all children of current item 0519 addChildrenTolist(index, &worklist); 0520 } 0521 } 0522 0523 void KateFileTree::slotCollapseRecursive() 0524 { 0525 if (!m_indexContextMenu.isValid()) { 0526 return; 0527 } 0528 0529 // Work list for DFS walk over sub tree 0530 QList<QPersistentModelIndex> worklist = {m_indexContextMenu}; 0531 0532 while (!worklist.isEmpty()) { 0533 QPersistentModelIndex index = worklist.takeLast(); 0534 0535 // Expand current item 0536 collapse(index); 0537 0538 // Prepend all children of current item 0539 addChildrenTolist(index, &worklist); 0540 } 0541 } 0542 0543 void KateFileTree::slotDocumentCloseOther() 0544 { 0545 QList<KTextEditor::Document *> closingDocuments = m_proxyModel->docTreeFromIndex(m_indexContextMenu.parent()); 0546 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_indexContextMenu); 0547 closingDocuments.removeOne(doc); 0548 closeDocs(closingDocuments); 0549 } 0550 0551 void KateFileTree::slotDocumentReload() 0552 { 0553 const QList<KTextEditor::Document *> docs = docTreeFromIndex(m_indexContextMenu); 0554 for (auto *doc : docs) { 0555 doc->documentReload(); 0556 } 0557 } 0558 0559 void KateFileTree::slotOpenContainingFolder() 0560 { 0561 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_indexContextMenu); 0562 0563 if (!doc) { 0564 return; 0565 } 0566 0567 KateFileActions::openContainingFolder(doc); 0568 } 0569 0570 void KateFileTree::slotCopyFilename() 0571 { 0572 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_indexContextMenu); 0573 0574 if (!doc) { 0575 return; 0576 } 0577 0578 KateFileActions::copyFilePathToClipboard(doc); 0579 } 0580 0581 void KateFileTree::slotRenameFile() 0582 { 0583 KateFileActions::renameDocumentFile(this, m_proxyModel->docFromIndex(m_indexContextMenu)); 0584 } 0585 0586 void KateFileTree::slotDocumentFirst() 0587 { 0588 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_proxyModel->index(0, 0)); 0589 if (doc) { 0590 Q_EMIT activateDocument(doc); 0591 } 0592 } 0593 0594 void KateFileTree::slotDocumentLast() 0595 { 0596 int count = m_proxyModel->rowCount(m_proxyModel->parent(currentIndex())); 0597 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_proxyModel->index(count - 1, 0)); 0598 if (doc) { 0599 Q_EMIT activateDocument(doc); 0600 } 0601 } 0602 0603 void KateFileTree::slotDocumentPrev() 0604 { 0605 QModelIndex current_index = currentIndex(); 0606 QModelIndex prev; 0607 0608 // scan up the tree skipping any dir nodes 0609 while (current_index.isValid()) { 0610 if (current_index.row() > 0) { 0611 current_index = m_proxyModel->sibling(current_index.row() - 1, current_index.column(), current_index); 0612 if (!current_index.isValid()) { 0613 break; 0614 } 0615 0616 if (m_proxyModel->isDir(current_index)) { 0617 // try and select the last child in this parent 0618 int children = m_proxyModel->rowCount(current_index); 0619 current_index = m_proxyModel->index(children - 1, 0, current_index); 0620 if (m_proxyModel->isDir(current_index)) { 0621 // since we're a dir, keep going 0622 while (m_proxyModel->isDir(current_index)) { 0623 children = m_proxyModel->rowCount(current_index); 0624 current_index = m_proxyModel->index(children - 1, 0, current_index); 0625 } 0626 0627 if (!m_proxyModel->isDir(current_index)) { 0628 prev = current_index; 0629 break; 0630 } 0631 0632 continue; 0633 } else { 0634 // we're the previous file, set prev 0635 prev = current_index; 0636 break; 0637 } 0638 } else { // found document item 0639 prev = current_index; 0640 break; 0641 } 0642 } else { 0643 // just select the parent, the logic above will handle the rest 0644 current_index = m_proxyModel->parent(current_index); 0645 if (!current_index.isValid()) { 0646 // paste the root node here, try and wrap around 0647 0648 int children = m_proxyModel->rowCount(current_index); 0649 QModelIndex last_index = m_proxyModel->index(children - 1, 0, current_index); 0650 if (!last_index.isValid()) { 0651 break; 0652 } 0653 0654 if (m_proxyModel->isDir(last_index)) { 0655 // last node is a dir, select last child row 0656 int last_children = m_proxyModel->rowCount(last_index); 0657 prev = m_proxyModel->index(last_children - 1, 0, last_index); 0658 // bug here? 0659 break; 0660 } else { 0661 // got last file node 0662 prev = last_index; 0663 break; 0664 } 0665 } 0666 } 0667 } 0668 0669 if (prev.isValid()) { 0670 if (auto *doc = m_proxyModel->docFromIndex(prev)) { 0671 Q_EMIT activateDocument(doc); 0672 } else if (auto *w = prev.data(KateFileTreeModel::WidgetRole).value<QWidget *>()) { 0673 Q_EMIT activateWidget(w); 0674 } 0675 } 0676 } 0677 0678 void KateFileTree::slotDocumentNext() 0679 { 0680 QModelIndex current_index = currentIndex(); 0681 int parent_row_count = m_proxyModel->rowCount(m_proxyModel->parent(current_index)); 0682 QModelIndex next; 0683 0684 // scan down the tree skipping any dir nodes 0685 while (current_index.isValid()) { 0686 if (current_index.row() < parent_row_count - 1) { 0687 current_index = m_proxyModel->sibling(current_index.row() + 1, current_index.column(), current_index); 0688 if (!current_index.isValid()) { 0689 break; 0690 } 0691 0692 if (m_proxyModel->isDir(current_index)) { 0693 // we have a dir node 0694 while (m_proxyModel->isDir(current_index)) { 0695 current_index = m_proxyModel->index(0, 0, current_index); 0696 } 0697 0698 parent_row_count = m_proxyModel->rowCount(m_proxyModel->parent(current_index)); 0699 0700 if (!m_proxyModel->isDir(current_index)) { 0701 next = current_index; 0702 break; 0703 } 0704 } else { // found document item 0705 next = current_index; 0706 break; 0707 } 0708 } else { 0709 // select the parent's next sibling 0710 QModelIndex parent_index = m_proxyModel->parent(current_index); 0711 int grandparent_row_count = m_proxyModel->rowCount(m_proxyModel->parent(parent_index)); 0712 0713 current_index = parent_index; 0714 parent_row_count = grandparent_row_count; 0715 0716 // at least if we're not past the last node 0717 if (!current_index.isValid()) { 0718 // paste the root node here, try and wrap around 0719 QModelIndex last_index = m_proxyModel->index(0, 0, QModelIndex()); 0720 if (!last_index.isValid()) { 0721 break; 0722 } 0723 0724 if (m_proxyModel->isDir(last_index)) { 0725 // last node is a dir, select first child row 0726 while (m_proxyModel->isDir(last_index)) { 0727 if (m_proxyModel->rowCount(last_index)) { 0728 // has children, select first 0729 last_index = m_proxyModel->index(0, 0, last_index); 0730 } 0731 } 0732 0733 next = last_index; 0734 break; 0735 } else { 0736 // got first file node 0737 next = last_index; 0738 break; 0739 } 0740 } 0741 } 0742 } 0743 0744 if (next.isValid()) { 0745 if (auto *doc = m_proxyModel->docFromIndex(next)) { 0746 Q_EMIT activateDocument(doc); 0747 } else if (auto *w = next.data(KateFileTreeModel::WidgetRole).value<QWidget *>()) { 0748 Q_EMIT activateWidget(w); 0749 } 0750 } 0751 } 0752 0753 void KateFileTree::slotPrintDocument() 0754 { 0755 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_indexContextMenu); 0756 0757 if (!doc) { 0758 return; 0759 } 0760 0761 doc->print(); 0762 } 0763 0764 void KateFileTree::slotPrintDocumentPreview() 0765 { 0766 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_indexContextMenu); 0767 0768 if (!doc) { 0769 return; 0770 } 0771 0772 doc->printPreview(); 0773 } 0774 0775 void KateFileTree::slotResetHistory() 0776 { 0777 m_sourceModel->resetHistory(); 0778 } 0779 0780 void KateFileTree::slotDocumentDelete() 0781 { 0782 KTextEditor::Document *doc = m_proxyModel->docFromIndex(m_indexContextMenu); 0783 KateFileActions::deleteDocumentFile(m_mainWindow->window(), doc); 0784 } 0785 0786 // END KateFileTree 0787 0788 #include "moc_katefiletree.cpp"