LocationEdit.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * Copyright (c) 2023, Cameron Youell <cameronyouell@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "LocationEdit.h"
  7. #include "Settings.h"
  8. #include "StringUtils.h"
  9. #include <AK/URL.h>
  10. #include <LibWebView/URL.h>
  11. #include <QApplication>
  12. #include <QPalette>
  13. #include <QTextLayout>
  14. #include <QTimer>
  15. namespace Ladybird {
  16. LocationEdit::LocationEdit(QWidget* parent)
  17. : QLineEdit(parent)
  18. {
  19. setPlaceholderText("Search or enter web address");
  20. m_autocomplete = make<AutoComplete>(this);
  21. this->setCompleter(m_autocomplete);
  22. connect(m_autocomplete, &AutoComplete::activated, [&](QModelIndex const&) {
  23. emit returnPressed();
  24. });
  25. connect(this, &QLineEdit::returnPressed, [&] {
  26. clearFocus();
  27. Optional<String> search_engine_url;
  28. if (Settings::the()->enable_search()) {
  29. auto search_engine = Settings::the()->search_engine();
  30. search_engine_url = MUST(ak_string_from_qstring(search_engine.url));
  31. }
  32. auto query = MUST(ak_string_from_qstring(text()));
  33. if (auto url = WebView::sanitize_url(query, search_engine_url.map([](auto& value) { return value.bytes_as_string_view(); })); url.has_value())
  34. setText(qstring_from_ak_deprecated_string(url->serialize()));
  35. });
  36. connect(this, &QLineEdit::textEdited, [this] {
  37. if (!Settings::the()->enable_autocomplete()) {
  38. m_autocomplete->clear_suggestions();
  39. return;
  40. }
  41. auto cursor_position = cursorPosition();
  42. auto result = m_autocomplete->get_search_suggestions(ak_deprecated_string_from_qstring(text()));
  43. if (result.is_error()) {
  44. dbgln("LocationEdit::textEdited: get_search_suggestions failed: {}", result.error());
  45. return;
  46. }
  47. setCursorPosition(cursor_position);
  48. });
  49. connect(this, &QLineEdit::textChanged, this, &LocationEdit::highlight_location);
  50. }
  51. void LocationEdit::focusInEvent(QFocusEvent* event)
  52. {
  53. QLineEdit::focusInEvent(event);
  54. highlight_location();
  55. QTimer::singleShot(0, this, &QLineEdit::selectAll);
  56. }
  57. void LocationEdit::focusOutEvent(QFocusEvent* event)
  58. {
  59. QLineEdit::focusOutEvent(event);
  60. highlight_location();
  61. }
  62. void LocationEdit::highlight_location()
  63. {
  64. auto url = AK::URL::create_with_url_or_path(ak_deprecated_string_from_qstring(text()));
  65. auto darkened_text_color = QPalette().color(QPalette::Text);
  66. darkened_text_color.setAlpha(127);
  67. QList<QInputMethodEvent::Attribute> attributes;
  68. if (url.is_valid() && !hasFocus()) {
  69. if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "gemini") {
  70. int host_start = (url.scheme().bytes_as_string_view().length() + 3) - cursorPosition();
  71. auto host_length = url.serialized_host().release_value_but_fixme_should_propagate_errors().bytes().size();
  72. // FIXME: Maybe add a generator to use https://publicsuffix.org/list/public_suffix_list.dat
  73. // for now just highlight the whole host
  74. QTextCharFormat defaultFormat;
  75. defaultFormat.setForeground(darkened_text_color);
  76. attributes.append({
  77. QInputMethodEvent::TextFormat,
  78. -cursorPosition(),
  79. static_cast<int>(text().length()),
  80. defaultFormat,
  81. });
  82. QTextCharFormat hostFormat;
  83. hostFormat.setForeground(QPalette().color(QPalette::Text));
  84. attributes.append({
  85. QInputMethodEvent::TextFormat,
  86. host_start,
  87. static_cast<int>(host_length),
  88. hostFormat,
  89. });
  90. } else if (url.scheme() == "file") {
  91. QTextCharFormat schemeFormat;
  92. schemeFormat.setForeground(darkened_text_color);
  93. attributes.append({
  94. QInputMethodEvent::TextFormat,
  95. -cursorPosition(),
  96. static_cast<int>(url.scheme().bytes_as_string_view().length() + 3),
  97. schemeFormat,
  98. });
  99. }
  100. }
  101. QInputMethodEvent event(QString(), attributes);
  102. QCoreApplication::sendEvent(this, &event);
  103. }
  104. }