1 /**************************************************************************
2 * Otter Browser: Web browser controlled by the user, not vice-versa.
3 * Copyright (C) 2013 - 2018 Michal Dutkiewicz aka Emdek <michal@emdek.pl>
4 * Copyright (C) 2014 - 2017 Jan Bajer aka bajasoft <jbajer@gmail.com>
5 * Copyright (C) 2014 Piotr Wójcik <chocimier@tlen.pl>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 **************************************************************************/
21
22 #include "AddressWidget.h"
23 #include "../../../core/ActionsManager.h"
24 #include "../../../core/AddressCompletionModel.h"
25 #include "../../../core/Application.h"
26 #include "../../../core/BookmarksManager.h"
27 #include "../../../core/InputInterpreter.h"
28 #include "../../../core/HistoryManager.h"
29 #include "../../../core/SearchEnginesManager.h"
30 #include "../../../core/ThemesManager.h"
31 #include "../../../core/Utils.h"
32 #include "../../../ui/Action.h"
33 #include "../../../ui/BookmarkPropertiesDialog.h"
34 #include "../../../ui/ContentsWidget.h"
35 #include "../../../ui/MainWindow.h"
36 #include "../../../ui/ToolBarWidget.h"
37 #include "../../../ui/Window.h"
38
39 #include <QtCore/QMetaEnum>
40 #include <QtGui/QAbstractTextDocumentLayout>
41 #include <QtGui/QClipboard>
42 #include <QtGui/QContextMenuEvent>
43 #include <QtGui/QPainter>
44 #include <QtGui/QTextBlock>
45 #include <QtGui/QTextDocument>
46 #include <QtWidgets/QApplication>
47 #include <QtWidgets/QMenu>
48 #include <QtWidgets/QToolTip>
49
50 namespace Otter
51 {
52
53 int AddressWidget::m_entryIdentifierEnumerator(-1);
54
AddressDelegate(const QString & highlight,ViewMode mode,QObject * parent)55 AddressDelegate::AddressDelegate(const QString &highlight, ViewMode mode, QObject *parent) : QStyledItemDelegate(parent),
56 m_highlight(highlight),
57 m_displayMode((SettingsManager::getOption(SettingsManager::AddressField_CompletionDisplayModeOption).toString() == QLatin1String("columns")) ? ColumnsMode : CompactMode),
58 m_viewMode(mode)
59 {
60 connect(SettingsManager::getInstance(), &SettingsManager::optionChanged, this, &AddressDelegate::handleOptionChanged);
61 }
62
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const63 void AddressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
64 {
65 QRect titleRectangle(option.rect);
66 const bool isRightToLeft(option.direction == Qt::RightToLeft);
67
68 if (static_cast<AddressCompletionModel::CompletionEntry::EntryType>(index.data(AddressCompletionModel::TypeRole).toInt()) == AddressCompletionModel::CompletionEntry::HeaderType)
69 {
70 QStyleOptionViewItem headerOption(option);
71 headerOption.rect = titleRectangle.marginsRemoved(QMargins(0, 2, (isRightToLeft ? 3 : 0), 2));
72 headerOption.text = index.data(AddressCompletionModel::TitleRole).toString();
73
74 if (index.row() > 0)
75 {
76 QPen pen(option.palette.color(QPalette::Disabled, QPalette::Text).lighter());
77 pen.setWidth(1);
78 pen.setStyle(Qt::SolidLine);
79
80 painter->save();
81 painter->setPen(pen);
82 painter->drawLine((option.rect.left() + 5), (option.rect.top() + 3), (option.rect.right() - 5), (option.rect.top() + 3));
83 painter->restore();
84 }
85
86 QStyledItemDelegate::paint(painter, headerOption, index);
87
88 return;
89 }
90
91 QAbstractTextDocumentLayout::PaintContext paintContext;
92 QTextDocument document;
93 document.setDefaultFont(option.font);
94
95 QString url(index.data(Qt::DisplayRole).toString());
96 QString description((m_viewMode == HistoryMode) ? Utils::formatDateTime(index.data(AddressCompletionModel::TimeVisitedRole).toDateTime()) : index.data(AddressCompletionModel::TitleRole).toString());
97 const int topPosition(titleRectangle.top() - qRound((titleRectangle.height() - painter->clipBoundingRect().united(document.documentLayout()->blockBoundingRect(document.firstBlock())).height()) / 2));
98 const bool isSearchSuggestion(static_cast<AddressCompletionModel::CompletionEntry::EntryType>(index.data(AddressCompletionModel::TypeRole).toInt()) == AddressCompletionModel::CompletionEntry::SearchSuggestionType);
99
100 if (option.state.testFlag(QStyle::State_Selected))
101 {
102 painter->fillRect(option.rect, option.palette.color(QPalette::Highlight));
103
104 paintContext.palette.setColor(QPalette::Text, option.palette.color(QPalette::HighlightedText));
105 }
106 else if (!isSearchSuggestion)
107 {
108 paintContext.palette.setColor(QPalette::Text, option.palette.color(QPalette::Link));
109 }
110
111 QRect decorationRectangle(option.rect);
112
113 if (isRightToLeft)
114 {
115 decorationRectangle.setLeft(option.rect.width() - option.rect.height() - 5);
116
117 titleRectangle.setRight(option.rect.width() - option.rect.height() - 10);
118 }
119 else
120 {
121 decorationRectangle.setRight(option.rect.height());
122
123 titleRectangle.setLeft(option.rect.height());
124 }
125
126 decorationRectangle = decorationRectangle.marginsRemoved(QMargins(2, 2, 2, 2));
127
128 QIcon icon(index.data(Qt::DecorationRole).value<QIcon>());
129
130 if (icon.isNull())
131 {
132 icon = ThemesManager::createIcon(QLatin1String("tab"));
133 }
134
135 icon.paint(painter, decorationRectangle, option.decorationAlignment);
136
137 if (m_displayMode == ColumnsMode)
138 {
139 const int maxUrlWidth(option.rect.width() / 2);
140
141 url = option.fontMetrics.elidedText(url, Qt::ElideRight, (maxUrlWidth - 40));
142
143 painter->save();
144
145 if (isRightToLeft)
146 {
147 painter->translate((titleRectangle.right() - calculateLength(option, url)), topPosition);
148 }
149 else
150 {
151 painter->translate(titleRectangle.left(), topPosition);
152 }
153
154 document.setHtml(isSearchSuggestion ? url : highlightText(url));
155 document.documentLayout()->draw(painter, paintContext);
156
157 painter->restore();
158
159 if (!description.isEmpty())
160 {
161 painter->save();
162
163 description = option.fontMetrics.elidedText(description, (isRightToLeft ? Qt::ElideLeft : Qt::ElideRight), (maxUrlWidth - 10));
164
165 if (isRightToLeft)
166 {
167 titleRectangle.setRight(maxUrlWidth);
168
169 painter->translate((titleRectangle.right() - calculateLength(option, description)), topPosition);
170 }
171 else
172 {
173 titleRectangle.setLeft(maxUrlWidth);
174
175 painter->translate(titleRectangle.left(), topPosition);
176 }
177
178 document.setHtml(highlightText(description));
179
180 if (option.state.testFlag(QStyle::State_Selected))
181 {
182 document.documentLayout()->draw(painter, paintContext);
183 }
184 else
185 {
186 document.drawContents(painter);
187 }
188
189 painter->restore();
190 }
191
192 return;
193 }
194
195 painter->save();
196
197 url = option.fontMetrics.elidedText(url, Qt::ElideRight, (option.rect.width() - 40));
198
199 if (isRightToLeft)
200 {
201 painter->translate((titleRectangle.right() - calculateLength(option, url)), topPosition);
202 }
203 else
204 {
205 painter->translate(titleRectangle.left(), topPosition);
206 }
207
208 document.setHtml(isSearchSuggestion ? url : highlightText(url));
209 document.documentLayout()->draw(painter, paintContext);
210
211 painter->restore();
212
213 if (!description.isEmpty())
214 {
215 const int urlLength(calculateLength(option, url + QLatin1Char(' ')));
216
217 if ((urlLength + 40) < titleRectangle.width())
218 {
219 painter->save();
220
221 description = option.fontMetrics.elidedText(description, (isRightToLeft ? Qt::ElideLeft : Qt::ElideRight), (option.rect.width() - urlLength - 50));
222
223 if (isRightToLeft)
224 {
225 description.append(QLatin1String(" -"));
226
227 titleRectangle.setRight(option.rect.width() - calculateLength(option, description) - (urlLength + 33));
228
229 painter->translate(titleRectangle.right(), topPosition);
230 }
231 else
232 {
233 description.insert(0, QLatin1String("- "));
234
235 titleRectangle.setLeft(urlLength + 33);
236
237 painter->translate(titleRectangle.left(), topPosition);
238 }
239
240 document.setHtml(highlightText(description));
241
242 if (option.state.testFlag(QStyle::State_Selected))
243 {
244 document.documentLayout()->draw(painter, paintContext);
245 }
246 else
247 {
248 document.drawContents(painter);
249 }
250
251 painter->restore();
252 }
253 }
254 }
255
handleOptionChanged(int identifier,const QVariant & value)256 void AddressDelegate::handleOptionChanged(int identifier, const QVariant &value)
257 {
258 if (identifier == SettingsManager::AddressField_CompletionDisplayModeOption)
259 {
260 m_displayMode = ((value.toString() == QLatin1String("columns")) ? ColumnsMode : CompactMode);
261 }
262 }
263
highlightText(const QString & text,const QString & html) const264 QString AddressDelegate::highlightText(const QString &text, const QString &html) const
265 {
266 const int index(text.indexOf(m_highlight, 0, Qt::CaseInsensitive));
267
268 if (m_highlight.isEmpty() || index < 0)
269 {
270 return (html + text);
271 }
272
273 return highlightText(text.mid(index + m_highlight.length()), html + text.left(index) + QStringLiteral("<b>%1</b>").arg(text.mid(index, m_highlight.length())));
274 }
275
calculateLength(const QStyleOptionViewItem & option,const QString & text,int length) const276 int AddressDelegate::calculateLength(const QStyleOptionViewItem &option, const QString &text, int length) const
277 {
278 const int index(text.indexOf(m_highlight, 0, Qt::CaseInsensitive));
279
280 if (m_highlight.isEmpty() || index < 0)
281 {
282 return (length + option.fontMetrics.width(text));
283 }
284
285 length += option.fontMetrics.width(text.left(index));
286
287 QStyleOptionViewItem highlightedOption(option);
288 highlightedOption.font.setBold(true);
289
290 length += highlightedOption.fontMetrics.width(text.mid(index, m_highlight.length()));
291
292 return calculateLength(option, text.mid(index + m_highlight.length()), length);
293 }
294
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const295 QSize AddressDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
296 {
297 QSize size(index.data(Qt::SizeHintRole).toSize());
298
299 if (index.row() != 0 && static_cast<AddressCompletionModel::CompletionEntry::EntryType>(index.data(AddressCompletionModel::TypeRole).toInt()) == AddressCompletionModel::CompletionEntry::HeaderType)
300 {
301 size.setHeight(qRound(option.fontMetrics.lineSpacing() * 1.75));
302 }
303 else
304 {
305 size.setHeight(qRound(option.fontMetrics.lineSpacing() * 1.25));
306 }
307
308 return size;
309 }
310
AddressWidget(Window * window,QWidget * parent)311 AddressWidget::AddressWidget(Window *window, QWidget *parent) : LineEditWidget(parent),
312 m_window(nullptr),
313 m_completionModel(new AddressCompletionModel(this)),
314 m_clickedEntry(UnknownEntry),
315 m_hoveredEntry(UnknownEntry),
316 m_completionModes(NoCompletionMode),
317 m_hints(SessionsManager::DefaultOpen),
318 m_hasFeeds(false),
319 m_isNavigatingCompletion(false),
320 m_isUsingSimpleMode(false),
321 m_wasEdited(false)
322 {
323 const ToolBarWidget *toolBar(qobject_cast<ToolBarWidget*>(parent));
324
325 if (!toolBar)
326 {
327 m_isUsingSimpleMode = true;
328 }
329
330 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
331 setMinimumWidth(100);
332 setWindow(window);
333 updateCompletion(true);
334 handleOptionChanged(SettingsManager::AddressField_CompletionModeOption, SettingsManager::getOption(SettingsManager::AddressField_CompletionModeOption));
335 handleOptionChanged(SettingsManager::AddressField_DropActionOption, SettingsManager::getOption(SettingsManager::AddressField_DropActionOption));
336 handleOptionChanged(SettingsManager::AddressField_LayoutOption, SettingsManager::getOption(SettingsManager::AddressField_LayoutOption));
337 handleOptionChanged(SettingsManager::AddressField_SelectAllOnFocusOption, SettingsManager::getOption(SettingsManager::AddressField_SelectAllOnFocusOption));
338
339 if (toolBar)
340 {
341 setPlaceholderText(tr("Enter address or search…"));
342
343 connect(SettingsManager::getInstance(), &SettingsManager::optionChanged, this, &AddressWidget::handleOptionChanged);
344
345 if (toolBar->getDefinition().isGlobal())
346 {
347 connect(toolBar, &ToolBarWidget::windowChanged, this, &AddressWidget::setWindow);
348 }
349 }
350
351 connect(this, &AddressWidget::textEdited, this, [&]()
352 {
353 m_wasEdited = true;
354 });
355 connect(this, &AddressWidget::textDropped, this, [&](const QString &text)
356 {
357 handleUserInput(text);
358 });
359 connect(m_completionModel, &AddressCompletionModel::completionReady, this, &AddressWidget::setCompletion);
360 connect(BookmarksManager::getModel(), &BookmarksModel::modelModified, this, &AddressWidget::updateGeometries);
361 }
362
changeEvent(QEvent * event)363 void AddressWidget::changeEvent(QEvent *event)
364 {
365 LineEditWidget::changeEvent(event);
366
367 switch (event->type())
368 {
369 case QEvent::LanguageChange:
370 if (!m_isUsingSimpleMode)
371 {
372 setPlaceholderText(tr("Enter address or search…"));
373 }
374
375 break;
376 case QEvent::LayoutDirectionChange:
377 updateGeometries();
378
379 break;
380 default:
381 break;
382 }
383 }
384
paintEvent(QPaintEvent * event)385 void AddressWidget::paintEvent(QPaintEvent *event)
386 {
387 LineEditWidget::paintEvent(event);
388
389 QPainter painter(this);
390
391 if (m_entries.contains(HistoryDropdownEntry))
392 {
393 QStyleOption arrowOption;
394 arrowOption.initFrom(this);
395 arrowOption.rect = m_entries[HistoryDropdownEntry].rectangle;
396
397 if (HistoryManager::getTypedHistoryModel()->rowCount() == 0)
398 {
399 arrowOption.palette.setCurrentColorGroup(QPalette::Disabled);
400 }
401
402 style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOption, &painter, this);
403 }
404
405 if (m_isUsingSimpleMode)
406 {
407 return;
408 }
409
410 QHash<EntryIdentifier, EntryDefinition>::const_iterator iterator;
411
412 for (iterator = m_entries.begin(); iterator != m_entries.end(); ++iterator)
413 {
414 if (!iterator.value().icon.isNull())
415 {
416 iterator.value().icon.paint(&painter, iterator.value().rectangle, Qt::AlignCenter, ((iterator.key() == m_hoveredEntry) ? QIcon::Active : QIcon::Normal));
417 }
418 }
419 }
420
resizeEvent(QResizeEvent * event)421 void AddressWidget::resizeEvent(QResizeEvent *event)
422 {
423 LineEditWidget::resizeEvent(event);
424
425 updateGeometries();
426 }
427
focusInEvent(QFocusEvent * event)428 void AddressWidget::focusInEvent(QFocusEvent *event)
429 {
430 if (event->reason() == Qt::MouseFocusReason)
431 {
432 const EntryIdentifier entry(getEntry(mapFromGlobal(QCursor::pos())));
433
434 if (entry != UnknownEntry && entry != AddressEntry && entry != HistoryDropdownEntry)
435 {
436 Application::triggerAction(ActionsManager::ActivateContentAction, {}, this);
437
438 return;
439 }
440 }
441
442 LineEditWidget::focusInEvent(event);
443
444 activate(event->reason());
445 }
446
keyPressEvent(QKeyEvent * event)447 void AddressWidget::keyPressEvent(QKeyEvent *event)
448 {
449 switch (event->key())
450 {
451 case Qt::Key_Down:
452 if (!isPopupVisible() && HistoryManager::getTypedHistoryModel()->rowCount() > 0)
453 {
454 showCompletion(true);
455 }
456
457 break;
458 case Qt::Key_Enter:
459 case Qt::Key_Return:
460 if (!m_isUsingSimpleMode)
461 {
462 handleUserInput(text().trimmed(), SessionsManager::calculateOpenHints(SessionsManager::CurrentTabOpen, Qt::LeftButton, event->modifiers()));
463 }
464
465 break;
466 case Qt::Key_Escape:
467 if (isPopupVisible())
468 {
469 hidePopup();
470 }
471 else if (m_window)
472 {
473 const QUrl url(m_window->getUrl());
474 const QString text(this->text().trimmed());
475
476 if (text.isEmpty() || text != url.toString())
477 {
478 setText(Utils::isUrlEmpty(url) ? QString() : url.toString());
479
480 if (!text.isEmpty() && SettingsManager::getOption(SettingsManager::AddressField_SelectAllOnFocusOption).toBool())
481 {
482 selectAll();
483 }
484 }
485 else
486 {
487 m_window->setFocus();
488 }
489 }
490
491 break;
492 default:
493 break;
494 }
495
496 LineEditWidget::keyPressEvent(event);
497 }
498
contextMenuEvent(QContextMenuEvent * event)499 void AddressWidget::contextMenuEvent(QContextMenuEvent *event)
500 {
501 const EntryIdentifier entry(getEntry(event->pos()));
502 QMenu menu(this);
503
504 if (entry == UnknownEntry || entry == AddressEntry)
505 {
506 ActionExecutor::Object executor(this, this);
507
508 menu.addAction(new Action(ActionsManager::UndoAction, {}, executor, &menu));
509 menu.addAction(new Action(ActionsManager::RedoAction, {}, executor, &menu));
510 menu.addSeparator();
511 menu.addAction(new Action(ActionsManager::CutAction, {}, executor, &menu));
512 menu.addAction(new Action(ActionsManager::CopyAction, {}, executor, &menu));
513 menu.addAction(new Action(ActionsManager::PasteAction, {}, executor, &menu));
514
515 if (!m_isUsingSimpleMode)
516 {
517 menu.addAction(new Action(ActionsManager::PasteAndGoAction, {}, ActionExecutor::Object(m_window, m_window), this));
518 }
519
520 menu.addAction(new Action(ActionsManager::DeleteAction, {}, executor, &menu));
521 menu.addSeparator();
522 menu.addAction(new Action(ActionsManager::CopyToNoteAction, {}, executor, &menu));
523 menu.addSeparator();
524 menu.addAction(new Action(ActionsManager::ClearAllAction, {}, executor, &menu));
525 menu.addAction(new Action(ActionsManager::SelectAllAction, {}, executor, &menu));
526 }
527 else
528 {
529 const QUrl url(getUrl());
530
531 if (entry == WebsiteInformationEntry && !Utils::isUrlEmpty(url) && url.scheme() != QLatin1String("about"))
532 {
533 ActionExecutor::Object executor(m_window, m_window);
534
535 menu.addAction(new Action(ActionsManager::WebsiteInformationAction, {}, executor, &menu));
536 menu.addAction(new Action(ActionsManager::WebsitePreferencesAction, {}, executor, &menu));
537 menu.addSeparator();
538 }
539
540 menu.addAction(tr("Remove this Icon"), this, &AddressWidget::removeEntry)->setData(entry);
541 }
542
543 const ToolBarWidget *toolBar(qobject_cast<ToolBarWidget*>(parentWidget()));
544
545 if (toolBar)
546 {
547 menu.addSeparator();
548 menu.addMenu(ToolBarWidget::createCustomizationMenu(toolBar->getIdentifier(), {}, &menu));
549 }
550
551 menu.exec(event->globalPos());
552 }
553
mousePressEvent(QMouseEvent * event)554 void AddressWidget::mousePressEvent(QMouseEvent *event)
555 {
556 m_clickedEntry = ((event->button() == Qt::LeftButton) ? getEntry(event->pos()) : UnknownEntry);
557
558 if (m_clickedEntry == WebsiteInformationEntry || m_clickedEntry == FaviconEntry)
559 {
560 m_dragStartPosition = event->pos();
561 }
562 else
563 {
564 m_dragStartPosition = {};
565 }
566
567 LineEditWidget::mousePressEvent(event);
568 }
569
mouseMoveEvent(QMouseEvent * event)570 void AddressWidget::mouseMoveEvent(QMouseEvent *event)
571 {
572 const QUrl url(getUrl());
573 const EntryIdentifier entry(getEntry(event->pos()));
574
575 if (entry != m_hoveredEntry)
576 {
577 if (entry == UnknownEntry || entry == AddressEntry)
578 {
579 setCursor(Qt::IBeamCursor);
580 }
581 else
582 {
583 setCursor(Qt::ArrowCursor);
584 }
585
586 m_hoveredEntry = entry;
587
588 update();
589 }
590
591 if (event->buttons().testFlag(Qt::LeftButton) && !m_dragStartPosition.isNull() && (event->pos() - m_dragStartPosition).manhattanLength() >= QApplication::startDragDistance() && url.isValid())
592 {
593 Utils::startLinkDrag(url, (m_window ? m_window->getTitle() : QString()), ((m_window ? m_window->getIcon() : ThemesManager::createIcon(QLatin1String("tab"))).pixmap(16, 16)), this);
594 }
595 else
596 {
597 LineEditWidget::mouseMoveEvent(event);
598 }
599 }
600
mouseReleaseEvent(QMouseEvent * event)601 void AddressWidget::mouseReleaseEvent(QMouseEvent *event)
602 {
603 if (event->button() == Qt::LeftButton && m_clickedEntry == getEntry(event->pos()))
604 {
605 switch (m_clickedEntry)
606 {
607 case WebsiteInformationEntry:
608 if (m_window)
609 {
610 m_window->triggerAction(ActionsManager::WebsiteInformationAction);
611 }
612
613 event->accept();
614
615 return;
616 case ListFeedsEntry:
617 {
618 const QVector<WebWidget::LinkUrl> feeds((m_window && m_window->getLoadingState() == WebWidget::FinishedLoadingState && m_window->getWebWidget()) ? m_window->getWebWidget()->getFeeds() : QVector<WebWidget::LinkUrl>());
619
620 if (feeds.count() == 1 && m_window)
621 {
622 m_window->setUrl(QUrl(QLatin1String("view-feed:") + feeds.first().url.toDisplayString()));
623 }
624 else if (feeds.count() > 1)
625 {
626 QMenu menu;
627
628 for (int i = 0; i < feeds.count(); ++i)
629 {
630 menu.addAction(feeds.at(i).title.isEmpty() ? tr("(Untitled)") : feeds.at(i).title)->setData(QUrl(QLatin1String("view-feed:") + feeds.at(i).url.toDisplayString()));
631 }
632
633 connect(&menu, &QMenu::triggered, this, [&](QAction *action)
634 {
635 if (action && m_window)
636 {
637 m_window->setUrl(action->data().toUrl());
638 }
639 });
640
641 menu.exec(mapToGlobal(m_entries.value(ListFeedsEntry).rectangle.bottomLeft()));
642 }
643
644 event->accept();
645 }
646
647 return;
648 case BookmarkEntry:
649 {
650 const QUrl url(getUrl());
651
652 if (!Utils::isUrlEmpty(url) && url.scheme() != QLatin1String("about"))
653 {
654 if (BookmarksManager::hasBookmark(url))
655 {
656 const QVector<BookmarksModel::Bookmark*> bookmarks(BookmarksManager::getModel()->findUrls(url));
657
658 for (int i = 0; i < bookmarks.count(); ++i)
659 {
660 BookmarksManager::getModel()->trashBookmark(bookmarks.at(i));
661 }
662 }
663 else
664 {
665 QMenu menu;
666 QAction *addBookmarkAction(menu.addAction(tr("Add to Bookmarks"), [&]()
667 {
668 if (m_window)
669 {
670 BookmarkPropertiesDialog dialog(getUrl().adjusted(QUrl::RemovePassword), m_window->getTitle(), (m_window->getContentsWidget() ? m_window->getContentsWidget()->getDescription() : QString()), nullptr, -1, true, this);
671 dialog.exec();
672 }
673 }, ActionsManager::getActionShortcut(ActionsManager::BookmarkPageAction)));
674 addBookmarkAction->setShortcutContext(Qt::WidgetShortcut);
675
676 menu.addAction(tr("Add to Start Page"), [&]()
677 {
678 if (m_window)
679 {
680 BookmarksManager::addBookmark(BookmarksModel::UrlBookmark, {{BookmarksModel::UrlRole, getUrl().adjusted(QUrl::RemovePassword)}, {BookmarksModel::TitleRole, m_window->getTitle()}}, BookmarksManager::getModel()->getBookmarkByPath(SettingsManager::getOption(SettingsManager::StartPage_BookmarksFolderOption).toString()));
681 }
682 });
683 menu.exec(mapToGlobal(m_entries.value(BookmarkEntry).rectangle.bottomLeft()));
684 }
685
686 updateGeometries();
687 }
688
689 event->accept();
690 }
691
692 return;
693 case LoadPluginsEntry:
694 m_window->triggerAction(ActionsManager::LoadPluginsAction);
695
696 updateGeometries();
697
698 event->accept();
699
700 return;
701 case FillPasswordEntry:
702 m_window->triggerAction(ActionsManager::FillPasswordAction);
703
704 event->accept();
705
706 return;
707 case HistoryDropdownEntry:
708 if (!isPopupVisible() && HistoryManager::getTypedHistoryModel()->rowCount() > 0)
709 {
710 showCompletion(true);
711 }
712
713 break;
714 default:
715 break;
716 }
717 }
718
719 if (event->button() == Qt::MiddleButton && text().isEmpty() && !QApplication::clipboard()->text().isEmpty() && SettingsManager::getOption(SettingsManager::AddressField_PasteAndGoOnMiddleClickOption).toBool())
720 {
721 handleUserInput(QApplication::clipboard()->text().trimmed(), SessionsManager::CurrentTabOpen);
722
723 event->accept();
724 }
725
726 m_clickedEntry = UnknownEntry;
727
728 LineEditWidget::mouseReleaseEvent(event);
729 }
730
dragEnterEvent(QDragEnterEvent * event)731 void AddressWidget::dragEnterEvent(QDragEnterEvent *event)
732 {
733 if (event->mimeData()->hasUrls())
734 {
735 event->accept();
736 }
737
738 LineEditWidget::dragEnterEvent(event);
739 }
740
openUrl(const QString & url)741 void AddressWidget::openUrl(const QString &url)
742 {
743 setUrl(url);
744 handleUserInput(url, SessionsManager::CurrentTabOpen);
745 }
746
removeEntry()747 void AddressWidget::removeEntry()
748 {
749 const QAction *action(qobject_cast<QAction*>(sender()));
750
751 if (action)
752 {
753 QStringList layout(SettingsManager::getOption(SettingsManager::AddressField_LayoutOption).toStringList());
754 QString name(metaObject()->enumerator(m_entryIdentifierEnumerator).valueToKey(action->data().toInt()));
755
756 if (!name.isEmpty())
757 {
758 name.chop(5);
759 name[0] = name.at(0).toLower();
760
761 layout.removeAll(name);
762
763 SettingsManager::setOption(SettingsManager::AddressField_LayoutOption, layout);
764 }
765 }
766 }
767
showCompletion(bool isTypedHistory)768 void AddressWidget::showCompletion(bool isTypedHistory)
769 {
770 PopupViewWidget *popupWidget(getPopup());
771 popupWidget->setModel(m_completionModel);
772 popupWidget->setItemDelegate(new AddressDelegate((isTypedHistory ? QString() : text()), (isTypedHistory ? AddressDelegate::HistoryMode : AddressDelegate::CompletionMode), popupWidget));
773
774 updateCompletion(isTypedHistory);
775
776 if (!isPopupVisible())
777 {
778 connect(popupWidget, &PopupViewWidget::clicked, this, [&](const QModelIndex &index)
779 {
780 hidePopup();
781
782 if (index.isValid())
783 {
784 if (static_cast<AddressCompletionModel::CompletionEntry::EntryType>(index.data(AddressCompletionModel::TypeRole).toInt()) == AddressCompletionModel::CompletionEntry::SearchSuggestionType)
785 {
786 emit requestedSearch(index.data(AddressCompletionModel::TextRole).toString(), SearchEnginesManager::getSearchEngine(index.data(AddressCompletionModel::KeywordRole).toString(), true).identifier, SessionsManager::CurrentTabOpen);
787 }
788 else
789 {
790 const QString url(index.data(AddressCompletionModel::UrlRole).toUrl().toString());
791
792 setUrl(url);
793 handleUserInput(url, SessionsManager::CurrentTabOpen);
794 }
795 }
796 });
797 connect(popupWidget->selectionModel(), &QItemSelectionModel::currentChanged, this, [&](const QModelIndex &index)
798 {
799 if (m_isNavigatingCompletion)
800 {
801 m_isNavigatingCompletion = false;
802
803 setText(index.data(AddressCompletionModel::TextRole).toString());
804 }
805 });
806
807 showPopup();
808 }
809
810 popupWidget->setCurrentIndex(m_completionModel->index(0, 0));
811 popupWidget->setFocus();
812 }
813
handleOptionChanged(int identifier,const QVariant & value)814 void AddressWidget::handleOptionChanged(int identifier, const QVariant &value)
815 {
816 switch (identifier)
817 {
818 case SettingsManager::AddressField_CompletionModeOption:
819 {
820 const QString completionMode(value.toString());
821
822 if (completionMode == QLatin1String("inlineAndPopup"))
823 {
824 m_completionModes = (InlineCompletionMode | PopupCompletionMode);
825 }
826 else if (completionMode == QLatin1String("inline"))
827 {
828 m_completionModes = InlineCompletionMode;
829 }
830 else if (completionMode == QLatin1String("popup"))
831 {
832 m_completionModes = PopupCompletionMode;
833 }
834
835 disconnect(this, &AddressWidget::textEdited, m_completionModel, &AddressCompletionModel::setFilter);
836
837 if (m_completionModes != NoCompletionMode)
838 {
839 connect(this, &AddressWidget::textEdited, m_completionModel, &AddressCompletionModel::setFilter);
840 }
841 }
842
843 break;
844 case SettingsManager::AddressField_DropActionOption:
845 {
846 const QString dropAction(value.toString());
847
848 if (dropAction == QLatin1String("pasteAndGo"))
849 {
850 setDropMode(LineEditWidget::ReplaceAndNotifyDropMode);
851 }
852 else if (dropAction == QLatin1String("replace"))
853 {
854 setDropMode(LineEditWidget::ReplaceDropMode);
855 }
856 else
857 {
858 setDropMode(LineEditWidget::PasteDropMode);
859 }
860 }
861
862 break;
863 case SettingsManager::AddressField_SelectAllOnFocusOption:
864 setSelectAllOnFocus(value.toBool());
865
866 break;
867 case SettingsManager::AddressField_LayoutOption:
868 if (m_isUsingSimpleMode)
869 {
870 m_layout = {AddressEntry, HistoryDropdownEntry};
871 }
872 else
873 {
874 if (m_entryIdentifierEnumerator < 0)
875 {
876 m_entryIdentifierEnumerator = metaObject()->indexOfEnumerator("EntryIdentifier");
877 }
878
879 const QStringList rawLayout(value.toStringList());
880 QVector<EntryIdentifier> layout;
881 layout.reserve(rawLayout.count());
882
883 for (int i = 0; i < rawLayout.count(); ++i)
884 {
885 QString name(rawLayout.at(i) + QLatin1String("Entry"));
886 name[0] = name.at(0).toUpper();
887
888 const EntryIdentifier entryIdentifier(static_cast<EntryIdentifier>(metaObject()->enumerator(m_entryIdentifierEnumerator).keyToValue(name.toLatin1())));
889
890 if (entryIdentifier > UnknownEntry && !layout.contains(entryIdentifier))
891 {
892 layout.append(entryIdentifier);
893 }
894 }
895
896 if (!layout.contains(AddressEntry))
897 {
898 layout.prepend(AddressEntry);
899 }
900
901 m_layout = layout;
902 }
903
904 updateGeometries();
905
906 break;
907 default:
908 break;
909 }
910 }
911
handleActionsStateChanged(const QVector<int> & identifiers)912 void AddressWidget::handleActionsStateChanged(const QVector<int> &identifiers)
913 {
914 if (identifiers.contains(ActionsManager::LoadPluginsAction) && m_layout.contains(LoadPluginsEntry))
915 {
916 updateGeometries();
917 }
918 }
919
handleWatchedDataChanged(WebWidget::ChangeWatcher watcher)920 void AddressWidget::handleWatchedDataChanged(WebWidget::ChangeWatcher watcher)
921 {
922 if (watcher == WebWidget::FeedsWatcher)
923 {
924 m_hasFeeds = (m_window && m_window->getWebWidget() && !m_window->getWebWidget()->getFeeds().isEmpty());
925
926 updateGeometries();
927 }
928 }
929
handleLoadingStateChanged()930 void AddressWidget::handleLoadingStateChanged()
931 {
932 m_hasFeeds = (m_window && m_window->getWebWidget() && !m_window->getWebWidget()->getFeeds().isEmpty());
933
934 updateGeometries();
935 }
936
handleUserInput(const QString & text,SessionsManager::OpenHints hints)937 void AddressWidget::handleUserInput(const QString &text, SessionsManager::OpenHints hints)
938 {
939 if (m_isUsingSimpleMode)
940 {
941 return;
942 }
943
944 if (hints == SessionsManager::DefaultOpen)
945 {
946 hints = SessionsManager::calculateOpenHints(SessionsManager::CurrentTabOpen);
947 }
948
949 if (!text.isEmpty())
950 {
951 const InputInterpreter::InterpreterResult result(InputInterpreter::interpret(text));
952
953 if (result.isValid())
954 {
955 MainWindow *mainWindow(m_window ? MainWindow::findMainWindow(m_window) : MainWindow::findMainWindow(this));
956 ActionExecutor::Object executor(mainWindow, mainWindow);
957
958 switch (result.type)
959 {
960 case InputInterpreter::InterpreterResult::BookmarkType:
961 if (executor.isValid())
962 {
963 executor.triggerAction(ActionsManager::OpenBookmarkAction, {{QLatin1String("bookmark"), result.bookmark->getIdentifier()}, {QLatin1String("hints"), QVariant(hints)}});
964 }
965
966 break;
967 case InputInterpreter::InterpreterResult::UrlType:
968 if (executor.isValid())
969 {
970 executor.triggerAction(ActionsManager::OpenUrlAction, {{QLatin1String("url"), result.url}, {QLatin1String("hints"), QVariant(hints)}});
971 }
972
973 break;
974 case InputInterpreter::InterpreterResult::SearchType:
975 emit requestedSearch(result.searchQuery, result.searchEngine, hints);
976
977 break;
978 default:
979 break;
980 }
981 }
982 }
983 }
984
updateGeometries()985 void AddressWidget::updateGeometries()
986 {
987 QHash<EntryIdentifier, EntryDefinition> entries;
988 QVector<EntryDefinition> leadingEntries;
989 QVector<EntryDefinition> trailingEntries;
990 const int offset(qMax(((height() - 16) / 2), 2));
991 QMargins margins(offset, 0, offset, 0);
992 const QUrl url(getUrl());
993 int availableWidth(width() - margins.left() - margins.right());
994 const bool hasValidWindow(m_window && !m_window->isAboutToClose() && m_window->getLoadingState() == WebWidget::FinishedLoadingState);
995 bool isLeading(true);
996 const bool isRightToLeft(layoutDirection() == Qt::RightToLeft);
997
998 if (m_layout.contains(WebsiteInformationEntry))
999 {
1000 availableWidth -= 20;
1001 }
1002
1003 if (m_layout.contains(HistoryDropdownEntry))
1004 {
1005 availableWidth -= 16;
1006 }
1007
1008 if (isRightToLeft)
1009 {
1010 isLeading = false;
1011 }
1012
1013 for (int i = 0; i < m_layout.count(); ++i)
1014 {
1015 EntryDefinition definition;
1016 definition.identifier = m_layout.at(i);
1017
1018 switch (m_layout.at(i))
1019 {
1020 case AddressEntry:
1021 isLeading = !isLeading;
1022
1023 break;
1024 case WebsiteInformationEntry:
1025 {
1026 QString icon(QLatin1String("unknown"));
1027 const WebWidget::ContentStates state(m_window ? m_window->getContentState() : WebWidget::UnknownContentState);
1028
1029 if (state.testFlag(WebWidget::FraudContentState))
1030 {
1031 icon = QLatin1String("badge-fraud");
1032 }
1033 else if (state.testFlag(WebWidget::MixedContentState))
1034 {
1035 icon = QLatin1String("badge-mixed");
1036 }
1037 else if (state.testFlag(WebWidget::SecureContentState))
1038 {
1039 icon = QLatin1String("badge-secure");
1040 }
1041 else if (state.testFlag(WebWidget::RemoteContentState))
1042 {
1043 icon = QLatin1String("badge-remote");
1044 }
1045 else if (state.testFlag(WebWidget::LocalContentState))
1046 {
1047 icon = QLatin1String("badge-local");
1048 }
1049 else if (state.testFlag(WebWidget::ApplicationContentState))
1050 {
1051 icon = QLatin1String("otter-browser");
1052 }
1053
1054 if (!Utils::isUrlEmpty(url) && url.scheme() != QLatin1String("about"))
1055 {
1056 definition.title = QT_TR_NOOP("Show website information");
1057 }
1058
1059 definition.icon = ThemesManager::createIcon(icon, false);
1060 }
1061
1062 break;
1063 case FaviconEntry:
1064 definition.icon = (m_window ? m_window->getIcon() : ThemesManager::createIcon((SessionsManager::isPrivate() ? QLatin1String("tab-private") : QLatin1String("tab")), false));
1065
1066 break;
1067 case ListFeedsEntry:
1068 if (m_hasFeeds)
1069 {
1070 definition.title = QT_TR_NOOP("Show feed list");
1071 definition.icon = ThemesManager::createIcon(QLatin1String("application-rss+xml"), false);
1072 }
1073
1074 break;
1075 case BookmarkEntry:
1076 if (!Utils::isUrlEmpty(url) && url.scheme() != QLatin1String("about"))
1077 {
1078 if (BookmarksManager::hasBookmark(url))
1079 {
1080 definition.title = QT_TR_NOOP("Remove bookmark");
1081 definition.icon = ThemesManager::createIcon(QLatin1String("bookmark-page-remove"), false);
1082 }
1083 else
1084 {
1085 definition.title = QT_TR_NOOP("Add bookmark");
1086 definition.icon = ThemesManager::createIcon(QLatin1String("bookmark-page-new"), false);
1087 }
1088 }
1089
1090 break;
1091 case LoadPluginsEntry:
1092 if (hasValidWindow && m_window->getActionState(ActionsManager::LoadPluginsAction).isEnabled)
1093 {
1094 definition.title = QT_TR_NOOP("Load all plugins on the page");
1095 definition.icon = ThemesManager::createIcon(QLatin1String("preferences-plugin"), false);
1096 }
1097
1098 break;
1099 case FillPasswordEntry:
1100 if (hasValidWindow && !Utils::isUrlEmpty(url) && url.scheme() != QLatin1String("about") && PasswordsManager::hasPasswords(url, PasswordsManager::FormPassword))
1101 {
1102 definition.title = QT_TR_NOOP("Log in");
1103 definition.icon = ThemesManager::createIcon(QLatin1String("fill-password"), false);
1104 }
1105
1106 break;
1107 default:
1108 break;
1109 }
1110
1111 if (m_layout.at(i) != HistoryDropdownEntry && definition.icon.isNull())
1112 {
1113 continue;
1114 }
1115
1116 switch (m_layout.at(i))
1117 {
1118 case AddressEntry:
1119 case HistoryDropdownEntry:
1120 case WebsiteInformationEntry:
1121 break;
1122 default:
1123 availableWidth -= 20;
1124
1125 if (availableWidth < 100)
1126 {
1127 continue;
1128 }
1129
1130 break;
1131 }
1132
1133 if (isLeading)
1134 {
1135 if (isRightToLeft)
1136 {
1137 leadingEntries.prepend(definition);
1138 }
1139 else
1140 {
1141 leadingEntries.append(definition);
1142 }
1143 }
1144 else
1145 {
1146 if (isRightToLeft)
1147 {
1148 trailingEntries.append(definition);
1149 }
1150 else
1151 {
1152 trailingEntries.prepend(definition);
1153 }
1154 }
1155 }
1156
1157 for (int i = 0; i < leadingEntries.count(); ++i)
1158 {
1159 switch (leadingEntries.at(i).identifier)
1160 {
1161 case WebsiteInformationEntry:
1162 case FaviconEntry:
1163 case ListFeedsEntry:
1164 case BookmarkEntry:
1165 case LoadPluginsEntry:
1166 case FillPasswordEntry:
1167 leadingEntries[i].rectangle = QRect(margins.left(), ((height() - 16) / 2), 16, 16);
1168
1169 margins.setLeft(margins.left() + 20);
1170
1171 break;
1172 case HistoryDropdownEntry:
1173 leadingEntries[i].rectangle = QRect(margins.left(), 0, 14, height());
1174
1175 margins.setLeft(margins.left() + 16);
1176
1177 break;
1178 default:
1179 break;
1180 }
1181
1182 entries[leadingEntries.at(i).identifier] = leadingEntries.at(i);
1183 }
1184
1185 for (int i = 0; i < trailingEntries.count(); ++i)
1186 {
1187 switch (trailingEntries.at(i).identifier)
1188 {
1189 case WebsiteInformationEntry:
1190 case FaviconEntry:
1191 case ListFeedsEntry:
1192 case BookmarkEntry:
1193 case LoadPluginsEntry:
1194 case FillPasswordEntry:
1195 trailingEntries[i].rectangle = QRect((width() - margins.right() - 20), ((height() - 16) / 2), 16, 16);
1196
1197 margins.setRight(margins.right() + 20);
1198
1199 break;
1200 case HistoryDropdownEntry:
1201 trailingEntries[i].rectangle = QRect((width() - margins.right() - 14), 0, 14, height());
1202
1203 margins.setRight(margins.right() + 16);
1204
1205 break;
1206 default:
1207 break;
1208 }
1209
1210 entries[trailingEntries.at(i).identifier] = trailingEntries.at(i);
1211 }
1212
1213 m_entries = entries;
1214
1215 if (margins.left() > offset)
1216 {
1217 margins.setLeft(margins.left() - 2);
1218 }
1219
1220 if (margins.right() > offset)
1221 {
1222 margins.setRight(margins.right() + 2);
1223 }
1224
1225 setTextMargins(margins);
1226 }
1227
updateCompletion(bool isTypedHistory)1228 void AddressWidget::updateCompletion(bool isTypedHistory)
1229 {
1230 AddressCompletionModel::CompletionTypes types(AddressCompletionModel::UnknownCompletionType);
1231
1232 if (isTypedHistory)
1233 {
1234 types = AddressCompletionModel::TypedHistoryCompletionType;
1235 }
1236 else
1237 {
1238 if (SettingsManager::getOption(SettingsManager::AddressField_SuggestBookmarksOption).toBool())
1239 {
1240 types |= AddressCompletionModel::BookmarksCompletionType;
1241 }
1242
1243 if (SettingsManager::getOption(SettingsManager::AddressField_SuggestHistoryOption).toBool())
1244 {
1245 types |= AddressCompletionModel::HistoryCompletionType;
1246 }
1247
1248 if (!m_isUsingSimpleMode && SettingsManager::getOption(SettingsManager::AddressField_SuggestSearchOption).toBool())
1249 {
1250 types |= AddressCompletionModel::SearchSuggestionsCompletionType;
1251 }
1252
1253 if (SettingsManager::getOption(SettingsManager::AddressField_SuggestSpecialPagesOption).toBool())
1254 {
1255 types |= AddressCompletionModel::SpecialPagesCompletionType;
1256 }
1257
1258 if (SettingsManager::getOption(SettingsManager::AddressField_SuggestLocalPathsOption).toBool())
1259 {
1260 types |= AddressCompletionModel::LocalPathSuggestionsCompletionType;
1261 }
1262 }
1263
1264 m_completionModel->setTypes(types);
1265 }
1266
setCompletion(const QString & filter)1267 void AddressWidget::setCompletion(const QString &filter)
1268 {
1269 if (filter.isEmpty() || m_completionModel->rowCount() == 0)
1270 {
1271 hidePopup();
1272
1273 LineEditWidget::setCompletion({});
1274
1275 return;
1276 }
1277
1278 if (m_completionModes.testFlag(PopupCompletionMode))
1279 {
1280 showCompletion(false);
1281 }
1282
1283 if (m_completionModes.testFlag(InlineCompletionMode))
1284 {
1285 for (int i = 0; i < m_completionModel->rowCount(); ++i)
1286 {
1287 const QString matchedText(m_completionModel->index(i).data(AddressCompletionModel::MatchRole).toString());
1288
1289 if (!matchedText.isEmpty())
1290 {
1291 LineEditWidget::setCompletion(matchedText);
1292
1293 break;
1294 }
1295 }
1296 }
1297 }
1298
setWindow(Window * window)1299 void AddressWidget::setWindow(Window *window)
1300 {
1301 const MainWindow *mainWindow(MainWindow::findMainWindow(this));
1302
1303 if (m_window && !m_window->isAboutToClose() && (!sender() || sender() != m_window))
1304 {
1305 disconnect(this, &AddressWidget::requestedSearch, m_window.data(), &Window::requestedSearch);
1306 disconnect(m_window.data(), &Window::urlChanged, this, &AddressWidget::setUrl);
1307 disconnect(m_window.data(), &Window::iconChanged, this, &AddressWidget::setIcon);
1308 disconnect(m_window.data(), &Window::arbitraryActionsStateChanged, this, &AddressWidget::handleActionsStateChanged);
1309 disconnect(m_window.data(), &Window::contentStateChanged, this, &AddressWidget::updateGeometries);
1310 disconnect(m_window.data(), &Window::loadingStateChanged, this, &AddressWidget::handleLoadingStateChanged);
1311
1312 if (m_window->getWebWidget())
1313 {
1314 m_window->getWebWidget()->stopWatchingChanges(this, WebWidget::FeedsWatcher);
1315
1316 disconnect(m_window->getWebWidget(), &WebWidget::watchedDataChanged, this, &AddressWidget::handleWatchedDataChanged);
1317 }
1318 }
1319
1320 m_window = window;
1321
1322 if (window)
1323 {
1324 if (mainWindow)
1325 {
1326 disconnect(this, &AddressWidget::requestedSearch, mainWindow, &MainWindow::search);
1327 }
1328
1329 if (isVisible() && window->isActive() && Utils::isUrlEmpty(window->getUrl()))
1330 {
1331 const AddressWidget *addressWidget(qobject_cast<AddressWidget*>(QApplication::focusWidget()));
1332
1333 if (!addressWidget)
1334 {
1335 setFocus();
1336 }
1337 }
1338
1339 connect(this, &AddressWidget::requestedSearch, window, &Window::requestedSearch);
1340 connect(window, &Window::urlChanged, this, &AddressWidget::setUrl);
1341 connect(window, &Window::iconChanged, this, &AddressWidget::setIcon);
1342 connect(window, &Window::arbitraryActionsStateChanged, this, &AddressWidget::handleActionsStateChanged);
1343 connect(window, &Window::contentStateChanged, this, &AddressWidget::updateGeometries);
1344 connect(window, &Window::loadingStateChanged, this, &AddressWidget::handleLoadingStateChanged);
1345 connect(window, &Window::destroyed, this, [&](QObject *object)
1346 {
1347 if (qobject_cast<Window*>(object) == m_window)
1348 {
1349 setWindow(nullptr);
1350 }
1351 });
1352
1353 if (window->getWebWidget())
1354 {
1355 window->getWebWidget()->startWatchingChanges(this, WebWidget::FeedsWatcher);
1356
1357 connect(window->getWebWidget(), &WebWidget::watchedDataChanged, this, &AddressWidget::handleWatchedDataChanged);
1358 }
1359
1360 const ToolBarWidget *toolBar(qobject_cast<ToolBarWidget*>(parentWidget()));
1361
1362 if (!toolBar || toolBar->getDefinition().isGlobal())
1363 {
1364 connect(window, &Window::aboutToClose, this, [&]()
1365 {
1366 setWindow(nullptr);
1367 });
1368 }
1369 }
1370 else if (mainWindow && !mainWindow->isAboutToClose() && !m_isUsingSimpleMode)
1371 {
1372 connect(this, &AddressWidget::requestedSearch, mainWindow, &MainWindow::search);
1373 }
1374
1375 setIcon(window ? window->getIcon() : QIcon());
1376 setUrl(window ? window->getUrl() : QUrl());
1377 update();
1378 }
1379
setUrl(const QUrl & url,bool force)1380 void AddressWidget::setUrl(const QUrl &url, bool force)
1381 {
1382 const QString text(Utils::isUrlEmpty(url) ? QString() : url.toString());
1383
1384 if (!m_isUsingSimpleMode)
1385 {
1386 updateGeometries();
1387 }
1388
1389 if (m_isUsingSimpleMode || ((force || !m_wasEdited || !hasFocus()) && url.scheme() != QLatin1String("javascript")))
1390 {
1391 setToolTip(text);
1392 setText(text);
1393 setCursorPosition(0);
1394
1395 m_wasEdited = false;
1396 }
1397 }
1398
setIcon(const QIcon & icon)1399 void AddressWidget::setIcon(const QIcon &icon)
1400 {
1401 if (m_layout.contains(FaviconEntry))
1402 {
1403 m_entries[FaviconEntry].icon = (icon.isNull() ? ThemesManager::createIcon((SessionsManager::isPrivate() ? QLatin1String("tab-private") : QLatin1String("tab")), false) : icon);
1404
1405 update();
1406 }
1407 }
1408
getUrl() const1409 QUrl AddressWidget::getUrl() const
1410 {
1411 return (m_window ? m_window->getUrl() : QUrl(QLatin1String("about:blank")));
1412 }
1413
getEntry(const QPoint & position) const1414 AddressWidget::EntryIdentifier AddressWidget::getEntry(const QPoint &position) const
1415 {
1416 QHash<EntryIdentifier, EntryDefinition>::const_iterator iterator;
1417
1418 for (iterator = m_entries.begin(); iterator != m_entries.end(); ++iterator)
1419 {
1420 if (iterator.value().rectangle.contains(position))
1421 {
1422 return iterator.key();
1423 }
1424 }
1425
1426 return UnknownEntry;
1427 }
1428
event(QEvent * event)1429 bool AddressWidget::event(QEvent *event)
1430 {
1431 if (event->type() == QEvent::ToolTip)
1432 {
1433 const QHelpEvent *helpEvent(static_cast<QHelpEvent*>(event));
1434 const EntryIdentifier entry(getEntry(helpEvent->pos()));
1435
1436 if (entry != UnknownEntry && entry != AddressEntry)
1437 {
1438 QString toolTip;
1439 QKeySequence shortcut;
1440 const QString title(m_entries[entry].title);
1441
1442 if (!title.isEmpty())
1443 {
1444 toolTip = tr(title.toUtf8().constData());
1445 }
1446
1447 switch (entry)
1448 {
1449 case HistoryDropdownEntry:
1450 shortcut = ActionsManager::getActionShortcut(ActionsManager::ActivateAddressFieldAction, {{QLatin1String("showTypedHistoryDropdown"), true}});
1451
1452 break;
1453 case WebsiteInformationEntry:
1454 shortcut = ActionsManager::getActionShortcut(ActionsManager::WebsiteInformationAction);
1455
1456 break;
1457 default:
1458 break;
1459 }
1460
1461 if (!shortcut.isEmpty())
1462 {
1463 if (!toolTip.isEmpty())
1464 {
1465 toolTip.append(QLatin1Char(' '));
1466 }
1467
1468 toolTip.append(QLatin1Char('(') + shortcut.toString(QKeySequence::NativeText) + QLatin1Char(')'));
1469 }
1470
1471 if (!toolTip.isEmpty())
1472 {
1473 QToolTip::showText(helpEvent->globalPos(), toolTip);
1474
1475 return true;
1476 }
1477 }
1478 }
1479
1480 return LineEditWidget::event(event);
1481 }
1482
1483 }
1484