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,
ClickHandlerPtr handler,
ClickContext context) {
crl::on_main(guard, [=] {
handler->onClick(context);
crl::on_main(guard, [=, weak = std::weak_ptr<ClickHandler>(handler)] {
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 {
public:
virtual ~ClickHandler() {

View file

@ -43,14 +43,19 @@ void Integration::startFontsEnd() {
}
std::shared_ptr<ClickHandler> Integration::createLinkHandler(
EntityType type,
const QString &text,
const QString &data,
const TextParseOptions &options) {
switch (type) {
const EntityLinkData &data,
const std::any &context) {
switch (data.type) {
case EntityType::CustomUrl:
return !data.isEmpty()
? std::make_shared<UrlClickHandler>(data, false)
return !data.data.isEmpty()
? 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;
}
return nullptr;

View file

@ -8,6 +8,8 @@
#include "base/basic_types.h"
#include <any>
// Methods that must be implemented outside lib_ui.
class QString;
@ -16,7 +18,7 @@ class QVariant;
struct TextParseOptions;
class ClickHandler;
enum class EntityType;
struct EntityLinkData;
namespace Ui {
namespace Emoji {
@ -43,10 +45,8 @@ public:
virtual void startFontsEnd();
[[nodiscard]] virtual std::shared_ptr<ClickHandler> createLinkHandler(
EntityType type,
const QString &text,
const QString &data,
const TextParseOptions &options);
const EntityLinkData &data,
const std::any &context);
[[nodiscard]] virtual bool handleUrlClick(
const QString &url,
const QVariant &context);

View file

@ -263,33 +263,18 @@ public:
Parser(
not_null<String*> string,
const QString &text,
const TextParseOptions &options);
const TextParseOptions &options,
const std::any &context);
Parser(
not_null<String*> string,
const TextWithEntities &textWithEntities,
const TextParseOptions &options);
const TextParseOptions &options,
const std::any &context);
private:
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 {
public:
explicit StartedEntity(TextBlockFlags flags);
@ -307,6 +292,7 @@ private:
not_null<String*> string,
TextWithEntities &&source,
const TextParseOptions &options,
const std::any &context,
ReadyToken);
void trimSourceRange();
@ -336,14 +322,11 @@ private:
void computeLinkText(
const QString &linkData,
QString *outLinkText,
LinkDisplayStatus *outDisplayStatus);
static ClickHandlerPtr CreateHandlerForLink(
const TextLinkData &link,
const TextParseOptions &options);
EntityLinkShown *outShown);
const not_null<String*> _t;
const TextWithEntities _source;
const std::any &_context;
const QChar * const _start = nullptr;
const QChar *_end = nullptr; // mutable, because we trim by decrementing.
const QChar *_ptr = nullptr;
@ -355,7 +338,7 @@ private:
const QFixed _stopAfterWidth; // summary width of all added words
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<
const QChar*,
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) {
Expects(_value >= 0 && _value < int(kStringLinkIndexShift));
}
@ -415,22 +387,26 @@ std::optional<uint16> Parser::StartedEntity::lnkIndex() const {
Parser::Parser(
not_null<String*> string,
const QString &text,
const TextParseOptions &options)
const TextParseOptions &options,
const std::any &context)
: Parser(
string,
PrepareRichFromPlain(text, options),
options,
context,
ReadyToken()) {
}
Parser::Parser(
not_null<String*> string,
const TextWithEntities &textWithEntities,
const TextParseOptions &options)
const TextParseOptions &options,
const std::any &context)
: Parser(
string,
PrepareRichFromRich(textWithEntities, options),
options,
context,
ReadyToken()) {
}
@ -438,9 +414,11 @@ Parser::Parser(
not_null<String*> string,
TextWithEntities &&source,
const TextParseOptions &options,
const std::any &context,
ReadyToken)
: _t(string)
, _source(std::move(source))
, _context(context)
, _start(_source.text.constData())
, _end(_start + _source.text.size())
, _ptr(_start)
@ -552,7 +530,7 @@ bool Parser::checkEntities() {
}
auto flags = TextBlockFlags();
auto link = TextLinkData();
auto link = EntityLinkData();
const auto entityType = _waitingEntity->type();
const auto entityLength = _waitingEntity->length();
const auto entityBegin = _start + _waitingEntity->offset();
@ -584,7 +562,7 @@ bool Parser::checkEntities() {
link.type = entityType;
link.data = QString(entityBegin, entityLength);
if (link.type == EntityType::Url) {
computeLinkText(link.data, &link.text, &link.displayStatus);
computeLinkText(link.data, &link.text, &link.shown);
} else {
link.text = link.data;
}
@ -745,7 +723,10 @@ bool Parser::readCommand() {
case TextCommandLinkText: {
createBlock();
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();
} break;
@ -942,9 +923,9 @@ void Parser::finalize(const TextParseOptions &options) {
}
_t->_links.resize(index);
const auto handler = CreateHandlerForLink(
const auto handler = Integration::Instance().createLinkHandler(
_links[realIndex - 1],
options);
_context);
if (handler) {
_t->setLink(index, handler);
}
@ -954,7 +935,10 @@ void Parser::finalize(const TextParseOptions &options) {
_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 good = QUrl(url.isValid()
? url.toEncoded()
@ -963,28 +947,9 @@ void Parser::computeLinkText(const QString &linkData, QString *outLinkText, Link
? good.toDisplayString()
: linkData;
*outLinkText = _t->_st->font->elided(readable, st::linkCropLimit);
*outDisplayStatus = (*outLinkText == readable) ? LinkDisplayedFull : LinkDisplayedElided;
}
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;
*outShown = (*outLinkText == readable)
? EntityLinkShown::Full
: EntityLinkShown::Partial;
}
namespace {
@ -2707,7 +2672,7 @@ void String::setText(const style::TextStyle &st, const QString &text, const Text
_st = &st;
clear();
{
Parser parser(this, text, options);
Parser parser(this, text, options, {});
}
recountNaturalSize(true, options.dir);
}
@ -2842,7 +2807,7 @@ int String::countMaxMonospaceWidth() const {
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;
clear();
{
@ -2870,9 +2835,9 @@ void String::setMarkedText(const style::TextStyle &st, const TextWithEntities &t
// }
// }
// 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);
}

View file

@ -13,6 +13,7 @@
#include "base/flags.h"
#include <private/qfixed_p.h>
#include <any>
static const QChar TextCommand(0x0010);
enum TextCommands {
@ -126,7 +127,7 @@ public:
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 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);
bool hasLinks() const;

View file

@ -12,7 +12,7 @@
#include <QtCore/QVector>
#include <QtGui/QClipboard>
enum class EntityType {
enum class EntityType : uchar {
Invalid = 0,
Url,
@ -33,6 +33,18 @@ enum class EntityType {
Pre, // block
};
enum class EntityLinkShown : uchar {
Full,
Partial,
};
struct EntityLinkData {
QString text;
QString data;
EntityType type = EntityType::Invalid;
EntityLinkShown shown = EntityLinkShown::Full;
};
class EntityInText;
using EntitiesInText = QList<EntityInText>;