Allow passing std::any context to link creation method.
This commit is contained in:
parent
771f702056
commit
ab61721a13
7 changed files with 72 additions and 87 deletions
|
|
@ -158,8 +158,10 @@ void ActivateClickHandler(
|
||||||
not_null<QWidget*> guard,
|
not_null<QWidget*> guard,
|
||||||
ClickHandlerPtr handler,
|
ClickHandlerPtr handler,
|
||||||
ClickContext context) {
|
ClickContext context) {
|
||||||
crl::on_main(guard, [=] {
|
crl::on_main(guard, [=, weak = std::weak_ptr<ClickHandler>(handler)] {
|
||||||
handler->onClick(context);
|
if (const auto strong = weak.lock()) {
|
||||||
|
strong->onClick(context);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ protected:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EntityType;
|
enum class EntityType : uchar;
|
||||||
class ClickHandler {
|
class ClickHandler {
|
||||||
public:
|
public:
|
||||||
virtual ~ClickHandler() {
|
virtual ~ClickHandler() {
|
||||||
|
|
|
||||||
|
|
@ -43,14 +43,19 @@ void Integration::startFontsEnd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClickHandler> Integration::createLinkHandler(
|
std::shared_ptr<ClickHandler> Integration::createLinkHandler(
|
||||||
EntityType type,
|
const EntityLinkData &data,
|
||||||
const QString &text,
|
const std::any &context) {
|
||||||
const QString &data,
|
switch (data.type) {
|
||||||
const TextParseOptions &options) {
|
|
||||||
switch (type) {
|
|
||||||
case EntityType::CustomUrl:
|
case EntityType::CustomUrl:
|
||||||
return !data.isEmpty()
|
return !data.data.isEmpty()
|
||||||
? std::make_shared<UrlClickHandler>(data, false)
|
? std::make_shared<UrlClickHandler>(data.data, false)
|
||||||
|
: nullptr;
|
||||||
|
case EntityType::Email:
|
||||||
|
case EntityType::Url:
|
||||||
|
return !data.data.isEmpty()
|
||||||
|
? std::make_shared<UrlClickHandler>(
|
||||||
|
data.data,
|
||||||
|
data.shown == EntityLinkShown::Full)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include "base/basic_types.h"
|
#include "base/basic_types.h"
|
||||||
|
|
||||||
|
#include <any>
|
||||||
|
|
||||||
// Methods that must be implemented outside lib_ui.
|
// Methods that must be implemented outside lib_ui.
|
||||||
|
|
||||||
class QString;
|
class QString;
|
||||||
|
|
@ -16,7 +18,7 @@ class QVariant;
|
||||||
|
|
||||||
struct TextParseOptions;
|
struct TextParseOptions;
|
||||||
class ClickHandler;
|
class ClickHandler;
|
||||||
enum class EntityType;
|
struct EntityLinkData;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace Emoji {
|
namespace Emoji {
|
||||||
|
|
@ -43,10 +45,8 @@ public:
|
||||||
virtual void startFontsEnd();
|
virtual void startFontsEnd();
|
||||||
|
|
||||||
[[nodiscard]] virtual std::shared_ptr<ClickHandler> createLinkHandler(
|
[[nodiscard]] virtual std::shared_ptr<ClickHandler> createLinkHandler(
|
||||||
EntityType type,
|
const EntityLinkData &data,
|
||||||
const QString &text,
|
const std::any &context);
|
||||||
const QString &data,
|
|
||||||
const TextParseOptions &options);
|
|
||||||
[[nodiscard]] virtual bool handleUrlClick(
|
[[nodiscard]] virtual bool handleUrlClick(
|
||||||
const QString &url,
|
const QString &url,
|
||||||
const QVariant &context);
|
const QVariant &context);
|
||||||
|
|
|
||||||
105
ui/text/text.cpp
105
ui/text/text.cpp
|
|
@ -263,33 +263,18 @@ public:
|
||||||
Parser(
|
Parser(
|
||||||
not_null<String*> string,
|
not_null<String*> string,
|
||||||
const QString &text,
|
const QString &text,
|
||||||
const TextParseOptions &options);
|
const TextParseOptions &options,
|
||||||
|
const std::any &context);
|
||||||
Parser(
|
Parser(
|
||||||
not_null<String*> string,
|
not_null<String*> string,
|
||||||
const TextWithEntities &textWithEntities,
|
const TextWithEntities &textWithEntities,
|
||||||
const TextParseOptions &options);
|
const TextParseOptions &options,
|
||||||
|
const std::any &context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ReadyToken {
|
struct ReadyToken {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LinkDisplayStatus {
|
|
||||||
LinkDisplayedFull,
|
|
||||||
LinkDisplayedElided,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TextLinkData {
|
|
||||||
TextLinkData() = default;
|
|
||||||
TextLinkData(
|
|
||||||
EntityType type,
|
|
||||||
const QString &text,
|
|
||||||
const QString &data,
|
|
||||||
LinkDisplayStatus displayStatus);
|
|
||||||
EntityType type = EntityType::Invalid;
|
|
||||||
QString text, data;
|
|
||||||
LinkDisplayStatus displayStatus = LinkDisplayedFull;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StartedEntity {
|
class StartedEntity {
|
||||||
public:
|
public:
|
||||||
explicit StartedEntity(TextBlockFlags flags);
|
explicit StartedEntity(TextBlockFlags flags);
|
||||||
|
|
@ -307,6 +292,7 @@ private:
|
||||||
not_null<String*> string,
|
not_null<String*> string,
|
||||||
TextWithEntities &&source,
|
TextWithEntities &&source,
|
||||||
const TextParseOptions &options,
|
const TextParseOptions &options,
|
||||||
|
const std::any &context,
|
||||||
ReadyToken);
|
ReadyToken);
|
||||||
|
|
||||||
void trimSourceRange();
|
void trimSourceRange();
|
||||||
|
|
@ -336,14 +322,11 @@ private:
|
||||||
void computeLinkText(
|
void computeLinkText(
|
||||||
const QString &linkData,
|
const QString &linkData,
|
||||||
QString *outLinkText,
|
QString *outLinkText,
|
||||||
LinkDisplayStatus *outDisplayStatus);
|
EntityLinkShown *outShown);
|
||||||
|
|
||||||
static ClickHandlerPtr CreateHandlerForLink(
|
|
||||||
const TextLinkData &link,
|
|
||||||
const TextParseOptions &options);
|
|
||||||
|
|
||||||
const not_null<String*> _t;
|
const not_null<String*> _t;
|
||||||
const TextWithEntities _source;
|
const TextWithEntities _source;
|
||||||
|
const std::any &_context;
|
||||||
const QChar * const _start = nullptr;
|
const QChar * const _start = nullptr;
|
||||||
const QChar *_end = nullptr; // mutable, because we trim by decrementing.
|
const QChar *_end = nullptr; // mutable, because we trim by decrementing.
|
||||||
const QChar *_ptr = nullptr;
|
const QChar *_ptr = nullptr;
|
||||||
|
|
@ -355,7 +338,7 @@ private:
|
||||||
const QFixed _stopAfterWidth; // summary width of all added words
|
const QFixed _stopAfterWidth; // summary width of all added words
|
||||||
const bool _checkTilde = false; // do we need a special text block for tilde symbol
|
const bool _checkTilde = false; // do we need a special text block for tilde symbol
|
||||||
|
|
||||||
std::vector<TextLinkData> _links;
|
std::vector<EntityLinkData> _links;
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
const QChar*,
|
const QChar*,
|
||||||
std::vector<StartedEntity>> _startedEntities;
|
std::vector<StartedEntity>> _startedEntities;
|
||||||
|
|
@ -379,17 +362,6 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Parser::TextLinkData::TextLinkData(
|
|
||||||
EntityType type,
|
|
||||||
const QString &text,
|
|
||||||
const QString &data,
|
|
||||||
LinkDisplayStatus displayStatus)
|
|
||||||
: type(type)
|
|
||||||
, text(text)
|
|
||||||
, data(data)
|
|
||||||
, displayStatus(displayStatus) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Parser::StartedEntity::StartedEntity(TextBlockFlags flags) : _value(flags) {
|
Parser::StartedEntity::StartedEntity(TextBlockFlags flags) : _value(flags) {
|
||||||
Expects(_value >= 0 && _value < int(kStringLinkIndexShift));
|
Expects(_value >= 0 && _value < int(kStringLinkIndexShift));
|
||||||
}
|
}
|
||||||
|
|
@ -415,22 +387,26 @@ std::optional<uint16> Parser::StartedEntity::lnkIndex() const {
|
||||||
Parser::Parser(
|
Parser::Parser(
|
||||||
not_null<String*> string,
|
not_null<String*> string,
|
||||||
const QString &text,
|
const QString &text,
|
||||||
const TextParseOptions &options)
|
const TextParseOptions &options,
|
||||||
|
const std::any &context)
|
||||||
: Parser(
|
: Parser(
|
||||||
string,
|
string,
|
||||||
PrepareRichFromPlain(text, options),
|
PrepareRichFromPlain(text, options),
|
||||||
options,
|
options,
|
||||||
|
context,
|
||||||
ReadyToken()) {
|
ReadyToken()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser::Parser(
|
Parser::Parser(
|
||||||
not_null<String*> string,
|
not_null<String*> string,
|
||||||
const TextWithEntities &textWithEntities,
|
const TextWithEntities &textWithEntities,
|
||||||
const TextParseOptions &options)
|
const TextParseOptions &options,
|
||||||
|
const std::any &context)
|
||||||
: Parser(
|
: Parser(
|
||||||
string,
|
string,
|
||||||
PrepareRichFromRich(textWithEntities, options),
|
PrepareRichFromRich(textWithEntities, options),
|
||||||
options,
|
options,
|
||||||
|
context,
|
||||||
ReadyToken()) {
|
ReadyToken()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,9 +414,11 @@ Parser::Parser(
|
||||||
not_null<String*> string,
|
not_null<String*> string,
|
||||||
TextWithEntities &&source,
|
TextWithEntities &&source,
|
||||||
const TextParseOptions &options,
|
const TextParseOptions &options,
|
||||||
|
const std::any &context,
|
||||||
ReadyToken)
|
ReadyToken)
|
||||||
: _t(string)
|
: _t(string)
|
||||||
, _source(std::move(source))
|
, _source(std::move(source))
|
||||||
|
, _context(context)
|
||||||
, _start(_source.text.constData())
|
, _start(_source.text.constData())
|
||||||
, _end(_start + _source.text.size())
|
, _end(_start + _source.text.size())
|
||||||
, _ptr(_start)
|
, _ptr(_start)
|
||||||
|
|
@ -552,7 +530,7 @@ bool Parser::checkEntities() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto flags = TextBlockFlags();
|
auto flags = TextBlockFlags();
|
||||||
auto link = TextLinkData();
|
auto link = EntityLinkData();
|
||||||
const auto entityType = _waitingEntity->type();
|
const auto entityType = _waitingEntity->type();
|
||||||
const auto entityLength = _waitingEntity->length();
|
const auto entityLength = _waitingEntity->length();
|
||||||
const auto entityBegin = _start + _waitingEntity->offset();
|
const auto entityBegin = _start + _waitingEntity->offset();
|
||||||
|
|
@ -584,7 +562,7 @@ bool Parser::checkEntities() {
|
||||||
link.type = entityType;
|
link.type = entityType;
|
||||||
link.data = QString(entityBegin, entityLength);
|
link.data = QString(entityBegin, entityLength);
|
||||||
if (link.type == EntityType::Url) {
|
if (link.type == EntityType::Url) {
|
||||||
computeLinkText(link.data, &link.text, &link.displayStatus);
|
computeLinkText(link.data, &link.text, &link.shown);
|
||||||
} else {
|
} else {
|
||||||
link.text = link.data;
|
link.text = link.data;
|
||||||
}
|
}
|
||||||
|
|
@ -745,7 +723,10 @@ bool Parser::readCommand() {
|
||||||
case TextCommandLinkText: {
|
case TextCommandLinkText: {
|
||||||
createBlock();
|
createBlock();
|
||||||
int32 len = _ptr->unicode();
|
int32 len = _ptr->unicode();
|
||||||
_links.emplace_back(EntityType::CustomUrl, QString(), QString(++_ptr, len), LinkDisplayedFull);
|
_links.push_back(EntityLinkData{
|
||||||
|
.data = QString(++_ptr, len),
|
||||||
|
.type = EntityType::CustomUrl
|
||||||
|
});
|
||||||
_lnkIndex = kStringLinkIndexShift + _links.size();
|
_lnkIndex = kStringLinkIndexShift + _links.size();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
@ -942,9 +923,9 @@ void Parser::finalize(const TextParseOptions &options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_t->_links.resize(index);
|
_t->_links.resize(index);
|
||||||
const auto handler = CreateHandlerForLink(
|
const auto handler = Integration::Instance().createLinkHandler(
|
||||||
_links[realIndex - 1],
|
_links[realIndex - 1],
|
||||||
options);
|
_context);
|
||||||
if (handler) {
|
if (handler) {
|
||||||
_t->setLink(index, handler);
|
_t->setLink(index, handler);
|
||||||
}
|
}
|
||||||
|
|
@ -954,7 +935,10 @@ void Parser::finalize(const TextParseOptions &options) {
|
||||||
_t->_text.squeeze();
|
_t->_text.squeeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::computeLinkText(const QString &linkData, QString *outLinkText, LinkDisplayStatus *outDisplayStatus) {
|
void Parser::computeLinkText(
|
||||||
|
const QString &linkData,
|
||||||
|
QString *outLinkText,
|
||||||
|
EntityLinkShown *outShown) {
|
||||||
auto url = QUrl(linkData);
|
auto url = QUrl(linkData);
|
||||||
auto good = QUrl(url.isValid()
|
auto good = QUrl(url.isValid()
|
||||||
? url.toEncoded()
|
? url.toEncoded()
|
||||||
|
|
@ -963,28 +947,9 @@ void Parser::computeLinkText(const QString &linkData, QString *outLinkText, Link
|
||||||
? good.toDisplayString()
|
? good.toDisplayString()
|
||||||
: linkData;
|
: linkData;
|
||||||
*outLinkText = _t->_st->font->elided(readable, st::linkCropLimit);
|
*outLinkText = _t->_st->font->elided(readable, st::linkCropLimit);
|
||||||
*outDisplayStatus = (*outLinkText == readable) ? LinkDisplayedFull : LinkDisplayedElided;
|
*outShown = (*outLinkText == readable)
|
||||||
}
|
? EntityLinkShown::Full
|
||||||
|
: EntityLinkShown::Partial;
|
||||||
ClickHandlerPtr Parser::CreateHandlerForLink(
|
|
||||||
const TextLinkData &link,
|
|
||||||
const TextParseOptions &options) {
|
|
||||||
const auto result = Integration::Instance().createLinkHandler(
|
|
||||||
link.type,
|
|
||||||
link.text,
|
|
||||||
link.data,
|
|
||||||
options);
|
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
switch (link.type) {
|
|
||||||
case EntityType::Email:
|
|
||||||
case EntityType::Url:
|
|
||||||
return std::make_shared<UrlClickHandler>(
|
|
||||||
link.data,
|
|
||||||
link.displayStatus == LinkDisplayedFull);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
@ -2707,7 +2672,7 @@ void String::setText(const style::TextStyle &st, const QString &text, const Text
|
||||||
_st = &st;
|
_st = &st;
|
||||||
clear();
|
clear();
|
||||||
{
|
{
|
||||||
Parser parser(this, text, options);
|
Parser parser(this, text, options, {});
|
||||||
}
|
}
|
||||||
recountNaturalSize(true, options.dir);
|
recountNaturalSize(true, options.dir);
|
||||||
}
|
}
|
||||||
|
|
@ -2842,7 +2807,7 @@ int String::countMaxMonospaceWidth() const {
|
||||||
return result.ceil().toInt();
|
return result.ceil().toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void String::setMarkedText(const style::TextStyle &st, const TextWithEntities &textWithEntities, const TextParseOptions &options) {
|
void String::setMarkedText(const style::TextStyle &st, const TextWithEntities &textWithEntities, const TextParseOptions &options, const std::any &context) {
|
||||||
_st = &st;
|
_st = &st;
|
||||||
clear();
|
clear();
|
||||||
{
|
{
|
||||||
|
|
@ -2870,9 +2835,9 @@ void String::setMarkedText(const style::TextStyle &st, const TextWithEntities &t
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// newText.append("},\n\n").append(text);
|
// newText.append("},\n\n").append(text);
|
||||||
// Parser parser(this, { newText, EntitiesInText() }, options);
|
// Parser parser(this, { newText, EntitiesInText() }, options, context);
|
||||||
|
|
||||||
Parser parser(this, textWithEntities, options);
|
Parser parser(this, textWithEntities, options, context);
|
||||||
}
|
}
|
||||||
recountNaturalSize(true, options.dir);
|
recountNaturalSize(true, options.dir);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "base/flags.h"
|
#include "base/flags.h"
|
||||||
|
|
||||||
#include <private/qfixed_p.h>
|
#include <private/qfixed_p.h>
|
||||||
|
#include <any>
|
||||||
|
|
||||||
static const QChar TextCommand(0x0010);
|
static const QChar TextCommand(0x0010);
|
||||||
enum TextCommands {
|
enum TextCommands {
|
||||||
|
|
@ -126,7 +127,7 @@ public:
|
||||||
void countLineWidths(int width, QVector<int> *lineWidths, bool breakEverywhere = false) const;
|
void countLineWidths(int width, QVector<int> *lineWidths, bool breakEverywhere = false) const;
|
||||||
void setText(const style::TextStyle &st, const QString &text, const TextParseOptions &options = _defaultOptions);
|
void setText(const style::TextStyle &st, const QString &text, const TextParseOptions &options = _defaultOptions);
|
||||||
void setRichText(const style::TextStyle &st, const QString &text, TextParseOptions options = _defaultOptions);
|
void setRichText(const style::TextStyle &st, const QString &text, TextParseOptions options = _defaultOptions);
|
||||||
void setMarkedText(const style::TextStyle &st, const TextWithEntities &textWithEntities, const TextParseOptions &options = _defaultOptions);
|
void setMarkedText(const style::TextStyle &st, const TextWithEntities &textWithEntities, const TextParseOptions &options = _defaultOptions, const std::any &context = {});
|
||||||
|
|
||||||
void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk);
|
void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk);
|
||||||
bool hasLinks() const;
|
bool hasLinks() const;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
#include <QtCore/QVector>
|
#include <QtCore/QVector>
|
||||||
#include <QtGui/QClipboard>
|
#include <QtGui/QClipboard>
|
||||||
|
|
||||||
enum class EntityType {
|
enum class EntityType : uchar {
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
|
|
||||||
Url,
|
Url,
|
||||||
|
|
@ -33,6 +33,18 @@ enum class EntityType {
|
||||||
Pre, // block
|
Pre, // block
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class EntityLinkShown : uchar {
|
||||||
|
Full,
|
||||||
|
Partial,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EntityLinkData {
|
||||||
|
QString text;
|
||||||
|
QString data;
|
||||||
|
EntityType type = EntityType::Invalid;
|
||||||
|
EntityLinkShown shown = EntityLinkShown::Full;
|
||||||
|
};
|
||||||
|
|
||||||
class EntityInText;
|
class EntityInText;
|
||||||
using EntitiesInText = QList<EntityInText>;
|
using EntitiesInText = QList<EntityInText>;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue