Allow passing std::any context to link creation method.

This commit is contained in:
John Preston 2020-06-09 13:04:44 +04:00
parent 771f702056
commit ab61721a13
7 changed files with 72 additions and 87 deletions

View file

@ -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);
}
}); });
} }

View file

@ -29,7 +29,7 @@ protected:
}; };
enum class EntityType; enum class EntityType : uchar;
class ClickHandler { class ClickHandler {
public: public:
virtual ~ClickHandler() { virtual ~ClickHandler() {

View file

@ -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;

View file

@ -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);

View file

@ -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);
} }

View file

@ -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;

View file

@ -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>;