File indexing completed on 2024-04-14 04:53:09

0001 /* This file is part of the KDE project
0002     SPDX-FileCopyrightText: 1998, 1999 Simon Hausmann <hausmann@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // Own
0008 #include "konqguiclients.h"
0009 
0010 // KDE
0011 #include <ktoggleaction.h>
0012 #include "konqdebug.h"
0013 #include <QIcon>
0014 #include <kiconloader.h>
0015 #include <KLocalizedString>
0016 
0017 // Local
0018 #include "konqview.h"
0019 #include "konqsettingsxt.h"
0020 #include "konqframe.h"
0021 #include "konqframevisitor.h"
0022 #include "konqframestatusbar.h"
0023 #include "konqviewmanager.h"
0024 #include "pluginmetadatautils.h"
0025 #include "konqutils.h"
0026 
0027 PopupMenuGUIClient::PopupMenuGUIClient(const QVector<KPluginMetaData> &embeddingServices,
0028                                        KonqPopupMenu::ActionGroupMap &actionGroups,
0029                                        QAction *showMenuBar, QAction *stopFullScreen)
0030     : m_actionCollection(this),
0031       m_embeddingServices(embeddingServices)
0032 {
0033     QList<QAction *> topActions;
0034     if (showMenuBar) {
0035         topActions.append(showMenuBar);
0036         QAction *separator = new QAction(&m_actionCollection);
0037         separator->setSeparator(true);
0038         topActions.append(separator);
0039     }
0040 
0041     if (stopFullScreen) {
0042         topActions.append(stopFullScreen);
0043         QAction *separator = new QAction(&m_actionCollection);
0044         separator->setSeparator(true);
0045         topActions.append(separator);
0046     }
0047 
0048     if (!embeddingServices.isEmpty()) {
0049         QList<QAction *> previewActions;
0050         if (embeddingServices.count() == 1) {
0051             KPluginMetaData service = embeddingServices.first();
0052             QAction *act = addEmbeddingPlugin(0, i18n("Preview &in %1", service.name()), service);
0053             previewActions.append(act);
0054         } else if (embeddingServices.count() > 1) {
0055             QVector<KPluginMetaData>::ConstIterator it = embeddingServices.begin();
0056             const QVector<KPluginMetaData>::ConstIterator end = embeddingServices.end();
0057             int idx = 0;
0058             for (; it != end; ++it, ++idx) {
0059                 QAction *act = addEmbeddingPlugin(idx, (*it).name(), *it);
0060                 previewActions.append(act);
0061             }
0062         }
0063         actionGroups.insert(KonqPopupMenu::PreviewActions, previewActions);
0064     }
0065     actionGroups.insert(KonqPopupMenu::TopActions, topActions);
0066 }
0067 
0068 PopupMenuGUIClient::~PopupMenuGUIClient()
0069 {
0070 }
0071 
0072 QAction *PopupMenuGUIClient::addEmbeddingPlugin(int idx, const QString &name, const KPluginMetaData &plugin)
0073 {
0074     QAction *act = m_actionCollection.addAction(QByteArray::number(idx));
0075     act->setText(name);
0076     act->setIcon(QIcon::fromTheme(plugin.iconName()));
0077     QObject::connect(act, &QAction::triggered, this, &PopupMenuGUIClient::slotOpenEmbedded);
0078     return act;
0079 }
0080 
0081 void PopupMenuGUIClient::slotOpenEmbedded()
0082 {
0083     int idx = sender()->objectName().toInt();
0084     // This calls KonqMainWindow::slotOpenEmbedded(service) (delayed so that the menu is closed first)
0085     emit openEmbedded(m_embeddingServices.at(idx));
0086 }
0087 
0088 ////
0089 
0090 ToggleViewGUIClient::ToggleViewGUIClient(KonqMainWindow *mainWindow)
0091     : QObject(mainWindow)
0092 {
0093     m_mainWindow = mainWindow;
0094 
0095     auto filter = [](const KPluginMetaData &md) {
0096         if (!Konq::serviceTypes(md).contains(QStringLiteral("Browser/View"))) {
0097             return false;
0098         }
0099         bool toggable = md.value(QStringLiteral("X-KDE-BrowserView-Toggable"), false);
0100         if (!toggable) {
0101             return false;
0102         }
0103         QString orientation = (QStringLiteral("X-KDE-BrowserView-ToggableView-Orientation"), QString());
0104         if (!orientation.isEmpty()) {
0105             return false;
0106         }
0107         return true;
0108     };
0109     QVector<KPluginMetaData> mds = findParts(filter, true);
0110     //TODO KF6: check whether this is still true
0111     //Sometimes there may be duplicates, so remove them
0112     std::sort(mds.begin(), mds.end(), [](const KPluginMetaData &md1, const KPluginMetaData &md2){return md1.pluginId() <= md2.pluginId();});
0113     auto last = std::unique(mds.begin(), mds.end(), [](const KPluginMetaData &md1, const KPluginMetaData &md2){return md1.pluginId() == md2.pluginId();});
0114     mds.erase(last, mds.end());
0115 
0116     m_empty = mds.isEmpty();
0117     if (m_empty) {
0118         return;
0119     }
0120 
0121     for (const KPluginMetaData &md : mds) {
0122         QString description = i18n("Show %1", md.name());
0123         QString name = md.pluginId();
0124         //qCDebug(KONQUEROR_LOG) << "ToggleViewGUIClient: name=" << name;
0125         KToggleAction *action = new KToggleAction(description, this);
0126         mainWindow->actionCollection()->addAction(name.toLatin1(), action);
0127 
0128         // HACK
0129         if (md.iconName() != QLatin1String("unknown")) {
0130             action->setIcon(QIcon::fromTheme(md.iconName()));
0131         }
0132 
0133         connect(action, &QAction::toggled, this, &ToggleViewGUIClient::slotToggleView);
0134 
0135         m_actions.insert(name, action);
0136 
0137         QVariant orientation = md.value(QStringLiteral("X-KDE-BrowserView-ToggableView-Orientation"));
0138         bool horizontal = orientation.toString().toLower() == QLatin1String("horizontal");
0139         m_mapOrientation.insert(name, horizontal);
0140     }
0141 
0142     connect(m_mainWindow, &KonqMainWindow::viewAdded, this, &ToggleViewGUIClient::slotViewAdded);
0143     connect(m_mainWindow, &KonqMainWindow::viewRemoved, this, &ToggleViewGUIClient::slotViewRemoved);
0144 }
0145 
0146 ToggleViewGUIClient::~ToggleViewGUIClient()
0147 {
0148 }
0149 
0150 QList<QAction *> ToggleViewGUIClient::actions() const
0151 {
0152     return m_actions.values();
0153 }
0154 
0155 void ToggleViewGUIClient::slotToggleView(bool toggle)
0156 {
0157     QString serviceName = sender()->objectName();
0158 
0159     bool horizontal = m_mapOrientation[ serviceName ];
0160 
0161     KonqViewManager *viewManager = m_mainWindow->viewManager();
0162 
0163     if (toggle) {
0164         // Don't crash when doing things too quickly.
0165         if (!m_mainWindow->currentView()) {
0166             return;
0167         }
0168         KonqView *childView = viewManager->splitMainContainer(m_mainWindow->currentView(),
0169                               horizontal ? Qt::Vertical : Qt::Horizontal,
0170                               QStringLiteral("Browser/View"),
0171                               serviceName,
0172                               !horizontal /* vertical = make it first */);
0173 
0174         QList<int> newSplitterSizes;
0175 
0176         if (horizontal) {
0177             newSplitterSizes << 100 << 30;
0178         } else {
0179             newSplitterSizes << 30 << 100;
0180         }
0181 
0182         if (!childView || !childView->frame()) {
0183             return;
0184         }
0185 
0186         // Toggleviews don't need their statusbar
0187         childView->frame()->statusbar()->hide();
0188 
0189         KonqFrameContainerBase *newContainer = childView->frame()->parentContainer();
0190 
0191         if (newContainer->frameType() == KonqFrameBase::Container) {
0192             static_cast<KonqFrameContainer *>(newContainer)->setSizes(newSplitterSizes);
0193         }
0194 
0195 #if 0 // already done by splitWindow
0196         if (m_mainWindow->currentView()) {
0197             QString locBarURL = m_mainWindow->currentView()->url().prettyUrl(); // default one in case it doesn't set it
0198             childView->openUrl(m_mainWindow->currentView()->url(), locBarURL);
0199         }
0200 #endif
0201 
0202         // If not passive, set as active :)
0203         if (!childView->isPassiveMode()) {
0204             viewManager->setActivePart(childView->part());
0205         }
0206 
0207         qCDebug(KONQUEROR_LOG) << "ToggleViewGUIClient::slotToggleView setToggleView(true) on " << childView;
0208         childView->setToggleView(true);
0209 
0210         m_mainWindow->viewCountChanged();
0211 
0212     } else {
0213         const QList<KonqView *> viewList = KonqViewCollector::collect(m_mainWindow);
0214         for (KonqView *view: viewList) {
0215             if (view->service().pluginId() == serviceName)
0216                 // takes care of choosing the new active view, and also calls slotViewRemoved
0217             {
0218                 viewManager->removeView(view);
0219             }
0220         }
0221     }
0222 
0223 }
0224 
0225 void ToggleViewGUIClient::saveConfig(bool add, const QString &serviceName)
0226 {
0227     // This is used on konqueror's startup....... so it's never used, since
0228     // the K menu only contains calls to kfmclient......
0229     // Well, it could be useful again in the future.
0230     // Currently, the profiles save this info.
0231     QStringList toggableViewsShown = KonqSettings::toggableViewsShown();
0232     if (add) {
0233         if (!toggableViewsShown.contains(serviceName)) {
0234             toggableViewsShown.append(serviceName);
0235         }
0236     } else {
0237         toggableViewsShown.removeAll(serviceName);
0238     }
0239     KonqSettings::setToggableViewsShown(toggableViewsShown);
0240 }
0241 
0242 void ToggleViewGUIClient::slotViewAdded(KonqView *view)
0243 {
0244     QString name = view->service().pluginId();
0245 
0246     QAction *action = m_actions.value(name);
0247 
0248     if (action) {
0249         disconnect(action, &QAction::toggled, this, &ToggleViewGUIClient::slotToggleView);
0250         static_cast<KToggleAction *>(action)->setChecked(true);
0251         connect(action, &QAction::toggled, this, &ToggleViewGUIClient::slotToggleView);
0252 
0253         saveConfig(true, name);
0254 
0255         // KonqView::isToggleView() is not set yet.. so just check for the orientation
0256 
0257 #if 0
0258         QVariant vert = view->service()->property("X-KDE-BrowserView-ToggableView-Orientation");
0259         bool vertical = vert.toString().toLower() == "vertical";
0260         QVariant nohead = view->service()->property("X-KDE-BrowserView-ToggableView-NoHeader");
0261         bool noheader = nohead.isValid() ? nohead.toBool() : false;
0262         // if it is a vertical toggle part, turn on the header.
0263         // this works even when konq loads the view from a profile.
0264         if (vertical && (!noheader)) {
0265             view->frame()->header()->setText(view->service()->name());
0266             view->frame()->header()->setAction(action);
0267         }
0268 #endif
0269     }
0270 }
0271 
0272 void ToggleViewGUIClient::slotViewRemoved(KonqView *view)
0273 {
0274     QString name = view->service().pluginId();
0275 
0276     QAction *action = m_actions.value(name);
0277 
0278     if (action) {
0279         disconnect(action, &QAction::toggled, this, &ToggleViewGUIClient::slotToggleView);
0280         static_cast<KToggleAction *>(action)->setChecked(false);
0281         connect(action, &QAction::toggled, this, &ToggleViewGUIClient::slotToggleView);
0282         saveConfig(false, name);
0283     }
0284 }
0285