File indexing completed on 2024-05-12 04:58:09
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 * ============================================================ */ 0018 #include "websearchbar.h" 0019 #include "browserwindow.h" 0020 #include "mainapplication.h" 0021 #include "tabbedwebview.h" 0022 #include "webpage.h" 0023 #include "settings.h" 0024 #include "qzsettings.h" 0025 #include "tabwidget.h" 0026 #include "searchenginesdialog.h" 0027 #include "networkmanager.h" 0028 #include "iconprovider.h" 0029 #include "scripts.h" 0030 0031 #include <QMimeData> 0032 #include <QAbstractItemView> 0033 #include <QCompleter> 0034 #include <QStringListModel> 0035 #include <QMenu> 0036 #include <QTimer> 0037 #include <QClipboard> 0038 #include <QContextMenuEvent> 0039 0040 WebSearchBar_Button::WebSearchBar_Button(QWidget* parent) 0041 : ClickableLabel(parent) 0042 { 0043 setObjectName("websearchbar-searchbutton"); 0044 setCursor(QCursor(Qt::PointingHandCursor)); 0045 setFocusPolicy(Qt::ClickFocus); 0046 } 0047 0048 void WebSearchBar_Button::contextMenuEvent(QContextMenuEvent* event) 0049 { 0050 event->accept(); 0051 } 0052 0053 WebSearchBar::WebSearchBar(BrowserWindow* window) 0054 : LineEdit(window) 0055 , m_window(window) 0056 , m_reloadingEngines(false) 0057 { 0058 setObjectName("websearchbar"); 0059 setDragEnabled(true); 0060 0061 m_buttonSearch = new WebSearchBar_Button(this); 0062 0063 m_boxSearchType = new ButtonWithMenu(this); 0064 m_boxSearchType->setObjectName("websearchbar-searchprovider-combobox"); 0065 m_boxSearchType->setFocusProxy(this); 0066 // RTL Support 0067 // If we don't add 'm_boxSearchType' by following code, then we should use suitable padding-left value 0068 // but then, when typing RTL text the layout dynamically changed and within RTL layout direction 0069 // padding-left is equivalent to padding-right and vice versa, and because style sheet is 0070 // not changed dynamically this create padding problems. 0071 addWidget(m_boxSearchType, LineEdit::LeftSide); 0072 0073 addWidget(m_buttonSearch, LineEdit::RightSide); 0074 0075 connect(m_buttonSearch, &ClickableLabel::clicked, this, &WebSearchBar::search); 0076 connect(m_buttonSearch, &ClickableLabel::middleClicked, this, &WebSearchBar::searchInNewTab); 0077 connect(m_boxSearchType, &ButtonWithMenu::activeItemChanged, this, &WebSearchBar::searchChanged); 0078 0079 setWidgetSpacing(0); 0080 0081 m_searchManager = mApp->searchEnginesManager(); 0082 connect(m_boxSearchType->menu(), &QMenu::aboutToShow, this, &WebSearchBar::aboutToShowMenu); 0083 0084 m_completer = new QCompleter(this); 0085 m_completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); 0086 m_completerModel = new QStringListModel(this); 0087 m_completer->setModel(m_completerModel); 0088 m_completer->popup()->setMinimumHeight(90); 0089 setCompleter(m_completer); 0090 connect(m_completer->popup(), &QAbstractItemView::activated, this, &WebSearchBar::search); 0091 0092 m_openSearchEngine = new OpenSearchEngine(this); 0093 m_openSearchEngine->setNetworkAccessManager(mApp->networkManager()); 0094 connect(m_openSearchEngine, &OpenSearchEngine::suggestions, this, &WebSearchBar::addSuggestions); 0095 connect(this, &QLineEdit::textEdited, m_openSearchEngine, &OpenSearchEngine::requestSuggestions); 0096 0097 editAction(PasteAndGo)->setText(tr("Paste And &Search")); 0098 editAction(PasteAndGo)->setIcon(QIcon::fromTheme(QSL("edit-paste"))); 0099 connect(editAction(PasteAndGo), &QAction::triggered, this, &WebSearchBar::pasteAndGo); 0100 0101 QTimer::singleShot(0, this, &WebSearchBar::setupEngines); 0102 } 0103 0104 void WebSearchBar::aboutToShowMenu() 0105 { 0106 QMenu* menu = m_boxSearchType->menu(); 0107 0108 menu->addSeparator(); 0109 0110 m_window->weView()->page()->runJavaScript(Scripts::getOpenSearchLinks(), WebPage::SafeJsWorld, [this, menu](const QVariant &res) { 0111 const QVariantList &list = res.toList(); 0112 for (const QVariant &val : list) { 0113 const QVariantMap &link = val.toMap(); 0114 QUrl url = m_window->weView()->url().resolved(link.value(QSL("url")).toUrl()); 0115 QString title = link.value(QSL("title")).toString(); 0116 0117 if (url.isEmpty()) 0118 continue; 0119 0120 if (title.isEmpty()) 0121 title = m_window->weView()->title(); 0122 0123 menu->addAction(m_window->weView()->icon(), tr("Add %1 ...").arg(title), this, &WebSearchBar::addEngineFromAction)->setData(url); 0124 } 0125 0126 menu->addSeparator(); 0127 menu->addAction(IconProvider::settingsIcon(), tr("Manage Search Engines"), this, &WebSearchBar::openSearchEnginesDialog); 0128 }); 0129 } 0130 0131 void WebSearchBar::addSuggestions(const QStringList &list) 0132 { 0133 if (qzSettings->showWSBSearchSuggestions) { 0134 QStringList list_ = list.mid(0, 6); 0135 m_completerModel->setStringList(list_); 0136 m_completer->complete(); 0137 } 0138 } 0139 0140 void WebSearchBar::openSearchEnginesDialog() 0141 { 0142 if (!m_searchDialog) 0143 m_searchDialog = new SearchEnginesDialog(this); 0144 0145 m_searchDialog->open(); 0146 m_searchDialog->raise(); 0147 m_searchDialog->activateWindow(); 0148 } 0149 0150 void WebSearchBar::enableSearchSuggestions(bool enable) 0151 { 0152 Settings settings; 0153 settings.beginGroup(QSL("SearchEngines")); 0154 settings.setValue(QSL("showSuggestions"), enable); 0155 settings.endGroup(); 0156 0157 qzSettings->showWSBSearchSuggestions = enable; 0158 m_completerModel->setStringList(QStringList()); 0159 updateOpenSearchEngine(); 0160 } 0161 0162 void WebSearchBar::setupEngines() 0163 { 0164 disconnect(m_searchManager, &SearchEnginesManager::enginesChanged, this, &WebSearchBar::setupEngines); 0165 m_reloadingEngines = true; 0166 0167 QString activeEngine = m_searchManager->startingEngineName(); 0168 0169 if (m_boxSearchType->allItems().count() != 0) { 0170 activeEngine = m_activeEngine.name; 0171 } 0172 0173 m_boxSearchType->clearItems(); 0174 0175 const auto engines = m_searchManager->allEngines(); 0176 for (const SearchEngine &en : engines) { 0177 ButtonWithMenu::Item item; 0178 item.icon = en.icon; 0179 item.text = en.name; 0180 QVariant v; 0181 v.setValue(en); 0182 item.userData = v; 0183 0184 m_boxSearchType->addItem(item); 0185 0186 if (item.text == activeEngine) { 0187 m_boxSearchType->setCurrentItem(item, false); 0188 } 0189 } 0190 0191 searchChanged(m_boxSearchType->currentItem()); 0192 0193 connect(m_searchManager, &SearchEnginesManager::enginesChanged, this, &WebSearchBar::setupEngines); 0194 m_reloadingEngines = false; 0195 } 0196 0197 void WebSearchBar::searchChanged(const ButtonWithMenu::Item &item) 0198 { 0199 setPlaceholderText(item.text); 0200 m_completerModel->setStringList(QStringList()); 0201 0202 m_activeEngine = item.userData.value<SearchEngine>(); 0203 0204 updateOpenSearchEngine(); 0205 0206 m_searchManager->setActiveEngine(m_activeEngine); 0207 0208 if (qzSettings->searchOnEngineChange && !m_reloadingEngines && !text().isEmpty()) { 0209 search(); 0210 } 0211 } 0212 0213 void WebSearchBar::instantSearchChanged(bool enable) 0214 { 0215 Settings settings; 0216 settings.beginGroup(QSL("SearchEngines")); 0217 settings.setValue(QSL("SearchOnEngineChange"), enable); 0218 settings.endGroup(); 0219 qzSettings->searchOnEngineChange = enable; 0220 } 0221 0222 void WebSearchBar::search() 0223 { 0224 m_window->weView()->setFocus(); 0225 m_window->weView()->load(m_searchManager->searchResult(m_activeEngine, text())); 0226 } 0227 0228 void WebSearchBar::searchInNewTab() 0229 { 0230 int index = m_window->tabWidget()->addView(QUrl()); 0231 m_window->weView(index)->setFocus(); 0232 m_window->weView(index)->load(m_searchManager->searchResult(m_activeEngine, text())); 0233 } 0234 0235 void WebSearchBar::addEngineFromAction() 0236 { 0237 if (auto* action = qobject_cast<QAction*>(sender())) { 0238 m_searchManager->addEngine(action->data().toUrl()); 0239 } 0240 } 0241 0242 void WebSearchBar::pasteAndGo() 0243 { 0244 clear(); 0245 paste(); 0246 search(); 0247 } 0248 0249 void WebSearchBar::contextMenuEvent(QContextMenuEvent* event) 0250 { 0251 Q_UNUSED(event) 0252 0253 QMenu* menu = createContextMenu(); 0254 menu->setAttribute(Qt::WA_DeleteOnClose); 0255 0256 menu->addSeparator(); 0257 QAction* act = menu->addAction(tr("Show suggestions")); 0258 act->setCheckable(true); 0259 act->setChecked(qzSettings->showWSBSearchSuggestions); 0260 connect(act, &QAction::triggered, this, &WebSearchBar::enableSearchSuggestions); 0261 0262 QAction* instantSearch = menu->addAction(tr("Search when engine changed")); 0263 instantSearch->setCheckable(true); 0264 instantSearch->setChecked(qzSettings->searchOnEngineChange); 0265 connect(instantSearch, &QAction::triggered, this, &WebSearchBar::instantSearchChanged); 0266 0267 // Prevent choosing first option with double rightclick 0268 QPoint pos = event->globalPos(); 0269 pos.setY(pos.y() + 1); 0270 menu->popup(pos); 0271 } 0272 0273 void WebSearchBar::focusOutEvent(QFocusEvent* e) 0274 { 0275 if (text().isEmpty()) { 0276 QString search = m_boxSearchType->currentItem().text; 0277 setPlaceholderText(search); 0278 } 0279 0280 LineEdit::focusOutEvent(e); 0281 } 0282 0283 void WebSearchBar::dropEvent(QDropEvent* event) 0284 { 0285 if (event->mimeData()->hasText()) { 0286 QString dropText = event->mimeData()->text(); 0287 setText(dropText); 0288 search(); 0289 0290 QFocusEvent event(QFocusEvent::FocusOut); 0291 LineEdit::focusOutEvent(&event); 0292 return; 0293 } 0294 0295 LineEdit::dropEvent(event); 0296 } 0297 0298 void WebSearchBar::keyPressEvent(QKeyEvent* event) 0299 { 0300 switch (event->key()) { 0301 case Qt::Key_V: 0302 if (event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { 0303 pasteAndGo(); 0304 event->accept(); 0305 return; 0306 } 0307 break; 0308 0309 case Qt::Key_Return: 0310 case Qt::Key_Enter: 0311 if (event->modifiers() == Qt::AltModifier) { 0312 searchInNewTab(); 0313 } 0314 else { 0315 search(); 0316 } 0317 break; 0318 0319 case Qt::Key_Up: 0320 if (event->modifiers() == Qt::ControlModifier) { 0321 m_boxSearchType->selectPreviousItem(); 0322 } 0323 break; 0324 0325 case Qt::Key_Down: 0326 if (event->modifiers() == Qt::ControlModifier) { 0327 m_boxSearchType->selectNextItem(); 0328 } 0329 break; 0330 0331 default: 0332 break; 0333 } 0334 0335 LineEdit::keyPressEvent(event); 0336 } 0337 0338 void WebSearchBar::updateOpenSearchEngine() 0339 { 0340 if (qzSettings->showWSBSearchSuggestions) { 0341 m_openSearchEngine->setSuggestionsUrl(m_activeEngine.suggestionsUrl); 0342 m_openSearchEngine->setSuggestionsParameters(m_activeEngine.suggestionsParameters); 0343 } 0344 else { 0345 m_openSearchEngine->setSuggestionsUrl(QL1S("")); 0346 } 0347 }