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 }