File indexing completed on 2024-04-21 04:58:08
0001 /* 0002 SPDX-FileCopyrightText: 2019 Raphael Rosch <kde-dev@insaner.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 /* 0008 0009 TODO: 0010 -sidepanel not triggering changes in session properly 0011 -"Configure sidebar" > "Add new" has no option to actually add anything there 0012 -places panel does not respond to view location changes 0013 -detect icon size for places panel 0014 -doubleclick on image (to open kuickview) causes sidebar to deselect 0015 0016 -"View mode" to "sidebar" causes crash and ruins session -- cannot undo 0017 0018 0019 BUGS: 0020 -(konq bug) sftp cannot save file being edited, because: "A file named sftp://hostname/path/to/file already exists." 0021 maybe: https://phabricator.kde.org/D23384 , or https://phabricator.kde.org/D15318 0022 -(konq bug) loading session from cmdline causes crash, but not when konq is loaded fresh 0023 0024 */ 0025 0026 0027 0028 #include "tree_module.h" 0029 #include <konq_events.h> 0030 0031 #include <KLocalizedString> 0032 #include <KPluginFactory> 0033 0034 #include <QAction> 0035 #include <QKeyEvent> 0036 0037 #include <QHeaderView> 0038 0039 0040 KonqSideBarTreeModule::KonqSideBarTreeModule(QWidget *parent, 0041 const KConfigGroup &configGroup) 0042 : KonqSidebarModule(parent, configGroup) 0043 { 0044 m_initURL = cleanupURL(QUrl(configGroup.readPathEntry("URL", QString()))); // because the .desktop file url might be "~" 0045 treeView = new QTreeView(parent); 0046 treeView->setHeaderHidden(true); 0047 treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); 0048 treeView->setTextElideMode(Qt::ElideMiddle); 0049 treeView->setDragEnabled(true); 0050 0051 model = new KDirModel(this); 0052 sorted_model = new KDirSortFilterProxyModel(this); 0053 sorted_model->setSortFoldersFirst(true); 0054 sorted_model->setSourceModel(model); 0055 model->dirLister()->setDirOnlyMode(true); 0056 model->dirLister()->setShowHiddenFiles(configGroup.readEntry("ShowHiddenFolders", false)); 0057 0058 model->openUrl(m_initURL, KDirModel::ShowRoot); 0059 0060 treeView->setModel(sorted_model); 0061 0062 for (int i = 1; i <= 6; i++) { 0063 treeView->setColumnHidden(i, true); 0064 } 0065 0066 connect(treeView, &QTreeView::expanded, 0067 this, &KonqSideBarTreeModule::slotUpdateColWidth); 0068 connect(treeView, &QTreeView::collapsed, 0069 this, &KonqSideBarTreeModule::slotUpdateColWidth); 0070 0071 model->expandToUrl(m_initURL); // KDirModel is async, we'll just have to wait for slotKDirCompleted() 0072 connect(model, &KDirModel::expand, 0073 this, &KonqSideBarTreeModule::slotKDirExpand_setRootIndex); 0074 0075 QItemSelectionModel *selectionModel = treeView->selectionModel(); 0076 connect(selectionModel, &QItemSelectionModel::selectionChanged, 0077 this, &KonqSideBarTreeModule::slotSelectionChanged); 0078 } 0079 0080 void KonqSideBarTreeModule::customEvent(QEvent *ev) // active view has changed 0081 { 0082 if (KParts::PartActivateEvent::test(ev)) { 0083 KParts::ReadOnlyPart* rpart = static_cast<KParts::ReadOnlyPart *>( static_cast<KParts::PartActivateEvent *>(ev)->part() ); 0084 if (!rpart->url().isEmpty()) { 0085 setSelection(rpart->url()); 0086 } 0087 } 0088 } 0089 0090 QUrl KonqSideBarTreeModule::cleanupURL(const QUrl &dirtyURL) 0091 { 0092 if (!dirtyURL.isValid()) { 0093 return dirtyURL; 0094 } 0095 QUrl url = dirtyURL; 0096 if (url.isRelative()) { 0097 url.setScheme("file"); 0098 if (url.path() == "~") { 0099 const QString homePath = QDir::homePath(); 0100 if (!homePath.endsWith("/")) { 0101 url.setPath(homePath + "/"); 0102 } else { 0103 url.setPath(homePath); 0104 } 0105 } 0106 } 0107 return url; 0108 } 0109 0110 KonqSideBarTreeModule::~KonqSideBarTreeModule() 0111 { 0112 } 0113 0114 QWidget *KonqSideBarTreeModule::getWidget() 0115 { 0116 return treeView; 0117 } 0118 0119 void KonqSideBarTreeModule::handleURL(const QUrl &url) 0120 { 0121 QUrl handleURL = url; 0122 0123 if (handleURL.scheme().isNull()) { 0124 setSelectionIndex(QModelIndex()); 0125 m_lastURL = QUrl(); 0126 return; 0127 } 0128 0129 m_lastURL = handleURL; 0130 setSelection(handleURL); 0131 } 0132 0133 void KonqSideBarTreeModule::setSelection(const QUrl &target_url, bool do_openURLreq) // do_openURLreq=true) 0134 { 0135 QModelIndex index = sorted_model->mapFromSource(model->indexForUrl(target_url)); 0136 0137 m_lastURL = target_url; 0138 0139 if (!index.isValid() && target_url.scheme() == m_initURL.scheme()) { 0140 if (do_openURLreq) { 0141 connect(model, &KDirModel::expand, 0142 this, &KonqSideBarTreeModule::slotKDirExpand_setSelection ); 0143 model->expandToUrl(target_url); // KDirModel is async, we'll just have to wait for slotKDirExpand_setSelection() 0144 } 0145 } 0146 0147 setSelectionIndex(index); 0148 } 0149 0150 void KonqSideBarTreeModule::setSelectionIndex(const QModelIndex &index) 0151 { 0152 if (index == treeView->selectionModel()->currentIndex()) { 0153 return; 0154 } 0155 treeView->expand(index); 0156 treeView->scrollTo(index); 0157 treeView->setCurrentIndex(index); 0158 } 0159 0160 void KonqSideBarTreeModule::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) 0161 { 0162 QModelIndex index = treeView->selectionModel()->currentIndex(); 0163 0164 QUrl urlFromIndex = getUrlFromIndex(index); 0165 if (index.isValid() && m_lastURL != urlFromIndex) { 0166 emit openUrlRequest(urlFromIndex); 0167 } 0168 slotUpdateColWidth(); 0169 } 0170 0171 // needed because when there is only one column, QTreeView does not trigger resize 0172 void KonqSideBarTreeModule::slotUpdateColWidth() 0173 { 0174 treeView->resizeColumnToContents(0); 0175 } 0176 0177 // needed because KDirModel is async 0178 void KonqSideBarTreeModule::slotKDirExpand_setRootIndex() 0179 { 0180 QModelIndex index = getIndexFromUrl(m_initURL); 0181 if (index.isValid()) { 0182 disconnect(model, &KDirModel::expand, 0183 this, &KonqSideBarTreeModule::slotKDirExpand_setRootIndex); 0184 treeView->setRootIndex(index.parent()); 0185 treeView->expand(index); 0186 } 0187 } 0188 0189 void KonqSideBarTreeModule::slotKDirExpand_setSelection(const QModelIndex &index) 0190 { 0191 QUrl urlFromIndex = getUrlFromIndex(index); // these are only going to be valid 0192 if (urlFromIndex == m_lastURL) { 0193 disconnect(model, &KDirModel::expand, 0194 this, &KonqSideBarTreeModule::slotKDirExpand_setSelection); 0195 setSelection(m_lastURL, false); 0196 } 0197 slotUpdateColWidth(); 0198 } 0199 0200 0201 // resolves index to the correct model (due to use of KDirSortFilterProxyModel) 0202 QModelIndex KonqSideBarTreeModule::resolveIndex(const QModelIndex &index) 0203 { 0204 if (index.isValid() && index.model() != model && model != nullptr) { 0205 return static_cast<const KDirSortFilterProxyModel*>(index.model())->mapToSource(index); 0206 } else { 0207 return index; 0208 } 0209 } 0210 0211 QUrl KonqSideBarTreeModule::getUrlFromIndex(const QModelIndex &index) 0212 { 0213 QUrl resolvedUrl; 0214 0215 if (index.isValid()) { 0216 KFileItem itemForIndex = model->itemForIndex(resolveIndex(index)); 0217 if (!itemForIndex.isNull()) { 0218 resolvedUrl = itemForIndex.url(); 0219 } 0220 } 0221 0222 return resolvedUrl; 0223 } 0224 0225 QModelIndex KonqSideBarTreeModule::getIndexFromUrl(const QUrl &url) const 0226 { 0227 return sorted_model->mapFromSource(model->indexForUrl(url)); 0228 } 0229 0230 0231 class KonqSidebarTreePlugin : public KonqSidebarPlugin 0232 { 0233 public: 0234 KonqSidebarTreePlugin(QObject *parent, const QVariantList &args) 0235 : KonqSidebarPlugin(parent, args) {} 0236 ~KonqSidebarTreePlugin() override {} 0237 0238 KonqSidebarModule *createModule(QWidget *parent, 0239 const KConfigGroup &configGroup, 0240 const QString &desktopname, 0241 const QVariant &unused) override 0242 { 0243 Q_UNUSED(desktopname); 0244 Q_UNUSED(unused); 0245 0246 return new KonqSideBarTreeModule(parent, configGroup); 0247 } 0248 0249 QList<QAction *> addNewActions(QObject *parent, 0250 const QList<KConfigGroup> &existingModules, 0251 const QVariant &unused) override 0252 { 0253 Q_UNUSED(existingModules); 0254 Q_UNUSED(unused); 0255 QAction *action = new QAction(parent); 0256 action->setText(i18nc("@action:inmenu Add", "Tree Sidebar Module")); 0257 action->setIcon(QIcon::fromTheme("folder-favorites")); 0258 return QList<QAction *>() << action; 0259 } 0260 0261 QString templateNameForNewModule(const QVariant &actionData, 0262 const QVariant &unused) const override 0263 { 0264 Q_UNUSED(actionData); 0265 Q_UNUSED(unused); 0266 return QString::fromLatin1("treesidebarplugin%1.desktop"); 0267 } 0268 0269 bool createNewModule(const QVariant &actionData, 0270 KConfigGroup &configGroup, 0271 QWidget *parentWidget, 0272 const QVariant &unused) override 0273 { 0274 Q_UNUSED(actionData); 0275 Q_UNUSED(parentWidget); 0276 Q_UNUSED(unused); 0277 configGroup.writeEntry("Type", "Link"); 0278 configGroup.writeEntry("Icon", "folder-favorites"); 0279 configGroup.writeEntry("Name", i18nc("@title:tab", "Tree")); 0280 configGroup.writeEntry("X-KDE-KonqSidebarModule", "konqsidebar_tree"); 0281 return true; 0282 } 0283 }; 0284 0285 K_PLUGIN_FACTORY_WITH_JSON(KonqSidebarTreePluginFactory, "konqsidebar_tree.json", registerPlugin<KonqSidebarTreePlugin>();) 0286 // K_EXPORT_PLUGIN(KonqSidebarTreePluginFactory()) 0287 0288 #include "tree_module.moc"