File indexing completed on 2024-04-21 04:58:11
0001 /* 0002 SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org> 0003 SPDX-FileCopyrightText: 2009 David Faure <faure@kde.org> 0004 SPDX-FileCopyrightText: 2019 Raphael Rosch <kde-dev@insaner.com> 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 // Own 0009 #include "sidebar_widget.h" 0010 #include "konqmultitabbar.h" 0011 #include "sidebar_debug.h" 0012 0013 // std 0014 #include <limits.h> 0015 0016 // Qt 0017 #include <QDir> 0018 #include <QPushButton> 0019 #include <QSplitter> 0020 #include <QStringList> 0021 #include <QMenu> 0022 #include <QMouseEvent> 0023 #include <QApplication> 0024 #include <QInputDialog> 0025 #include <QIcon> 0026 #include <QHBoxLayout> 0027 #include <QStandardPaths> 0028 0029 // KDE 0030 #include <KLocalizedString> 0031 #include <kconfig.h> 0032 0033 #include <kdesktopfile.h> 0034 #include <kicondialog.h> 0035 #include <kmessagebox.h> 0036 #include <konq_events.h> 0037 #include <kfileitem.h> 0038 #include <kurlrequesterdialog.h> 0039 #include <KUrlRequester> 0040 #include <KJobUiDelegate> 0041 #include <KJobWidgets> 0042 #include <KPluginFactory> 0043 #include <KIO/StatJob> 0044 0045 void Sidebar_Widget::aboutToShowAddMenu() 0046 { 0047 m_addMenu->clear(); 0048 m_pluginForAction.clear(); 0049 0050 QList<KConfigGroup> existingGroups; 0051 // Collect the "already shown" modules 0052 for (int i = 0; i < m_buttons.count(); ++i) { 0053 existingGroups.append(m_buttons[i].configFile->group("Desktop Entry")); 0054 } 0055 0056 //TODO KF6: remove version check and replace with code using json 0057 // We need to instantiate all available plugins 0058 // And since the web module isn't in the default entries at all, we can't just collect 0059 // the plugins there. 0060 const QVector<KPluginMetaData> plugins = m_moduleManager.availablePlugins(); 0061 for (const KPluginMetaData &service : plugins) { 0062 if (!service.isValid()) { 0063 continue; 0064 } 0065 auto pluginResult = KPluginFactory::instantiatePlugin<KonqSidebarPlugin>(service, this); 0066 if (pluginResult) { 0067 KonqSidebarPlugin *plugin = pluginResult.plugin; 0068 const QList<QAction *> actions = plugin->addNewActions(&m_addMenuActionGroup, 0069 existingGroups, 0070 QVariant()); 0071 // Remember which plugin the action came from. 0072 // We can't use QAction::setData for that, because we let plugins use 0073 // that already. 0074 for (QAction *action: actions) { 0075 m_pluginForAction.insert(action, plugin); 0076 } 0077 m_addMenu->addActions(actions); 0078 } else { 0079 qCWarning(SIDEBAR_LOG) << "Error loading plugin" << pluginResult.errorText; 0080 } 0081 } 0082 m_addMenu->addSeparator(); 0083 m_addMenu->addAction(KStandardGuiItem::defaults().icon(), i18n("Restore All Removed Default Buttons"), this, &Sidebar_Widget::slotRestoreDeletedButtons); 0084 m_addMenu->addAction(KStandardGuiItem::defaults().icon(), i18n("Rollback to System Default"), this, &Sidebar_Widget::slotRollback); 0085 } 0086 0087 void Sidebar_Widget::triggeredAddMenu(QAction *action) 0088 { 0089 KonqSidebarPlugin *plugin = m_pluginForAction.value(action); 0090 m_pluginForAction.clear(); // save memory 0091 0092 QString templ = plugin->templateNameForNewModule(action->data(), QVariant()); 0093 Q_ASSERT(!templ.contains('/')); 0094 if (templ.isEmpty()) { 0095 return; 0096 } 0097 const QString myFile = m_moduleManager.addModuleFromTemplate(templ); 0098 if (myFile.isEmpty()) { 0099 return; 0100 } 0101 0102 qCDebug(SIDEBAR_LOG) << myFile << "filename=" << templ; 0103 KDesktopFile df(myFile); 0104 KConfigGroup configGroup = df.desktopGroup(); 0105 configGroup.writeEntry("X-KDE-Weight", m_moduleManager.getNextAvailableKDEWeight()); 0106 const bool ok = plugin->createNewModule(action->data(), configGroup, this, QVariant()); 0107 df.sync(); 0108 if (ok) { 0109 m_moduleManager.moduleAdded(templ /*contains the final filename*/); 0110 // TODO only add the new button 0111 QTimer::singleShot(0, this, &Sidebar_Widget::updateButtons); 0112 } else { 0113 QFile::remove(myFile); 0114 } 0115 } 0116 0117 Sidebar_Widget::Sidebar_Widget(QWidget *parent, KParts::ReadOnlyPart *par, const QString ¤tProfile) 0118 : QWidget(parent), 0119 m_partParent(par), 0120 m_addMenuActionGroup(this), 0121 m_config(new KConfigGroup(KSharedConfig::openConfig("konqsidebartngrc"), 0122 currentProfile)), 0123 m_moduleManager(m_config) 0124 { 0125 m_somethingVisible = false; 0126 m_noUpdate = false; 0127 m_layout = nullptr; 0128 m_currentButtonIndex = -1; 0129 m_activeModule = nullptr; 0130 //m_userMovedSplitter = false; 0131 m_latestViewed = -1; 0132 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); 0133 0134 m_area = new QSplitter(Qt::Vertical, this); 0135 m_area->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); 0136 m_area->setMinimumWidth(0); 0137 0138 m_buttonBar = new KonqMultiTabBar(this); 0139 connect(m_buttonBar, &KonqMultiTabBar::urlsDropped, this, &Sidebar_Widget::slotUrlsDropped); 0140 0141 m_menu = new QMenu(this); 0142 m_menu->setIcon(QIcon::fromTheme("configure")); 0143 m_menu->setTitle(i18n("Configure Sidebar")); 0144 0145 m_addMenu = m_menu->addMenu(KStandardGuiItem::add().icon(), i18n("Add New")); 0146 connect(m_addMenu, &QMenu::aboutToShow, this, &Sidebar_Widget::aboutToShowAddMenu); 0147 connect(&m_addMenuActionGroup, &QActionGroup::triggered, this, &Sidebar_Widget::triggeredAddMenu); 0148 m_menu->addSeparator(); 0149 m_multiViews = m_menu->addAction(i18n("Multiple Views"), this, &Sidebar_Widget::slotMultipleViews); 0150 m_multiViews->setCheckable(true); 0151 m_showTabLeft = m_menu->addAction(i18n("Show Tabs on Left"), this, &Sidebar_Widget::slotShowTabsLeft); 0152 m_showConfigButton = m_menu->addAction(i18n("Show Configuration Button"), this, &Sidebar_Widget::slotShowConfigurationButton); 0153 m_showConfigButton->setCheckable(true); 0154 m_menu->addSeparator(); 0155 m_menu->addAction(KStandardGuiItem::close().icon(), i18n("Close Sidebar"), par, &QObject::deleteLater); 0156 0157 connect(m_menu, &QMenu::aboutToShow, this, &Sidebar_Widget::aboutToShowConfigMenu); 0158 0159 m_configTimer.setSingleShot(true); 0160 connect(&m_configTimer, &QTimer::timeout, this, &Sidebar_Widget::saveConfig); 0161 readConfig(); 0162 m_openViews = m_config->readEntry("OpenViews", QStringList()); 0163 m_savedWidth = m_config->readEntry("SavedWidth", 200); 0164 m_somethingVisible = !m_openViews.isEmpty(); 0165 doLayout(); 0166 QTimer::singleShot(0, this, &Sidebar_Widget::createButtons); 0167 } 0168 0169 bool Sidebar_Widget::createDirectModule(const QString &templ, 0170 const QString &name, 0171 const QUrl &url, 0172 const QString &icon, 0173 const QString &module, 0174 const QString &treeModule) 0175 { 0176 QString filename = templ; 0177 const QString myFile = m_moduleManager.addModuleFromTemplate(filename); 0178 if (!myFile.isEmpty()) { 0179 qCDebug(SIDEBAR_LOG) << "Writing" << myFile; 0180 KDesktopFile df(myFile); 0181 KConfigGroup scf = df.desktopGroup(); 0182 scf.writeEntry("Type", "Link"); 0183 scf.writePathEntry("URL", url.url()); 0184 scf.writeEntry("Icon", icon); 0185 scf.writeEntry("Name", name); 0186 scf.writeEntry("X-KDE-KonqSidebarModule", module); 0187 if (!treeModule.isEmpty()) { 0188 scf.writeEntry("X-KDE-TreeModule", treeModule); 0189 } 0190 int maxKDEWeight = m_moduleManager.getNextAvailableKDEWeight(); 0191 scf.writeEntry("X-KDE-Weight", maxKDEWeight); // because modules with same weight as an already displayed module are inaccessible. 0192 scf.sync(); 0193 m_moduleManager.moduleAdded(filename); 0194 QTimer::singleShot(0, this, &Sidebar_Widget::updateButtons); 0195 return true; 0196 } 0197 return false; 0198 } 0199 0200 void Sidebar_Widget::addWebSideBar(const QUrl &url, const QString &name) 0201 { 0202 //qCDebug(SIDEBAR_LOG) << "Web sidebar entry to be added: " << url << name << endl; 0203 0204 // Look for existing ones with this URL 0205 const QStringList files = m_moduleManager.localModulePaths("websidebarplugin*.desktop"); 0206 for (const QString &file: files) { 0207 KConfig _scf(file, KConfig::SimpleConfig); 0208 KConfigGroup scf(&_scf, "Desktop Entry"); 0209 if (scf.readPathEntry("URL", QString()) == url.url()) { 0210 KMessageBox::information(this, i18n("This entry already exists.")); 0211 return; 0212 } 0213 } 0214 0215 createDirectModule("websidebarplugin%1.desktop", name, url, "internet-web-browser", "konqsidebar_web"); 0216 } 0217 0218 void Sidebar_Widget::slotRestoreDeletedButtons() 0219 { 0220 m_moduleManager.restoreDeletedButtons(); 0221 QTimer::singleShot(0, this, &Sidebar_Widget::updateButtons); 0222 } 0223 0224 void Sidebar_Widget::slotRollback() 0225 { 0226 if (KMessageBox::warningContinueCancel(this, i18n("<qt>This removes all your entries from the sidebar and adds the system default ones.<br /><b>This procedure is irreversible.</b><br />Do you want to proceed?</qt>")) == KMessageBox::Continue) { 0227 m_moduleManager.rollbackToDefault(); 0228 QTimer::singleShot(0, this, &Sidebar_Widget::updateButtons); 0229 } 0230 } 0231 0232 void Sidebar_Widget::saveConfig() 0233 { 0234 m_config->writeEntry("SingleWidgetMode", m_singleWidgetMode); 0235 m_config->writeEntry("ShowExtraButtons", m_showExtraButtons); 0236 m_config->writeEntry("ShowTabsLeft", m_showTabsLeft); 0237 m_config->writeEntry("HideTabs", m_hideTabs); 0238 m_config->writeEntry("SavedWidth", m_savedWidth); 0239 m_config->sync(); 0240 } 0241 0242 void Sidebar_Widget::doLayout() 0243 { 0244 delete m_layout; 0245 m_layout = new QHBoxLayout(this); 0246 m_layout->setContentsMargins(0, 0, 0, 0); 0247 m_layout->setSpacing(0); 0248 if (m_showTabsLeft) { 0249 m_layout->addWidget(m_buttonBar); 0250 m_layout->addWidget(m_area); 0251 m_buttonBar->setPosition(KMultiTabBar::Left); 0252 } else { 0253 m_layout->addWidget(m_area); 0254 m_layout->addWidget(m_buttonBar); 0255 m_buttonBar->setPosition(KMultiTabBar::Right); 0256 } 0257 m_layout->activate(); 0258 if (m_hideTabs) { 0259 m_buttonBar->hide(); 0260 } else { 0261 m_buttonBar->show(); 0262 } 0263 } 0264 0265 void Sidebar_Widget::aboutToShowConfigMenu() 0266 { 0267 m_multiViews->setChecked(!m_singleWidgetMode); 0268 m_showTabLeft->setText(m_showTabsLeft ? i18n("Show Tabs on Right") : i18n("Show Tabs on Left")); 0269 m_showConfigButton->setChecked(m_showExtraButtons); 0270 } 0271 0272 void Sidebar_Widget::slotSetName() 0273 { 0274 // Set a name for this sidebar tab 0275 bool ok; 0276 0277 // Pop up the dialog asking the user for name. 0278 const QString name = QInputDialog::getText(this, 0279 i18nc("@title:window", "Set Name"), 0280 i18n("Enter the name:"), 0281 QLineEdit::Normal, 0282 currentButtonInfo().displayName, 0283 &ok); 0284 if (ok) { 0285 m_moduleManager.setModuleName(currentButtonInfo().file, name); 0286 0287 // Update the buttons with a QTimer (why?) 0288 // Because we're in the RMB of a button that updateButtons deletes... 0289 // TODO: update THAT button only. 0290 QTimer::singleShot(0, this, &Sidebar_Widget::updateButtons); 0291 } 0292 } 0293 0294 // TODO make this less generic. Bookmarks and history have no URL, only folders and websidebars do. 0295 // So this should move to the modules that need it. 0296 void Sidebar_Widget::slotSetURL() 0297 { 0298 KUrlRequesterDialog dlg(currentButtonInfo().initURL, i18n("Enter a URL:"), this); 0299 dlg.urlRequester()->setMode(KFile::Directory); 0300 if (dlg.exec()) { 0301 m_moduleManager.setModuleUrl(currentButtonInfo().file, dlg.selectedUrl()); 0302 // TODO: update THAT button only. 0303 QTimer::singleShot(0, this, &Sidebar_Widget::updateButtons); 0304 } 0305 } 0306 0307 void Sidebar_Widget::slotSetIcon() 0308 { 0309 // kicd.setStrictIconSize(true); 0310 const QString iconname = KIconDialog::getIcon(KIconLoader::Small); 0311 if (!iconname.isEmpty()) { 0312 m_moduleManager.setModuleIcon(currentButtonInfo().file, iconname); 0313 // TODO: update THAT button only. 0314 QTimer::singleShot(0, this, &Sidebar_Widget::updateButtons); 0315 } 0316 } 0317 0318 void Sidebar_Widget::slotRemove() 0319 { 0320 if (KMessageBox::warningContinueCancel(this, i18n("<qt>Do you really want to remove the <b>%1</b> tab?</qt>", currentButtonInfo().displayName), 0321 QString(), KStandardGuiItem::del()) == KMessageBox::Continue) { 0322 m_moduleManager.removeModule(currentButtonInfo().file); 0323 QTimer::singleShot(0, this, &Sidebar_Widget::updateButtons); 0324 } 0325 } 0326 0327 void Sidebar_Widget::slotToggleShowHiddenFolders() 0328 { 0329 Q_ASSERT(currentButtonInfo().canToggleShowHiddenFolders); 0330 bool newToggleState = !currentButtonInfo().showHiddenFolders; 0331 m_moduleManager.setShowHiddenFolders(currentButtonInfo().file, newToggleState); 0332 // TODO: update THAT button only. 0333 QTimer::singleShot(0, this, SLOT(updateButtons())); 0334 } 0335 0336 void Sidebar_Widget::slotMultipleViews() 0337 { 0338 m_singleWidgetMode = !m_singleWidgetMode; 0339 if ((m_singleWidgetMode) && (m_visibleViews.count() > 1)) { 0340 int tmpViewID = m_latestViewed; 0341 for (int i = 0; i < m_buttons.count(); i++) { 0342 if (i != tmpViewID) { 0343 const ButtonInfo &button = m_buttons.at(i); 0344 if (button.dock && button.dock->isVisibleTo(this)) { 0345 showHidePage(i); 0346 } 0347 } 0348 } 0349 m_latestViewed = tmpViewID; 0350 } 0351 m_configTimer.start(400); 0352 } 0353 0354 void Sidebar_Widget::slotShowTabsLeft() 0355 { 0356 m_showTabsLeft = ! m_showTabsLeft; 0357 doLayout(); 0358 m_configTimer.start(400); 0359 } 0360 0361 void Sidebar_Widget::slotShowConfigurationButton() 0362 { 0363 m_showExtraButtons = ! m_showExtraButtons; 0364 if (m_showExtraButtons) { 0365 m_buttonBar->button(-1)->show(); 0366 } else { 0367 m_buttonBar->button(-1)->hide(); 0368 0369 KMessageBox::information(this, 0370 i18n("You have hidden the sidebar configuration button. To make it visible again, click the right mouse button on any of the sidebar buttons and select \"Show Configuration Button\".")); 0371 0372 } 0373 m_configTimer.start(400); 0374 } 0375 0376 void Sidebar_Widget::readConfig() 0377 { 0378 m_singleWidgetMode = m_config->readEntry("SingleWidgetMode", true); 0379 m_showExtraButtons = m_config->readEntry("ShowExtraButtons", false); 0380 m_showTabsLeft = m_config->readEntry("ShowTabsLeft", true); 0381 m_hideTabs = m_config->readEntry("HideTabs", false); 0382 } 0383 0384 void Sidebar_Widget::stdAction(const char *handlestd) 0385 { 0386 // ### problem: what about multi mode? We could have multiple modules shown, 0387 // and if we use Edit/Copy, which one should be used? Need to care about focus... 0388 qCDebug(SIDEBAR_LOG) << handlestd << "m_activeModule=" << m_activeModule; 0389 if (m_activeModule) { 0390 QMetaObject::invokeMethod(m_activeModule, handlestd); 0391 } 0392 } 0393 0394 void Sidebar_Widget::updateButtons() 0395 { 0396 //PARSE ALL DESKTOP FILES 0397 m_openViews = m_visibleViews; 0398 0399 for (int i = 0; i < m_buttons.count(); ++i) { 0400 const ButtonInfo &button = m_buttons.at(i); 0401 if (button.dock) { 0402 m_noUpdate = true; 0403 if (button.dock->isVisibleTo(this)) { 0404 showHidePage(i); 0405 } 0406 delete button.module; 0407 delete button.dock; 0408 } 0409 m_buttonBar->removeTab(i); 0410 } 0411 m_buttons.clear(); 0412 0413 readConfig(); 0414 doLayout(); 0415 createButtons(); 0416 } 0417 0418 void Sidebar_Widget::createButtons() 0419 { 0420 const QStringList modules = m_moduleManager.modules(); 0421 for (const QString &fileName: modules) { 0422 addButton(fileName); 0423 } 0424 0425 if (!m_buttonBar->button(-1)) { 0426 m_buttonBar->appendButton(QIcon::fromTheme("configure"), -1, m_menu, 0427 i18n("Configure Sidebar")); 0428 } 0429 0430 if (m_showExtraButtons) { 0431 m_buttonBar->button(-1)->show(); 0432 } else { 0433 m_buttonBar->button(-1)->hide(); 0434 } 0435 0436 for (int i = 0; i < m_buttons.count(); i++) { 0437 const ButtonInfo &button = m_buttons.at(i); 0438 if (m_openViews.contains(button.file)) { 0439 m_buttonBar->setTab(i, true); 0440 m_noUpdate = true; 0441 showHidePage(i); 0442 if (m_singleWidgetMode) { 0443 break; 0444 } 0445 } 0446 } 0447 0448 collapseExpandSidebar(); 0449 m_noUpdate = false; 0450 } 0451 0452 bool Sidebar_Widget::openUrl(const QUrl &url) 0453 { 0454 if (url.scheme() == "sidebar") { 0455 for (int i = 0; i < m_buttons.count(); i++) 0456 if (m_buttons.at(i).file == url.path()) { 0457 KMultiTabBarTab *tab = m_buttonBar->tab(i); 0458 if (!tab->isChecked()) { 0459 tab->animateClick(); 0460 } 0461 return true; 0462 } 0463 return false; 0464 } 0465 0466 bool ret = false; 0467 if (m_buttons.isEmpty()) { // special case, since KonqMainWindow uses openURL to launch sidebar before buttons exist 0468 m_urlBeforeInstanceFlag = true; 0469 } 0470 setStoredCurViewUrl(cleanupURL(url)); 0471 m_origURL = m_storedCurViewUrl; 0472 0473 for (int i = 0; i < m_buttons.count(); i++) { 0474 const ButtonInfo &button = m_buttons.at(i); 0475 if (button.dock) { 0476 if ((button.dock->isVisibleTo(this)) && (button.module)) { 0477 ret = true; 0478 button.module->openUrl(url); 0479 } 0480 } 0481 } 0482 return ret; 0483 } 0484 0485 void Sidebar_Widget::setStoredCurViewUrl(const QUrl& url) 0486 { 0487 m_storedCurViewUrl = url; 0488 emit curViewUrlChanged(url); 0489 } 0490 0491 QUrl Sidebar_Widget::cleanupURL(const QString &dirtyURL) 0492 { 0493 return cleanupURL(QUrl(dirtyURL)); 0494 } 0495 0496 QUrl Sidebar_Widget::cleanupURL(const QUrl &dirtyURL) 0497 { 0498 if (!dirtyURL.isValid()) { 0499 return dirtyURL; 0500 } 0501 QUrl url = dirtyURL; 0502 if (url.isRelative()) { 0503 url.setScheme("file"); 0504 if (url.path() == "~") { 0505 url.setPath(QDir::homePath()); 0506 } 0507 } 0508 return url; 0509 } 0510 0511 bool Sidebar_Widget::addButton(const QString &desktopFileName, int pos) 0512 { 0513 int lastbtn = m_buttons.count(); 0514 0515 qCDebug(SIDEBAR_LOG) << "addButton:" << desktopFileName; 0516 0517 const QString moduleDataPath = m_moduleManager.moduleDataPath(desktopFileName); 0518 // Check the desktop file still exists 0519 if (QStandardPaths::locate(QStandardPaths::GenericDataLocation, moduleDataPath).isEmpty()) { 0520 return false; 0521 } 0522 0523 KSharedConfig::Ptr config = KSharedConfig::openConfig(moduleDataPath, 0524 KConfig::NoGlobals, 0525 QStandardPaths::GenericDataLocation); 0526 KConfigGroup configGroup(config, "Desktop Entry"); 0527 const QString icon = configGroup.readEntry("Icon", QString()); 0528 const QString name = configGroup.readEntry("Name", QString()); 0529 const QString comment = configGroup.readEntry("Comment", QString()); 0530 const QUrl url(configGroup.readPathEntry("URL", QString())); 0531 const QString lib = configGroup.readEntry("X-KDE-KonqSidebarModule"); 0532 const QString configOpenStr = configGroup.readEntry("Open", QString()); // NOTE: is this redundant? 0533 0534 if (pos == -1) { // TODO handle insertion 0535 m_buttonBar->appendTab(QIcon::fromTheme(icon), lastbtn, name); 0536 ButtonInfo buttonInfo(config, desktopFileName, cleanupURL(url), lib, name, icon); 0537 buttonInfo.configOpen = configGroup.readEntry("Open", false); 0538 buttonInfo.canToggleShowHiddenFolders = (configGroup.readEntry("X-KDE-KonqSidebarModule", QString()) == "konqsidebar_tree"); 0539 buttonInfo.showHiddenFolders = configGroup.readEntry("ShowHiddenFolders", false); 0540 m_buttons.insert(lastbtn, buttonInfo); 0541 KMultiTabBarTab *tab = m_buttonBar->tab(lastbtn); 0542 tab->installEventFilter(this); 0543 connect(tab, &KMultiTabBarTab::clicked, this, &Sidebar_Widget::showHidePage); 0544 0545 // Set Whats This help 0546 // This uses the comments in the .desktop files 0547 tab->setWhatsThis(comment); 0548 } 0549 0550 return true; 0551 } 0552 0553 bool Sidebar_Widget::eventFilter(QObject *obj, QEvent *ev) 0554 { 0555 if (ev->type() == QEvent::MouseButtonPress && ((QMouseEvent *)ev)->button() == Qt::RightButton) { 0556 KMultiTabBarTab *bt = dynamic_cast<KMultiTabBarTab *>(obj); 0557 if (bt) { 0558 qCDebug(SIDEBAR_LOG) << "Request for popup"; 0559 m_currentButtonIndex = -1; 0560 for (int i = 0; i < m_buttons.count(); i++) { 0561 if (bt == m_buttonBar->tab(i)) { 0562 m_currentButtonIndex = i; 0563 break; 0564 } 0565 } 0566 0567 if (m_currentButtonIndex > -1) { 0568 QMenu *buttonPopup = new QMenu(this); 0569 buttonPopup->setTitle(currentButtonInfo().displayName); 0570 buttonPopup->setIcon(QIcon::fromTheme(currentButtonInfo().iconName)); 0571 buttonPopup->addAction(QIcon::fromTheme("edit-rename"), i18n("Set Name..."), this, &Sidebar_Widget::slotSetName); // Item to open a dialog to change the name of the sidebar item (by Pupeno) 0572 buttonPopup->addAction(QIcon::fromTheme("internet-web-browser"), i18n("Set URL..."), this, &Sidebar_Widget::slotSetURL); 0573 buttonPopup->addAction(QIcon::fromTheme("preferences-desktop-icons"), i18n("Set Icon..."), this, &Sidebar_Widget::slotSetIcon); 0574 if (currentButtonInfo().canToggleShowHiddenFolders) { 0575 QAction *toggleShowHiddenFolders = buttonPopup->addAction(i18n("Show Hidden Folders..."), this, &Sidebar_Widget::slotToggleShowHiddenFolders); 0576 toggleShowHiddenFolders->setCheckable(true); 0577 toggleShowHiddenFolders->setChecked(currentButtonInfo().showHiddenFolders); 0578 } 0579 buttonPopup->addSeparator(); 0580 buttonPopup->addAction(QIcon::fromTheme("edit-delete"), i18n("Remove"), this, &Sidebar_Widget::slotRemove); 0581 buttonPopup->addSeparator(); 0582 buttonPopup->addMenu(m_menu); 0583 buttonPopup->exec(QCursor::pos()); 0584 delete buttonPopup; 0585 } 0586 return true; 0587 } 0588 } 0589 return false; 0590 } 0591 0592 void Sidebar_Widget::mousePressEvent(QMouseEvent *ev) 0593 { 0594 // TODO move to contextMenuEvent? 0595 if (ev->type() == QEvent::MouseButtonPress && ev->button() == Qt::RightButton) { 0596 m_menu->exec(QCursor::pos()); 0597 } 0598 } 0599 0600 KonqSidebarModule *Sidebar_Widget::loadModule(QWidget *parent, const QString &desktopName, 0601 ButtonInfo &buttonInfo, const KSharedConfig::Ptr &config) 0602 { 0603 const KConfigGroup configGroup = config->group("Desktop Entry"); 0604 KonqSidebarPlugin *plugin = buttonInfo.plugin(this); 0605 if (!plugin) { 0606 return nullptr; 0607 } 0608 0609 return plugin->createModule(parent, configGroup, desktopName, QVariant()); 0610 } 0611 0612 KParts::NavigationExtension *Sidebar_Widget::getExtension() 0613 { 0614 return KParts::NavigationExtension::childObject(m_partParent); 0615 } 0616 0617 bool Sidebar_Widget::createView(ButtonInfo &buttonInfo) 0618 { 0619 buttonInfo.dock = nullptr; 0620 buttonInfo.module = loadModule(m_area, buttonInfo.file, buttonInfo, buttonInfo.configFile); 0621 0622 if (buttonInfo.module == nullptr) { 0623 return false; 0624 } 0625 0626 buttonInfo.dock = buttonInfo.module->getWidget(); 0627 connectModule(buttonInfo.module); 0628 connect(this, &Sidebar_Widget::fileSelection, buttonInfo.module, &KonqSidebarModule::openPreview); 0629 connect(this, &Sidebar_Widget::fileMouseOver, buttonInfo.module, &KonqSidebarModule::openPreviewOnMouseOver); 0630 connect(this, &Sidebar_Widget::curViewUrlChanged, buttonInfo.module, &KonqSidebarModule::slotCurViewUrlChanged); 0631 0632 return true; 0633 } 0634 0635 void Sidebar_Widget::showHidePage(int page) 0636 { 0637 Q_ASSERT(page >= 0); 0638 Q_ASSERT(page < m_buttons.count()); 0639 ButtonInfo &buttonInfo = m_buttons[page]; 0640 0641 auto buttonInfoHandleURL = [&] () { 0642 buttonInfo.dock->show(); 0643 m_area->show(); 0644 openUrl(m_storedCurViewUrl); // also runs the buttonInfo.module->openUrl() 0645 m_visibleViews << buttonInfo.file; 0646 m_latestViewed = page; 0647 m_moduleManager.saveOpenViews(m_visibleViews); // TODO: this would be best stored per-window, in the session file 0648 }; 0649 0650 if (!buttonInfo.dock) { 0651 if (m_buttonBar->isTabRaised(page)) { 0652 //SingleWidgetMode 0653 if (m_singleWidgetMode) { 0654 if (m_latestViewed != -1) { 0655 m_noUpdate = true; 0656 showHidePage(m_latestViewed); 0657 } 0658 } 0659 0660 if (!createView(buttonInfo)) { 0661 m_buttonBar->setTab(page, false); 0662 return; 0663 } 0664 0665 m_buttonBar->setTab(page, true); 0666 0667 connect(buttonInfo.module, &KonqSidebarModule::setIcon, 0668 [this,page](const QString &iconName) 0669 { m_buttonBar->tab(page)->setIcon(QIcon::fromTheme(iconName)); }); 0670 connect(buttonInfo.module, &KonqSidebarModule::setCaption, 0671 m_buttonBar->tab(page), &KMultiTabBarTab::setText); 0672 0673 m_area->addWidget(buttonInfo.dock); 0674 buttonInfoHandleURL(); 0675 } 0676 } else { 0677 if ((!buttonInfo.dock->isVisibleTo(this)) && (m_buttonBar->isTabRaised(page))) { 0678 //SingleWidgetMode 0679 if (m_singleWidgetMode) { 0680 if (m_latestViewed != -1) { 0681 m_noUpdate = true; 0682 showHidePage(m_latestViewed); 0683 } 0684 } 0685 buttonInfoHandleURL(); 0686 m_buttonBar->setTab(page, true); 0687 } else { 0688 m_buttonBar->setTab(page, false); 0689 buttonInfo.dock->hide(); 0690 m_latestViewed = -1; 0691 m_visibleViews.removeAll(buttonInfo.file); 0692 if (m_visibleViews.empty()) { 0693 m_area->hide(); 0694 } 0695 } 0696 } 0697 0698 if (!m_noUpdate) { 0699 collapseExpandSidebar(); 0700 } 0701 m_noUpdate = false; 0702 } 0703 0704 void Sidebar_Widget::collapseExpandSidebar() 0705 { 0706 if (!parentWidget()) { 0707 return; // Can happen during destruction 0708 } 0709 0710 if (m_visibleViews.count() == 0) { 0711 m_somethingVisible = false; 0712 parentWidget()->setMaximumWidth(minimumSizeHint().width()); 0713 updateGeometry(); 0714 emit panelHasBeenExpanded(false); 0715 } else { 0716 m_somethingVisible = true; 0717 parentWidget()->setMaximumWidth(32767); 0718 updateGeometry(); 0719 emit panelHasBeenExpanded(true); 0720 } 0721 } 0722 0723 QSize Sidebar_Widget::sizeHint() const 0724 { 0725 if (m_somethingVisible) { 0726 return QSize(m_savedWidth, 200); 0727 } 0728 return minimumSizeHint(); 0729 } 0730 0731 void Sidebar_Widget::submitFormRequest(const char *action, 0732 const QString &url, 0733 const QByteArray &formData, 0734 const QString & /*target*/, 0735 const QString &contentType, 0736 const QString & /*boundary*/) 0737 { 0738 KParts::OpenUrlArguments arguments; 0739 BrowserArguments browserArguments; 0740 browserArguments.setContentType("Content-Type: " + contentType); 0741 browserArguments.postData = formData; 0742 browserArguments.setDoPost(QByteArray(action).toLower() == "post"); 0743 // boundary? 0744 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0745 emit getExtension()->openUrlRequest(QUrl(url), arguments, browserArguments); 0746 #else 0747 if (getBrowserExtension()) { 0748 emit getBrowserExtension()->browserOpenUrlRequest(QUrl(url), arguments, browserArguments); 0749 } else { 0750 emit getExtension()->openUrlRequest(QUrl(url)); 0751 } 0752 #endif 0753 } 0754 0755 void Sidebar_Widget::openUrlRequest(const QUrl &url, const KParts::OpenUrlArguments &args, const BrowserArguments &browserArgs) 0756 { 0757 if (m_storedCurViewUrl == url) { // don't pollute the history stack 0758 return; 0759 } 0760 0761 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0762 getExtension()->openUrlRequest(url, args, browserArgs); 0763 #else 0764 if (getBrowserExtension()) { 0765 getBrowserExtension()->browserOpenUrlRequest(url, args, browserArgs); 0766 } else { 0767 getExtension()->openUrlRequest(url); 0768 } 0769 #endif 0770 0771 setStoredCurViewUrl(url); 0772 } 0773 0774 void Sidebar_Widget::createNewWindow(const QUrl &url, const KParts::OpenUrlArguments &args, const BrowserArguments &browserArgs, 0775 const WindowArgs &windowArgs) 0776 { 0777 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0778 getExtension()->createNewWindow(url, args, browserArgs, windowArgs); 0779 #else 0780 if (getBrowserExtension()) { 0781 getBrowserExtension()->browserCreateNewWindow(url, args, browserArgs, windowArgs); 0782 } else { 0783 getExtension()->createNewWindow(url); 0784 } 0785 #endif 0786 } 0787 0788 void Sidebar_Widget::slotEnableAction(KonqSidebarModule *module, const char *name, bool enabled) 0789 { 0790 if (module->getWidget()->isVisible()) { 0791 emit getExtension()->enableAction(name, enabled); 0792 } 0793 } 0794 0795 void Sidebar_Widget::doEnableActions() 0796 { 0797 if (m_activeModule) { 0798 getExtension()->enableAction("copy", m_activeModule->isCopyEnabled()); 0799 getExtension()->enableAction("cut", m_activeModule->isCutEnabled()); 0800 getExtension()->enableAction("paste", m_activeModule->isPasteEnabled()); 0801 } 0802 } 0803 0804 void Sidebar_Widget::connectModule(KonqSidebarModule *mod) 0805 { 0806 connect(mod, &KonqSidebarModule::started, this, &Sidebar_Widget::started); 0807 connect(mod, &KonqSidebarModule::completed, this, &Sidebar_Widget::completed); 0808 0809 connect(mod, &KonqSidebarModule::popupMenu, this, &Sidebar_Widget::slotPopupMenu); 0810 0811 connect(mod, &KonqSidebarModule::openUrlRequest, this, &Sidebar_Widget::openUrlRequest); 0812 connect(mod, &KonqSidebarModule::createNewWindow, this, &Sidebar_Widget::createNewWindow); 0813 0814 // TODO define in base class 0815 if (mod->metaObject()->indexOfSignal("submitFormRequest(const char*,QString,QByteArray,QString,QString,QString)") != -1) { 0816 connect(mod, &KonqSidebarModule::submitFormRequest, this, &Sidebar_Widget::submitFormRequest); 0817 } 0818 0819 connect(mod, &KonqSidebarModule::enableAction, this, &Sidebar_Widget::slotEnableAction); 0820 } 0821 0822 Sidebar_Widget::~Sidebar_Widget() 0823 { 0824 m_config->writeEntry("OpenViews", m_visibleViews); 0825 if (m_configTimer.isActive()) { 0826 saveConfig(); 0827 } 0828 delete m_config; 0829 m_buttons.clear(); 0830 m_noUpdate = true; 0831 } 0832 0833 void Sidebar_Widget::customEvent(QEvent *ev) 0834 { 0835 if (KonqFileSelectionEvent::test(ev)) { 0836 emit fileSelection(static_cast<KonqFileSelectionEvent *>(ev)->selection()); 0837 } else if (KonqFileMouseOverEvent::test(ev)) { 0838 emit fileMouseOver(static_cast<KonqFileMouseOverEvent *>(ev)->item()); 0839 } else if (KParts::PartActivateEvent::test(ev)) { 0840 KParts::ReadOnlyPart* rpart = static_cast<KParts::ReadOnlyPart *>( static_cast<KParts::PartActivateEvent *>(ev)->part() ); 0841 0842 if (! rpart->url().isEmpty()) { 0843 setStoredCurViewUrl(cleanupURL(rpart->url())); 0844 } 0845 0846 if (m_buttons.isEmpty()) { // special case when the event is received but the buttons have not been created yet 0847 m_urlBeforeInstanceFlag = true; 0848 m_origURL = m_storedCurViewUrl; 0849 } 0850 0851 for (int i = 0; i < m_buttons.count(); i++) { 0852 const ButtonInfo &button = m_buttons.at(i); 0853 if (button.dock) { 0854 if ((button.dock->isVisibleTo(this)) && (button.module)) { 0855 // Forward the event to the widget 0856 QApplication::sendEvent(button.module, ev); 0857 break; // if you found the one you wanted.. exit. (Not sure how this would play out in a split-view sidepanel 0858 } 0859 } 0860 } 0861 0862 // Forward the event to the widget 0863 // QApplication::sendEvent(button(), ev); 0864 } 0865 } 0866 0867 KonqSidebarPlugin *ButtonInfo::plugin(QObject *parent) 0868 { 0869 if (!m_plugin) { 0870 KPluginMetaData md = KPluginMetaData::findPluginById(ModuleManager::pluginDirectory(), pluginId); 0871 auto pluginResult = KPluginFactory::instantiatePlugin<KonqSidebarPlugin>(md, parent); 0872 if (pluginResult) { 0873 m_plugin = pluginResult.plugin; 0874 } else { 0875 qCWarning(SIDEBAR_LOG) << "error loading sidebar plugin" << pluginResult.errorText; 0876 } 0877 } 0878 return m_plugin; 0879 } 0880 0881 void Sidebar_Widget::slotPopupMenu(KonqSidebarModule *module, 0882 const QPoint &global, const KFileItemList &items, 0883 const KParts::OpenUrlArguments &args, 0884 const BrowserArguments &browserArgs, 0885 KParts::NavigationExtension::PopupFlags flags, 0886 const KParts::NavigationExtension::ActionGroupMap &actionGroups) 0887 { 0888 m_activeModule = module; 0889 doEnableActions(); 0890 0891 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0892 emit getExtension()->popupMenu(global, items, args, browserArgs, flags, actionGroups); 0893 #else 0894 if (getBrowserExtension()) { 0895 emit getBrowserExtension()->browserPopupMenuFromFiles(global, items, args, browserArgs, flags, actionGroups); 0896 } else { 0897 emit getExtension()->popupMenu(global, items, args, flags, actionGroups); 0898 } 0899 #endif 0900 } 0901 0902 void Sidebar_Widget::slotUrlsDropped(const QList<QUrl> &urls) 0903 { 0904 for (const QUrl &url: urls) { 0905 KIO::StatJob *job = KIO::stat(url); 0906 KJobWidgets::setWindow(job, this); 0907 connect(job, &KIO::StatJob::result, this, &Sidebar_Widget::slotStatResult); 0908 } 0909 } 0910 0911 void Sidebar_Widget::slotStatResult(KJob *job) 0912 { 0913 KIO::StatJob *statJob = static_cast<KIO::StatJob *>(job); 0914 if (statJob->error()) { 0915 statJob->uiDelegate()->showErrorMessage(); 0916 } else { 0917 const QUrl url = statJob->url(); 0918 KFileItem item(statJob->statResult(), url); 0919 if (item.isDir()) { 0920 createDirectModule("folder%1.desktop", url.fileName(), url, item.iconName(), "konqsidebar_tree", "Directory"); 0921 } else if (item.currentMimeType().inherits("text/html") || url.scheme().startsWith("http")) { 0922 const QString name = i18n("Web module"); 0923 createDirectModule("websidebarplugin%1.desktop", name, url, "internet-web-browser", "konqsidebar_web"); 0924 } else { 0925 // What to do about other kinds of files? 0926 qCWarning(SIDEBAR_LOG) << "The dropped URL" << url << "is" << item.mimetype() << ", which is not a directory nor an HTML page, what should we do with it?"; 0927 } 0928 } 0929 } 0930 0931 BrowserExtension *Sidebar_Widget::getBrowserExtension() 0932 { 0933 return qobject_cast<BrowserExtension*>(getExtension()); 0934 } 0935 0936