basic_click_handlers.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include "ui/basic_click_handlers.h"
  8. #include "ui/widgets/tooltip.h"
  9. #include "ui/text/text_entity.h"
  10. #include "ui/integration.h"
  11. #include "base/qthelp_url.h"
  12. #include "base/qt/qt_string_view.h"
  13. #include <QtCore/QUrl>
  14. #include <QtCore/QRegularExpression>
  15. #include <QtGui/QDesktopServices>
  16. #include <QtGui/QGuiApplication>
  17. QString TextClickHandler::readable() const {
  18. const auto result = url();
  19. return !result.startsWith(qstr("internal:"))
  20. ? result
  21. : result.startsWith(qstr("internal:url:"))
  22. ? result.mid(qstr("internal:url:").size())
  23. : QString();
  24. }
  25. UrlClickHandler::UrlClickHandler(const QString &url, bool fullDisplayed)
  26. : TextClickHandler(fullDisplayed)
  27. , _originalUrl(url) {
  28. if (isEmail()) {
  29. _readable = _originalUrl;
  30. } else if (!_originalUrl.startsWith(qstr("internal:"))) {
  31. const auto original = QUrl(_originalUrl);
  32. const auto good = QUrl(original.isValid()
  33. ? original.toEncoded()
  34. : QString());
  35. _readable = good.isValid() ? good.toDisplayString() : _originalUrl;
  36. } else if (_originalUrl.startsWith(qstr("internal:url:"))) {
  37. const auto external = _originalUrl.mid(qstr("internal:url:").size());
  38. const auto original = QUrl(external);
  39. const auto good = QUrl(original.isValid()
  40. ? original.toEncoded()
  41. : QString());
  42. _readable = good.isValid() ? good.toDisplayString() : external;
  43. }
  44. }
  45. QString UrlClickHandler::copyToClipboardContextItemText() const {
  46. return isEmail()
  47. ? Ui::Integration::Instance().phraseContextCopyEmail()
  48. : Ui::Integration::Instance().phraseContextCopyLink();
  49. }
  50. QString UrlClickHandler::EncodeForOpening(const QString &originalUrl) {
  51. if (IsEmail(originalUrl)) {
  52. return originalUrl;
  53. }
  54. static const auto TonExp = QRegularExpression(u"^[^/@:]+\\.ton($|/)"_q);
  55. if (TonExp.match(originalUrl.toLower()).hasMatch()) {
  56. return u"tonsite://"_q + originalUrl;
  57. }
  58. const auto u = QUrl(originalUrl);
  59. const auto good = QUrl(u.isValid() ? u.toEncoded() : QString());
  60. const auto result = good.isValid()
  61. ? QString::fromUtf8(good.toEncoded())
  62. : originalUrl;
  63. static const auto RegExp = QRegularExpression(u"^[a-zA-Z]+:"_q);
  64. if (!result.isEmpty()
  65. && !RegExp.match(result).hasMatch()) {
  66. // No protocol.
  67. return u"https://"_q + result;
  68. }
  69. return result;
  70. }
  71. void UrlClickHandler::Open(QString url, QVariant context) {
  72. Ui::Tooltip::Hide();
  73. if (!Ui::Integration::Instance().handleUrlClick(url, context)
  74. && !url.isEmpty()) {
  75. if (IsEmail(url)) {
  76. url = "mailto: " + url;
  77. }
  78. QDesktopServices::openUrl(url);
  79. }
  80. }
  81. bool UrlClickHandler::IsSuspicious(const QString &url) {
  82. static const auto Check1 = QRegularExpression(
  83. "^((https?|s?ftp)://)?([^/#\\:]+)([/#\\:]|$)",
  84. QRegularExpression::CaseInsensitiveOption);
  85. const auto match1 = Check1.match(url);
  86. if (!match1.hasMatch()) {
  87. return false;
  88. }
  89. const auto domain = match1.capturedView(3);
  90. static const auto Check2 = QRegularExpression("^(.*)\\.[a-zA-Z]+$");
  91. const auto match2 = Check2.match(domain);
  92. if (!match2.hasMatch()) {
  93. return false;
  94. }
  95. const auto part = match2.capturedView(1);
  96. static const auto Check3 = QRegularExpression("[^a-zA-Z0-9\\.\\-]");
  97. return Check3.match(part).hasMatch();
  98. }
  99. QString UrlClickHandler::ShowEncoded(const QString &url) {
  100. if (const auto u = QUrl(url); u.isValid()) {
  101. return QString::fromUtf8(u.toEncoded());
  102. }
  103. static const auto Check1 = QRegularExpression(
  104. "^(https?://)?([^/#\\:]+)([/#\\:]|$)",
  105. QRegularExpression::CaseInsensitiveOption);
  106. if (const auto match1 = Check1.match(url); match1.hasMatch()) {
  107. const auto domain = match1.captured(1).append(match1.capturedView(2));
  108. if (const auto u = QUrl(domain); u.isValid()) {
  109. return QString(
  110. ).append(QString::fromUtf8(u.toEncoded())
  111. ).append(base::StringViewMid(url, match1.capturedEnd(2)));
  112. }
  113. }
  114. return url;
  115. }
  116. auto UrlClickHandler::getTextEntity() const -> TextEntity {
  117. const auto type = isEmail() ? EntityType::Email : EntityType::Url;
  118. return { type, _originalUrl };
  119. }