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 &currentProfile)
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