File indexing completed on 2024-05-12 11:54:37
0001 /* 0002 SPDX-FileCopyrightText: 2000 Malte Starostik <malte@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "searchproviderdlg.h" 0008 #include "searchprovider.h" 0009 0010 #include <QClipboard> 0011 0012 #include <KLocalizedString> 0013 #include <KMessageBox> 0014 #include <QApplication> 0015 #include <QTextCodec> 0016 #include <QVBoxLayout> 0017 0018 SearchProviderDialog::SearchProviderDialog(SearchProvider *provider, QList<SearchProvider *> &providers, QWidget *parent) 0019 : QDialog(parent) 0020 , m_provider(provider) 0021 { 0022 setModal(true); 0023 0024 m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); 0025 connect(m_buttons, &QDialogButtonBox::accepted, this, &SearchProviderDialog::accept); 0026 connect(m_buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); 0027 0028 QWidget *mainWidget = new QWidget(this); 0029 m_dlg.setupUi(mainWidget); 0030 0031 QVBoxLayout *layout = new QVBoxLayout(this); 0032 layout->addWidget(mainWidget); 0033 layout->addWidget(m_buttons); 0034 0035 m_dlg.leQuery->setMinimumWidth(m_dlg.leQuery->fontMetrics().averageCharWidth() * 50); 0036 0037 connect(m_dlg.leName, &QLineEdit::textChanged, this, &SearchProviderDialog::slotChanged); 0038 connect(m_dlg.leQuery, &QLineEdit::textChanged, this, &SearchProviderDialog::slotChanged); 0039 connect(m_dlg.leShortcut, &QLineEdit::textChanged, this, &SearchProviderDialog::slotChanged); 0040 connect(m_dlg.leShortcut, &QLineEdit::textChanged, this, &SearchProviderDialog::shortcutsChanged); 0041 connect(m_dlg.pbPaste, &QAbstractButton::clicked, this, &SearchProviderDialog::pastePlaceholder); 0042 0043 // Data init 0044 m_providers = providers; 0045 QStringList charsets; 0046 for (const auto &codec : QTextCodec::availableCodecs()) { 0047 charsets << QString::fromUtf8(codec); 0048 } 0049 charsets.prepend(i18nc("@item:inlistbox The default character set", "Default")); 0050 m_dlg.cbCharset->addItems(charsets); 0051 if (m_provider) { 0052 setWindowTitle(i18n("Modify Web Shortcut")); 0053 m_dlg.leName->setText(m_provider->name()); 0054 m_dlg.leQuery->setText(m_provider->query()); 0055 m_dlg.leShortcut->setText(m_provider->keys().join(QLatin1Char(','))); 0056 m_dlg.cbCharset->setCurrentIndex(m_provider->charset().isEmpty() ? 0 : charsets.indexOf(m_provider->charset())); 0057 m_dlg.leName->setEnabled(false); 0058 m_dlg.leQuery->setFocus(); 0059 } else { 0060 setWindowTitle(i18n("New Web Shortcut")); 0061 m_dlg.leName->setFocus(); 0062 0063 // If the clipboard contains a url copy it to the query lineedit 0064 const QClipboard *clipboard = QApplication::clipboard(); 0065 const QString url = clipboard->text(); 0066 0067 if (!QUrl(url).host().isEmpty()) { 0068 m_dlg.leQuery->setText(url); 0069 } 0070 0071 m_buttons->button(QDialogButtonBox::Ok)->setEnabled(false); 0072 } 0073 } 0074 0075 void SearchProviderDialog::slotChanged() 0076 { 0077 m_buttons->button(QDialogButtonBox::Ok) 0078 ->setEnabled(!(m_dlg.leName->text().isEmpty() || m_dlg.leShortcut->text().isEmpty() || m_dlg.leQuery->text().isEmpty()) 0079 && m_dlg.noteLabel->text().isEmpty()); 0080 } 0081 0082 // Check if the user wants to assign shorthands that are already assigned to 0083 // another search provider. Invoked on every change to the shortcuts field. 0084 void SearchProviderDialog::shortcutsChanged(const QString &newShorthands) 0085 { 0086 // Convert all spaces to commas. A shorthand should be a single word. 0087 // Assume that the user wanted to enter an alternative shorthand and hit 0088 // space instead of the comma key. Save cursor position beforehand because 0089 // setText() will reset it to the end, which is not what we want when 0090 // backspacing something in the middle. 0091 int savedCursorPosition = m_dlg.leShortcut->cursorPosition(); 0092 QString normalizedShorthands = QString(newShorthands).replace(QLatin1Char(' '), QLatin1Char(',')); 0093 m_dlg.leShortcut->setText(normalizedShorthands); 0094 m_dlg.leShortcut->setCursorPosition(savedCursorPosition); 0095 0096 QHash<QString, const SearchProvider *> contenders; 0097 const QStringList normList = normalizedShorthands.split(QLatin1Char(',')); 0098 const QSet<QString> shorthands(normList.begin(), normList.end()); 0099 0100 auto findProvider = [this](const QString &shorthand) { 0101 return std::find_if(m_providers.cbegin(), m_providers.cend(), [this, &shorthand](const SearchProvider *provider) { 0102 return provider != m_provider && provider->keys().contains(shorthand); 0103 }); 0104 }; 0105 // Look at each shorthand the user entered and wade through the search 0106 // provider list in search of a conflicting shorthand. Do not continue 0107 // search after finding one, because shorthands should be assigned only 0108 // once. Act like data inconsistencies regarding this don't exist (should 0109 // probably be handled on load). 0110 for (const QString &shorthand : shorthands) { 0111 auto it = findProvider(shorthand); 0112 if (it != m_providers.cend()) { 0113 contenders.insert(shorthand, *it); 0114 } 0115 } 0116 0117 const int contendersSize = contenders.size(); 0118 if (contendersSize != 0) { 0119 if (contendersSize == 1) { 0120 auto it = contenders.cbegin(); 0121 m_dlg.noteLabel->setText(i18n("The shortcut \"%1\" is already assigned to \"%2\". Please choose a different one.", it.key(), it.value()->name())); 0122 } else { 0123 QStringList contenderList; 0124 contenderList.reserve(contendersSize); 0125 for (auto it = contenders.cbegin(); it != contenders.cend(); ++it) { 0126 contenderList.append(i18nc("- web short cut (e.g. gg): what it refers to (e.g. Google)", "- %1: \"%2\"", it.key(), it.value()->name())); 0127 } 0128 0129 m_dlg.noteLabel->setText( 0130 i18n("The following shortcuts are already assigned. Please choose different ones.\n%1", contenderList.join(QLatin1Char('\n')))); 0131 } 0132 m_buttons->button(QDialogButtonBox::Ok)->setEnabled(false); 0133 } else { 0134 m_dlg.noteLabel->clear(); 0135 } 0136 slotChanged(); 0137 } 0138 0139 void SearchProviderDialog::accept() 0140 { 0141 if ((m_dlg.leQuery->text().indexOf(QLatin1String("\\{")) == -1) 0142 && KMessageBox::warningContinueCancel(nullptr, 0143 i18n("The Shortcut URL does not contain a \\{...} placeholder for the user query.\n" 0144 "This means that the same page is always going to be visited, " 0145 "regardless of the text typed in with the shortcut."), 0146 QString(), 0147 KGuiItem(i18n("Keep It"))) 0148 == KMessageBox::Cancel) { 0149 return; 0150 } 0151 0152 if (!m_provider) { 0153 m_provider = new SearchProvider; 0154 } 0155 0156 const QString name = m_dlg.leName->text().trimmed(); 0157 const QString query = m_dlg.leQuery->text().trimmed(); 0158 QStringList keys = m_dlg.leShortcut->text().trimmed().toLower().split(QLatin1Char(','), Qt::SkipEmptyParts); 0159 keys.removeDuplicates(); // #169801. Remove duplicates... 0160 const QString charset = (m_dlg.cbCharset->currentIndex() ? m_dlg.cbCharset->currentText().trimmed() : QString()); 0161 0162 m_provider->setDirty((name != m_provider->name() || query != m_provider->query() || keys != m_provider->keys() || charset != m_provider->charset())); 0163 m_provider->setName(name); 0164 m_provider->setQuery(query); 0165 m_provider->setKeys(keys); 0166 m_provider->setCharset(charset); 0167 QDialog::accept(); 0168 } 0169 0170 void SearchProviderDialog::pastePlaceholder() 0171 { 0172 m_dlg.leQuery->insert(QStringLiteral("\\{@}")); 0173 m_dlg.leQuery->setFocus(); 0174 } 0175 0176 #include "moc_searchproviderdlg.cpp"