File indexing completed on 2024-05-19 05:00:55

0001 /*
0002     This file is part of the KDE project.
0003 
0004     SPDX-FileCopyrightText: 2020 Stefano Crocco <stefano.crocco@alice.it>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 */
0008 
0009 #include "useragent.h"
0010 #include "ui_useragent.h"
0011 #include "interfaces/browser.h"
0012 
0013 #include <KConfigGroup>
0014 #include <KMessageWidget>
0015 
0016 #include <QDBusMessage>
0017 #include <QDBusConnection>
0018 #include <QInputDialog>
0019 #include <QWebEngineProfile>
0020 #include <QDir>
0021 
0022 
0023 UserAgent::UserAgent(QObject *parent, const KPluginMetaData &md, const QVariantList &): KCModule(parent, md),
0024     m_ui(new Ui::UserAgent),
0025     m_config(KSharedConfig::openConfig(QString(), KConfig::NoGlobals)),
0026     m_templatesConfig(KSharedConfig::openConfig("useragenttemplatesrc"))
0027 {
0028     m_ui->setupUi(widget());
0029     fillTemplateWidget(m_templatesConfig->group("Templates").entryMap());
0030     connect(m_ui->useTemplateBtn, &QPushButton::clicked, this, &UserAgent::useSelectedTemplate);
0031     connect(m_ui->templates, &QTreeWidget::itemDoubleClicked, this, &UserAgent::useDblClickedTemplate);
0032     connect(m_ui->templates, &QTreeWidget::itemSelectionChanged, this, &UserAgent::templateSelectionChanged);
0033     connect(m_ui->useDefaultUA, &QCheckBox::toggled, this, [this](bool on){toggleCustomUA(!on);});
0034     connect(m_ui->userAgentString, &QLineEdit::textChanged, this, [this](){setNeedsSave(true);});
0035     connect(m_ui->editTemplateBtn, &QPushButton::clicked, this, &UserAgent::editTemplate);
0036     connect(m_ui->newTemplateBtn, &QPushButton::clicked, this, &UserAgent::createNewTemplate);
0037     connect(m_ui->duplicateTemplateBtn, &QPushButton::clicked, this, &UserAgent::duplicateTemplate);
0038     connect(m_ui->renameTemplateBtn, &QPushButton::clicked, this, &UserAgent::renameTemplate);
0039     connect(m_ui->deleteTemplateBtn, &QPushButton::clicked, this, &UserAgent::deleteTemplate);
0040     connect(m_ui->templates, &QTreeWidget::itemChanged, this, &UserAgent::templateChanged);
0041 }
0042 
0043 UserAgent::~UserAgent()
0044 {
0045 }
0046 
0047 bool UserAgent::useCustomUserAgent() const
0048 {
0049     return !m_ui->useDefaultUA->isChecked();
0050 }
0051 
0052 void UserAgent::fillTemplateWidget(const UserAgent::TemplateMap& templates)
0053 {
0054     m_ui->templates->clear();
0055     for (auto it = templates.constBegin(); it != templates.constEnd(); ++it) {
0056         QTreeWidgetItem *item = new QTreeWidgetItem(m_ui->templates, {it.key(), it.value()});
0057         item->setFlags(item->flags() | Qt::ItemIsEditable);
0058         item->setToolTip(1, it.value());
0059         m_ui->templates->addTopLevelItem(item);
0060     }
0061 }
0062 
0063 void UserAgent::defaults()
0064 {
0065     //Find the default templates. As far as I know, KConfig doesn't provide a way to only open the global config
0066     //so we use QStandardPaths::locateAll to find all useragenttemplatesrc files. We assume that, as for QStandardPaths::standardLocations
0067     //the files are sorted from highest to lowest priority, so we use the last one.
0068     QStringList files = QStandardPaths::locateAll(QStandardPaths::ConfigLocation, "useragenttemplatesrc");
0069     if (!files.isEmpty()) {
0070         KConfigGroup grp = KSharedConfig::openConfig(files.constLast(), KConfig::SimpleConfig)->group("Templates");
0071         fillTemplateWidget(grp.entryMap());
0072     }
0073 
0074     m_ui->useDefaultUA->setChecked(true);
0075     m_ui->userAgentString->setText(QString());
0076     setNeedsSave(true);
0077 
0078 #if QT_VERSION_MAJOR > 5
0079     setRepresentsDefaults(true);
0080 #endif
0081 }
0082 
0083 void UserAgent::load()
0084 {
0085     KConfigGroup grp = m_config->group("UserAgent");
0086     m_ui->userAgentString->setText(grp.readEntry("CustomUserAgent", QString()));
0087     m_ui->useDefaultUA->setChecked(grp.readEntry("UseDefaultUserAgent", true));
0088     toggleCustomUA(useCustomUserAgent());
0089     m_ui->invalidTemplateNameWidget->hide(); //There can't be problems when loading
0090     KCModule::load();
0091 }
0092 
0093 void UserAgent::save()
0094 {
0095     KConfigGroup grp = m_config->group("UserAgent");
0096     grp.writeEntry("CustomUserAgent", m_ui->userAgentString->text());
0097     grp.writeEntry("UseDefaultUserAgent", m_ui->useDefaultUA->isChecked());
0098     grp.sync();
0099     saveTemplates();
0100     QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KonqMain"), QStringLiteral("org.kde.Konqueror.Main"),
0101                                                       QStringLiteral("reparseConfiguration"));
0102     QDBusConnection::sessionBus().send(message);
0103     KCModule::save();
0104 }
0105 
0106 void UserAgent::saveTemplates()
0107 {
0108     KConfigGroup grp = m_templatesConfig->group("Templates");
0109     TemplateMap oldTemplates = grp.entryMap();
0110     TemplateMap newTemplates = templatesFromUI();
0111     for (TemplateMap::const_iterator it = oldTemplates.constBegin(); it!= oldTemplates.constEnd(); ++it) {
0112         if (!newTemplates.contains(it.key())) {
0113             grp.deleteEntry(it.key());
0114         }
0115     }
0116     for (TemplateMap::const_iterator it = newTemplates.constBegin(); it!= newTemplates.constEnd(); ++it) {
0117         grp.writeEntry(it.key(), it.value());
0118     }
0119     grp.sync();
0120 }
0121 
0122 void UserAgent::enableDisableUseSelectedTemplateBtn()
0123 {
0124     m_ui->useTemplateBtn->setEnabled(useCustomUserAgent() && selectedTemplate() != nullptr);
0125 }
0126 
0127 void UserAgent::toggleCustomUA(bool on)
0128 {
0129     m_ui->userAgentString->setEnabled(on);
0130     m_ui->customUABox->setEnabled(on);
0131     enableDisableUseSelectedTemplateBtn();
0132     setNeedsSave(true);
0133 }
0134 
0135 QTreeWidgetItem * UserAgent::selectedTemplate() const
0136 {
0137     QList<QTreeWidgetItem*> items = m_ui->templates->selectedItems();
0138     return !items.isEmpty() ? items.at(0) : nullptr;
0139 }
0140 
0141 void UserAgent::useSelectedTemplate()
0142 {
0143     QTreeWidgetItem *it = selectedTemplate();
0144     if (it) {
0145         useTemplate(it->text(1));
0146     }
0147 }
0148 
0149 void UserAgent::useDblClickedTemplate(QTreeWidgetItem *it, int)
0150 {
0151     if (it) {
0152         useTemplate(it->text(1));
0153     }
0154 }
0155 
0156 void UserAgent::useTemplate(const QString &templ)
0157 {
0158     m_ui->userAgentString->setText(templ);
0159 }
0160 
0161 void UserAgent::templateSelectionChanged()
0162 {
0163     bool selectionExists = !m_ui->templates->selectedItems().isEmpty();
0164     std::vector<QPushButton*> btns {m_ui->deleteTemplateBtn, m_ui->editTemplateBtn, m_ui->renameTemplateBtn, m_ui->duplicateTemplateBtn};
0165     for (QPushButton *btn : btns) {
0166         btn->setEnabled(selectionExists);
0167     }
0168     enableDisableUseSelectedTemplateBtn();
0169 }
0170 
0171 void UserAgent::createNewTemplate()
0172 {
0173     QTreeWidgetItem *it = createNewTemplateInternal();
0174     if (it) {
0175         m_ui->templates->editItem(it, 1);
0176     }
0177 }
0178 
0179 void UserAgent::duplicateTemplate()
0180 {
0181     QTreeWidgetItem *sel = selectedTemplate();
0182     if (!sel) {
0183         return;
0184     }
0185     QTreeWidgetItem *it = createNewTemplateInternal();
0186     if (it) {
0187         it->setText(1, sel->text(1));
0188     }
0189 }
0190 
0191 QTreeWidgetItem* UserAgent::createNewTemplateInternal()
0192 {
0193     bool ok = false;
0194     QString name = QInputDialog::getText(widget(), i18nc("@title:window Title of dialog to choose name to given to new User Agent", "Choose User Agent name"),
0195                                          i18nc("Name of the new User Agent", "User Agent name"), QLineEdit::Normal, QString(), &ok);
0196     if (!ok) {
0197         return nullptr;
0198     }
0199     KonqInterfaces::Browser* browser = KonqInterfaces::Browser::browser(qApp);
0200     QString defaultUserAgent = browser ? browser->konqUserAgent() : QString();
0201     QTreeWidgetItem *it = new QTreeWidgetItem({name, defaultUserAgent});
0202     it->setFlags(it->flags() | Qt::ItemIsEditable);
0203     m_ui->templates->addTopLevelItem(it);
0204     checkTemplatesValidity();
0205     m_ui->templates->selectionModel()->clearSelection();
0206     it->setSelected(true);
0207     return it;
0208 }
0209 
0210 
0211 void UserAgent::deleteTemplate()
0212 {
0213     QTreeWidgetItem *it = selectedTemplate();
0214     if (it) {
0215         delete it;
0216         setNeedsSave(true);
0217     }
0218 }
0219 
0220 void UserAgent::editTemplate()
0221 {
0222     QTreeWidgetItem *it = selectedTemplate();
0223     if (it) {
0224         m_ui->templates->editItem(it, 1);
0225     }
0226 }
0227 
0228 void UserAgent::renameTemplate()
0229 {
0230     QTreeWidgetItem *it = selectedTemplate();
0231     if (it) {
0232         m_ui->templates->editItem(it, 0);
0233     }
0234 }
0235 
0236 void UserAgent::templateChanged(QTreeWidgetItem*, int col)
0237 {
0238     if (col == 0) {
0239         checkTemplatesValidity();
0240     }
0241     setNeedsSave(true);
0242 }
0243 
0244 UserAgent::TemplateMap UserAgent::templatesFromUI() const
0245 {
0246     TemplateMap map;
0247     for (int i = 0; i < m_ui->templates->topLevelItemCount(); ++i) {
0248         QTreeWidgetItem *it = m_ui->templates->topLevelItem(i);
0249         map[it->text(0)] = it->text(1);
0250     }
0251     return map;
0252 }
0253 
0254 QString emptyTemplateNameMsg() {
0255     static QString s_msg(i18n("there are templates with empty names"));
0256     return s_msg;
0257 }
0258 
0259 QString duplicateTemplateNamesMsg() {
0260     static QString s_msg(i18n("there are multiple templates with the same name"));
0261     return s_msg;
0262 }
0263 
0264 void UserAgent::checkTemplatesValidity()
0265 {
0266     QStringList names;
0267     names.reserve(m_ui->templates->topLevelItemCount());
0268     bool emptyNames = false;
0269     for (int i =0; i < m_ui->templates->topLevelItemCount(); ++i) {
0270         QString name = m_ui->templates->topLevelItem(i)->text(0);
0271         names.append(name);
0272         if (name.isEmpty()) {
0273             emptyNames = true;
0274         }
0275     }
0276     names.sort();
0277     bool hasDuplicates = std::unique(names.begin(), names.end()) != names.end();
0278     if (!emptyNames && !hasDuplicates) {
0279         m_ui->invalidTemplateNameWidget->animatedHide();
0280         return;
0281     }
0282 
0283     QString invalidTemplateNamesHeader(i18nc("The user gave a custom user agent string an empty or duplicate name", "Invalid user agent names:"));
0284     QString invalidTemplatesText;
0285     if (emptyNames && hasDuplicates) {
0286         invalidTemplatesText = QLatin1String("%1<br><ul><li>%2</li><li>%3</li></ul>").arg(invalidTemplateNamesHeader, emptyTemplateNameMsg(), duplicateTemplateNamesMsg());
0287     } else {
0288         invalidTemplatesText = QLatin1String("%1 %2").arg(invalidTemplateNamesHeader, (emptyNames ? emptyTemplateNameMsg() : duplicateTemplateNamesMsg()));
0289     }
0290     m_ui->invalidTemplateNameWidget->setText(invalidTemplatesText);
0291     m_ui->invalidTemplateNameWidget->animatedShow();
0292 }