#ifndef CLIPBOARDURL_H #define CLIPBOARDURL_H #include #include #include #ifndef QT_NO_DEBUG #include #endif namespace ClipboardUrl { inline QUrl parseText(const QString &text) { QString urlText = text.trimmed(); #ifndef QT_NO_DEBUG qDebug() << "[clipboard] raw text:" << text << "UTF-8 hex:" << text.toUtf8().toHex(); #endif if (urlText.size() >= 2) { const QChar first = urlText.front(); const QChar last = urlText.back(); if ((first == '\'' && last == '\'') || (first == '"' && last == '"') || (first == '<' && last == '>')) urlText = urlText.mid(1, urlText.size() - 2).trimmed(); } static const QRegularExpression markdownLink( QStringLiteral("\\A\\[[^\\r\\n]*\\]\\((https?://[^\\r\\n]+)\\)\\z"), QRegularExpression::CaseInsensitiveOption); const auto match = markdownLink.match(urlText); if (match.hasMatch()) urlText = match.captured(1); const QUrl url = QUrl::fromUserInput(urlText); #ifndef QT_NO_DEBUG qDebug() << "[clipboard] normalized text:" << urlText << "parsed URL:" << url << "valid:" << url.isValid() << "scheme:" << url.scheme() << "host:" << url.host() << "parse error:" << url.errorString(); #endif if (!url.isValid() || url.scheme().isEmpty() || url.host().isEmpty()) return QUrl(); return url; } inline QUrl fromMimeData(const QMimeData *mimeData) { if (mimeData == nullptr) { #ifndef QT_NO_DEBUG qDebug() << "[clipboard] MIME data unavailable"; #endif return QUrl(); } const auto urls = mimeData->urls(); #ifndef QT_NO_DEBUG qDebug() << "[clipboard] MIME formats:" << mimeData->formats() << "URL entries:" << urls; #endif if (urls.size() == 1) { const QUrl url = urls.first(); if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) { #ifndef QT_NO_DEBUG qDebug() << "[clipboard] using MIME URL:" << url; #endif return url; } } return parseText(mimeData->text()); } }// namespace ClipboardUrl #endif// CLIPBOARDURL_H