complex layouts for context gifs started

This commit is contained in:
John Preston 2015-12-30 19:56:05 +08:00
parent fa9850c319
commit e58c8a6fcb
12 changed files with 766 additions and 442 deletions

View file

@ -1991,10 +1991,10 @@ stickerPreviewDuration: 150;
stickerPreviewBg: #FFFFFFB0;
stickerPreviewMin: 0.1;
savedGifsLeft: 15px;
savedGifsSkip: 3px;
savedGifHeight: 96px;
savedGifMinWidth: 64px;
inlineResultsLeft: 15px;
inlineResultsSkip: 3px;
inlineMediaHeight: 96px;
inlineResultsMinWidth: 64px;
verifiedCheckProfile: sprite(285px, 235px, 18px, 18px);
verifiedCheckProfilePos: point(7px, 6px);

View file

@ -1309,7 +1309,7 @@ void StickerPanInner::paintContextItems(Painter &p, const QRect &r) {
const ContextRow &contextRow(_contextRows.at(row));
if (top >= r.top() + r.height()) break;
if (top + contextRow.height > r.top()) {
int32 left = st::savedGifsLeft;
int32 left = st::inlineResultsLeft;
for (int32 col = 0, cols = contextRow.items.size(); col < cols; ++col) {
if (left >= tox) break;
@ -1319,7 +1319,7 @@ void StickerPanInner::paintContextItems(Painter &p, const QRect &r) {
contextRow.items.at(col)->paint(p, r.translated(-left, -top), 0, &context);
p.translate(-left, -top);
}
left += w + st::savedGifsSkip;
left += w + st::inlineResultsSkip;
}
}
top += contextRow.height;
@ -1598,6 +1598,33 @@ void StickerPanInner::refreshStickers() {
updateSelected();
}
void StickerPanInner::contextRowsAddItem(DocumentData *savedGif, ContextResult *result, ContextRow &row, int32 &sumWidth) {
LayoutContextItem *layout = 0;
if (savedGif) {
layout = layoutPrepareSavedGif(savedGif, (_contextRows.size() * MatrixRowShift) + row.items.size());
} else if (result) {
layout = layoutPrepareContextResult(result, (_contextRows.size() * MatrixRowShift) + row.items.size());
}
if (!layout) return;
contextRowFinalize(row, sumWidth, layout->fullLine());
row.items.push_back(layout);
sumWidth += layout->maxWidth();
}
void StickerPanInner::contextRowFinalize(ContextRow &row, int32 &sumWidth, bool force) {
if (row.items.isEmpty()) return;
bool full = (row.items.size() >= SavedGifsMaxPerRow);
bool big = (sumWidth >= st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - (row.items.size() - 1) * st::inlineResultsSkip);
if (full || big || force) {
_contextRows.push_back(layoutContextRow(row, (full || big) ? sumWidth : 0));
row = ContextRow();
row.items.reserve(SavedGifsMaxPerRow);
sumWidth = 0;
}
}
void StickerPanInner::refreshSavedGifs() {
if (_showingSavedGifs) {
clearContextRows();
@ -1610,33 +1637,11 @@ void StickerPanInner::refreshSavedGifs() {
_contextRows.reserve(saved.size());
ContextRow row;
row.items.reserve(SavedGifsMaxPerRow);
int32 maxWidth = width() - st::savedGifsLeft, sumWidth = 0, widths[SavedGifsMaxPerRow] = { 0 };
int32 sumWidth = 0;
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
DocumentData *doc = *i;
int32 w = doc->dimensions.width(), h = doc->dimensions.height();
if ((w <= 0 || h <= 0) && !doc->thumb->isNull()) {
w = doc->thumb->width();
h = doc->thumb->height();
}
if (w <= 0 || h <= 0) continue;
w = w * st::savedGifHeight / h;
widths[row.items.size()] = w;
w = qMax(w, int32(st::savedGifMinWidth));
sumWidth += w;
row.items.push_back(layoutPrepare(doc, (_contextRows.size() * MatrixRowShift) + row.items.size(), w));
if (row.items.size() >= SavedGifsMaxPerRow || sumWidth >= maxWidth - (row.items.size() - 1) * st::savedGifsSkip) {
_contextRows.push_back(layoutContextRow(row, widths, sumWidth));
row = ContextRow();
sumWidth = 0;
memset(widths, 0, sizeof(widths));
}
}
if (!row.items.isEmpty()) {
_contextRows.push_back(layoutContextRow(row, 0, 0));
contextRowsAddItem(*i, 0, row, sumWidth);
}
contextRowFinalize(row, sumWidth, true);
}
deleteUnusedGifLayouts();
@ -1651,12 +1656,8 @@ void StickerPanInner::refreshSavedGifs() {
updateSelected();
}
void StickerPanInner::refreshContextResults(const ContextResults &results) {
}
void StickerPanInner::contextBotChanged() {
refreshContextResults(ContextResults());
refreshContextRows(0, ContextResults());
deleteUnusedContextLayouts();
}
@ -1664,19 +1665,43 @@ void StickerPanInner::clearContextRows() {
clearSelection(true);
for (ContextRows::const_iterator i = _contextRows.cbegin(), e = _contextRows.cend(); i != e; ++i) {
for (ContextItems::const_iterator j = i->items.cbegin(), end = i->items.cend(); j != end; ++j) {
(*j)->setPosition(-1, 0);
(*j)->setPosition(-1);
}
}
_contextRows.clear();
}
LayoutContextGif *StickerPanInner::layoutPrepare(DocumentData *doc, int32 position, int32 width) {
LayoutContextGif *StickerPanInner::layoutPrepareSavedGif(DocumentData *doc, int32 position) {
GifLayouts::const_iterator i = _gifLayouts.constFind(doc);
if (i == _gifLayouts.cend()) {
i = _gifLayouts.insert(doc, new LayoutContextGif(doc, true));
i = _gifLayouts.insert(doc, new LayoutContextGif(0, doc, true));
i.value()->initDimensions();
}
i.value()->setPosition(position, width);
if (!i.value()->maxWidth()) return 0;
i.value()->setPosition(position);
return i.value();
}
LayoutContextItem *StickerPanInner::layoutPrepareContextResult(ContextResult *result, int32 position) {
ContextLayouts::const_iterator i = _contextLayouts.constFind(result);
if (i == _contextLayouts.cend()) {
LayoutContextItem *layout = 0;
if (result->type == qstr("gif")) {
layout = new LayoutContextGif(result, 0, false);
} else if (result->type == qstr("photo")) {
} else if (result->type == qstr("web_player_video")) {
} else if (result->type == qstr("article")) {
return 0;
}
if (!layout) return 0;
i = _contextLayouts.insert(result, layout);
layout->initDimensions();
}
if (!i.value()->maxWidth()) return 0;
i.value()->setPosition(position);
return i.value();
}
@ -1716,20 +1741,19 @@ void StickerPanInner::deleteUnusedContextLayouts() {
}
}
StickerPanInner::ContextRow &StickerPanInner::layoutContextRow(ContextRow &row, int32 *widths, int32 sumWidth) {
StickerPanInner::ContextRow &StickerPanInner::layoutContextRow(ContextRow &row, int32 sumWidth) {
int32 count = row.items.size();
t_assert(count <= SavedGifsMaxPerRow);
row.height = 0;
int32 availw = width() - st::savedGifsLeft - st::savedGifsSkip * (count - 1);
int32 availw = width() - st::inlineResultsLeft - st::inlineResultsSkip * (count - 1);
for (int32 i = 0; i < count; ++i) {
int32 w = widths ? (widths[i] * availw / sumWidth) : row.items.at(i)->width();
int32 actualw = qMax(w, int32(st::savedGifMinWidth));
int32 w = sumWidth ? (row.items.at(i)->maxWidth() * availw / sumWidth) : row.items.at(i)->maxWidth();
int32 actualw = qMax(w, int32(st::inlineResultsMinWidth));
row.height = qMax(row.height, row.items.at(i)->resizeGetHeight(actualw));
if (widths) {
if (sumWidth) {
availw -= actualw;
sumWidth -= qMax(widths[i], int32(st::savedGifMinWidth));
sumWidth -= row.items.at(i)->maxWidth();
}
}
return row;
@ -1778,8 +1802,85 @@ uint64 StickerPanInner::currentSet(int yOffset) const {
return _sets.isEmpty() ? RecentStickerSetId : _sets.back().id;
}
void StickerPanInner::refreshContextRows(const ContextResults &results) {
void StickerPanInner::refreshContextRows(UserData *bot, const ContextResults &results) {
int32 count = results.size(), until = 0, untilrow = 0, untilcol = 0;
if (!count) {
_contextRows.clear();
_showingSavedGifs = true;
if (_showingContextItems) {
refreshSavedGifs();
emit scrollToY(0);
emit scrollUpdated();
}
return;
}
t_assert(bot != 0);
_inlineBotTitle = lng_inline_bot_results(lt_inline_bot, bot->username.isEmpty() ? bot->name : ('@' + bot->username));
_showingContextItems = true;
_showingSavedGifs = false;
for (; until < count;) {
if (untilrow >= _contextRows.size() || _contextRows.at(untilrow).items.at(untilcol)->result() != results.at(until)) {
break;
}
++until;
if (++untilcol == _contextRows.at(untilrow).items.size()) {
++untilrow;
untilcol = 0;
}
}
if (until == count) { // all items are layed out
if (untilrow == _contextRows.size()) { // nothing changed
return;
}
for (int32 i = untilrow, l = _contextRows.size(), skip = untilcol; i < l; ++i) {
for (int32 j = 0, s = _contextRows.at(i).items.size(); j < s; ++j) {
if (skip) {
--skip;
} else {
_contextRows.at(i).items.at(j)->setPosition(-1);
}
}
}
if (!untilcol) { // all good rows are filled
_contextRows.resize(untilrow);
return;
}
_contextRows.resize(untilrow + 1);
_contextRows[untilrow].items.resize(untilcol);
_contextRows[untilrow] = layoutContextRow(_contextRows[untilrow]);
return;
}
if (untilrow && !untilcol) { // remove last row, maybe it is not full
--untilrow;
untilcol = _contextRows.at(untilrow).items.size();
}
until -= untilcol;
for (int32 i = untilrow, l = _contextRows.size(); i < l; ++i) {
for (int32 j = 0, s = _contextRows.at(i).items.size(); j < s; ++j) {
_contextRows.at(i).items.at(j)->setPosition(-1);
}
}
_contextRows.resize(untilrow);
_contextRows.reserve(count);
ContextRow row;
row.items.reserve(SavedGifsMaxPerRow);
int32 sumWidth = 0;
for (int32 i = until; i < count; ++i) {
contextRowsAddItem(0, results.at(i), row, sumWidth);
}
contextRowFinalize(row, sumWidth, true);
int32 h = countHeight();
if (h != height()) resize(width(), h);
update();
emit refreshIcons();
updateSelected();
}
void StickerPanInner::ui_repaintContextItem(const LayoutContextItem *layout) {
@ -1916,7 +2017,7 @@ void StickerPanInner::fillPanels(QVector<EmojiPanel*> &panels) {
panels.clear();
if (_showingContextItems) {
panels.push_back(new EmojiPanel(parentWidget(), lang(lng_saved_gifs), NoneStickerSetId, true, 0));
panels.push_back(new EmojiPanel(parentWidget(), _showingSavedGifs ? lang(lng_saved_gifs) : _inlineBotTitle, NoneStickerSetId, true, 0));
panels.back()->show();
return;
}
@ -1957,7 +2058,7 @@ void StickerPanInner::updateSelected() {
QPoint p(mapFromGlobal(_lastMousePos));
if (_showingContextItems) {
int sx = (rtl() ? width() - p.x() : p.x()) - st::savedGifsLeft, sy = p.y() - st::emojiPanHeader;
int sx = (rtl() ? width() - p.x() : p.x()) - st::inlineResultsLeft, sy = p.y() - st::emojiPanHeader;
int32 row = -1, col = -1, sel = -1;
TextLinkPtr lnk;
HistoryCursorState cursor = HistoryDefaultCursorState;
@ -1978,7 +2079,7 @@ void StickerPanInner::updateSelected() {
if (sx < width) {
break;
}
sx -= width + st::savedGifsSkip;
sx -= width + st::inlineResultsSkip;
}
if (col < contextItems.size()) {
sel = row * MatrixRowShift + col;
@ -2118,7 +2219,6 @@ void StickerPanInner::onPreview() {
if (_pressedSel < 0) return;
if (_showingContextItems) {
int32 row = _pressedSel / MatrixRowShift, col = _pressedSel % MatrixRowShift;
if (col >= SavedGifsMaxPerRow) col -= SavedGifsMaxPerRow;
if (row < _contextRows.size() && col < _contextRows.at(row).items.size() && _contextRows.at(row).items.at(col)->document() && _contextRows.at(row).items.at(col)->document()->loaded()) {
Ui::showStickerPreview(_contextRows.at(row).items.at(col)->document());
_previewShown = true;
@ -2165,9 +2265,6 @@ void StickerPanInner::showStickerSet(uint64 setId) {
clearSelection(true);
if (setId == NoneStickerSetId) {
if (_contextRows.isEmpty() && !cSavedGifs().isEmpty()) {
refreshSavedGifs();
}
bool wasNotShowingGifs = !_showingContextItems;
if (wasNotShowingGifs) {
_showingContextItems = true;
@ -2582,7 +2679,7 @@ void EmojiPan::enterEvent(QEvent *e) {
}
void EmojiPan::leaveEvent(QEvent *e) {
if (_removingSetId) return;
if (_removingSetId || s_inner.contextResultsShown()) return;
if (_a_appearance.animating()) {
hideStart();
} else {
@ -2596,6 +2693,7 @@ void EmojiPan::otherEnter() {
}
void EmojiPan::otherLeave() {
if (_removingSetId || s_inner.contextResultsShown()) return;
if (_a_appearance.animating()) {
hideStart();
} else {
@ -2909,6 +3007,8 @@ void EmojiPan::step_appearance(float64 ms, bool timer) {
}
void EmojiPan::hideStart() {
if (_removingSetId || s_inner.contextResultsShown()) return;
if (_cache.isNull()) {
QPixmap from = _fromCache, to = _toCache;
_fromCache = _toCache = QPixmap();
@ -3249,6 +3349,8 @@ void EmojiPan::onDelayedHide() {
void EmojiPan::contextBotChanged() {
if (!_contextBot) return;
if (!isHidden()) hideStart();
if (_contextRequestId) MTP::cancel(_contextRequestId);
_contextRequestId = 0;
_contextQuery = _contextNextQuery = _contextNextOffset = QString();
@ -3311,8 +3413,31 @@ void EmojiPan::contextResultsDone(const MTPmessages_BotResults &result) {
message = &r.vsend_message;
} break;
}
bool badAttachment = (!result->photo || result->photo->access) && (!result->doc || result->doc->access);
bool canSend = (result->photo || result->doc || !result->message.isEmpty());
bool badAttachment = (result->photo && !result->photo->access) || (result->doc && !result->doc->access);
if (!message) {
delete result;
continue;
}
switch (message->type()) {
case mtpc_botContextMessageMediaAuto: {
const MTPDbotContextMessageMediaAuto &r(message->c_botContextMessageMediaAuto());
result->caption = qs(r.vcaption);
} break;
case mtpc_botContextMessageText: {
const MTPDbotContextMessageText &r(message->c_botContextMessageText());
result->message = qs(r.vmessage);
if (r.has_entities()) result->entities = entitiesFromMTP(r.ventities.c_vector().v);
result->noWebPage = r.is_no_webpage();
} break;
default: {
badAttachment = true;
} break;
}
bool canSend = (result->photo || result->doc || !result->message.isEmpty() || (!result->content_url.isEmpty() && (result->type == qstr("gif") || result->type == qstr("photo"))));
if (result->type.isEmpty() || badAttachment || !canSend) {
delete result;
} else {
@ -3323,7 +3448,7 @@ void EmojiPan::contextResultsDone(const MTPmessages_BotResults &result) {
it.value()->clearResults();
it.value()->nextOffset = QString();
}
refreshContextRows(!adding);
showContextRows(!adding);
}
bool EmojiPan::contextResultsFail(const RPCError &error) {
@ -3332,7 +3457,7 @@ bool EmojiPan::contextResultsFail(const RPCError &error) {
return true;
}
void EmojiPan::showContextResults(UserData *bot, QString query) {
void EmojiPan::queryContextBot(UserData *bot, QString query) {
bool force = false;
if (bot != _contextBot) {
contextBotChanged();
@ -3344,10 +3469,11 @@ void EmojiPan::showContextResults(UserData *bot, QString query) {
_contextRequestId = 0;
}
if (_contextQuery != query || force) {
if (_contextCache.contains(_contextQuery)) {
refreshContextRows(true);
if (_contextCache.contains(query)) {
_contextQuery = query;
showContextRows(true);
} else {
_contextNextQuery = _contextQuery;
_contextNextQuery = query;
_contextRequestTimer.start(ContextBotRequestDelay);
}
}
@ -3366,16 +3492,37 @@ void EmojiPan::onContextRequest() {
_contextRequestId = MTP::send(MTPmessages_GetContextBotResults(_contextBot->inputUser, MTP_string(_contextQuery), MTP_string(nextOffset)), rpcDone(&EmojiPan::contextResultsDone), rpcFail(&EmojiPan::contextResultsFail));
}
void EmojiPan::refreshContextRows(bool newResults) {
void EmojiPan::showContextRows(bool newResults) {
bool clear = true;
ContextCache::const_iterator i = _contextCache.constFind(_contextQuery);
if (i != _contextCache.cend()) {
clear = !i.value()->results.isEmpty();
clear = i.value()->results.isEmpty();
_contextNextOffset = i.value()->nextOffset;
}
s_inner.refreshContextRows(clear ? ContextResults() : i.value()->results);
s_inner.refreshContextRows(_contextBot, clear ? ContextResults() : i.value()->results);
if (newResults) s_scroll.scrollToY(0);
if (clear && !isHidden() && _stickersShown && s_inner.contextResultsShown()) {
hideStart();
} else if (!clear) {
_hideTimer.stop();
if (!_stickersShown) {
if (!isHidden() || _hiding) {
onSwitch();
} else {
_stickersShown = true;
if (isHidden()) {
show();
a_opacity = anim::fvalue(0, 1);
a_opacity.update(0, anim::linear);
_cache = _fromCache = _toCache = QPixmap();
}
}
}
if (isHidden() || _hiding) {
showStart();
}
}
}
MentionsInner::MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows)

View file

@ -314,31 +314,6 @@ struct StickerIcon {
int32 pixw, pixh;
};
struct ContextResult {
ContextResult(uint64 queryId)
: queryId(queryId)
, doc(0)
, photo(0)
, width(0)
, height(0)
, duration(0)
, noWebPage(false) {
}
uint64 queryId;
QString id, type;
DocumentData *doc;
PhotoData *photo;
QString title, description, url, thumb_url;
QString content_type, content_url;
int32 width, height, duration;
QString message; // botContextMessageText
bool noWebPage;
EntitiesInText entities;
QString caption; // if message.isEmpty() use botContextMessageMediaAuto
};
typedef QList<ContextResult*> ContextResults;
class StickerPanInner : public TWidget {
Q_OBJECT
@ -366,8 +341,9 @@ public:
void refreshStickers();
void refreshRecentStickers(bool resize = true);
void refreshSavedGifs();
void refreshContextRows(const ContextResults &results);
void refreshContextRows(UserData *bot, const ContextResults &results);
void refreshRecent();
void contextBotChanged();
void fillIcons(QList<StickerIcon> &icons);
void fillPanels(QVector<EmojiPanel*> &panels);
@ -377,13 +353,15 @@ public:
void preloadImages();
uint64 currentSet(int yOffset) const;
void refreshContextResults(const ContextResults &results);
void contextBotChanged();
void ui_repaintContextItem(const LayoutContextItem *layout);
bool ui_isContextItemVisible(const LayoutContextItem *layout);
bool ui_isContextItemBeingChosen();
bool contextResultsShown() const {
return _showingContextItems && !_showingSavedGifs;
}
~StickerPanInner() {
clearContextRows();
deleteUnusedGifLayouts();
@ -445,28 +423,33 @@ private:
QList<bool> _custom;
bool _showingSavedGifs, _showingContextItems;
QString _inlineBotTitle;
uint64 _lastScrolled;
QTimer _updateContextItems;
typedef QList<LayoutContextItem*> ContextItems;
typedef QVector<LayoutContextItem*> ContextItems;
struct ContextRow {
ContextRow() : height(0) {
}
int32 height;
ContextItems items;
};
typedef QList<ContextRow> ContextRows;
typedef QVector<ContextRow> ContextRows;
ContextRows _contextRows;
void clearContextRows();
typedef QMap<DocumentData*, LayoutContextGif*> GifLayouts;
GifLayouts _gifLayouts;
LayoutContextGif *layoutPrepare(DocumentData *doc, int32 position, int32 width);
LayoutContextGif *layoutPrepareSavedGif(DocumentData *doc, int32 position);
typedef QMap<ContextResult*, LayoutContextItem*> ContextLayouts;
ContextLayouts _contextLayouts;
LayoutContextItem *layoutPrepareContextResult(ContextResult *result, int32 position);
ContextRow &layoutContextRow(ContextRow &row, int32 *widths, int32 sumWidth);
void contextRowsAddItem(DocumentData *savedGif, ContextResult *result, ContextRow &row, int32 &sumWidth);
void contextRowFinalize(ContextRow &row, int32 &sumWidth, bool force = false);
ContextRow &layoutContextRow(ContextRow &row, int32 sumWidth = 0);
void deleteUnusedGifLayouts();
void deleteUnusedContextLayouts();
@ -569,7 +552,7 @@ public:
bool eventFilter(QObject *obj, QEvent *e);
void stickersInstalled(uint64 setId);
void showContextResults(UserData *bot, QString query);
void queryContextBot(UserData *bot, QString query);
void contextBotChanged();
bool overlaps(const QRect &globalRect) {
@ -701,7 +684,7 @@ private:
ContextCache _contextCache;
QTimer _contextRequestTimer;
void refreshContextRows(bool newResults);
void showContextRows(bool newResults);
UserData *_contextBot;
QString _contextQuery, _contextNextQuery, _contextNextOffset;
mtpRequestId _contextRequestId;

View file

@ -5559,207 +5559,6 @@ HistoryWebPage::~HistoryWebPage() {
deleteAndMark(_attach);
}
namespace {
ImageLinkManager manager;
}
void ImageLinkManager::init() {
if (manager) delete manager;
manager = new QNetworkAccessManager();
App::setProxySettings(*manager);
connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*)));
connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(onFailed(QNetworkReply*)));
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
if (black) delete black;
QImage b(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
{
QPainter p(&b);
p.fillRect(QRect(0, 0, cIntRetinaFactor(), cIntRetinaFactor()), st::white->b);
}
QPixmap p = QPixmap::fromImage(b, Qt::ColorOnly);
p.setDevicePixelRatio(cRetinaFactor());
black = new ImagePtr(p, "PNG");
}
void ImageLinkManager::reinit() {
if (manager) App::setProxySettings(*manager);
}
void ImageLinkManager::deinit() {
if (manager) {
delete manager;
manager = 0;
}
if (black) {
delete black;
black = 0;
}
dataLoadings.clear();
imageLoadings.clear();
}
void initImageLinkManager() {
manager.init();
}
void reinitImageLinkManager() {
manager.reinit();
}
void deinitImageLinkManager() {
manager.deinit();
}
void ImageLinkManager::getData(ImageLinkData *data) {
if (!manager) {
DEBUG_LOG(("App Error: getting image link data without manager init!"));
return failed(data);
}
QString url;
switch (data->type) {
case GoogleMapsLink: {
int32 w = st::locationSize.width(), h = st::locationSize.height();
int32 zoom = 13, scale = 1;
if (cScale() == dbisTwo || cRetina()) {
scale = 2;
} else {
w = convertScale(w);
h = convertScale(h);
}
url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + data->id.mid(9) + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + data->id.mid(9) + qsl("&sensor=false");
QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
imageLoadings[reply] = data;
} break;
default: {
failed(data);
} break;
}
}
void ImageLinkManager::onFinished(QNetworkReply *reply) {
if (!manager) return;
if (reply->error() != QNetworkReply::NoError) return onFailed(reply);
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (statusCode.isValid()) {
int status = statusCode.toInt();
if (status == 301 || status == 302) {
QString loc = reply->header(QNetworkRequest::LocationHeader).toString();
if (!loc.isEmpty()) {
QMap<QNetworkReply*, ImageLinkData*>::iterator i = dataLoadings.find(reply);
if (i != dataLoadings.cend()) {
ImageLinkData *d = i.value();
if (serverRedirects.constFind(d) == serverRedirects.cend()) {
serverRedirects.insert(d, 1);
} else if (++serverRedirects[d] > MaxHttpRedirects) {
DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc));
return onFailed(reply);
}
dataLoadings.erase(i);
dataLoadings.insert(manager->get(QNetworkRequest(loc)), d);
return;
} else if ((i = imageLoadings.find(reply)) != imageLoadings.cend()) {
ImageLinkData *d = i.value();
if (serverRedirects.constFind(d) == serverRedirects.cend()) {
serverRedirects.insert(d, 1);
} else if (++serverRedirects[d] > MaxHttpRedirects) {
DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc));
return onFailed(reply);
}
imageLoadings.erase(i);
imageLoadings.insert(manager->get(QNetworkRequest(loc)), d);
return;
}
}
}
if (status != 200) {
DEBUG_LOG(("Network Error: Bad HTTP status received in onFinished() for image link: %1").arg(status));
return onFailed(reply);
}
}
ImageLinkData *d = 0;
QMap<QNetworkReply*, ImageLinkData*>::iterator i = dataLoadings.find(reply);
if (i != dataLoadings.cend()) {
d = i.value();
dataLoadings.erase(i);
QJsonParseError e;
QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &e);
if (e.error != QJsonParseError::NoError) {
DEBUG_LOG(("JSON Error: Bad json received in onFinished() for image link"));
return onFailed(reply);
}
switch (d->type) {
case GoogleMapsLink: failed(d); break;
}
if (App::main()) App::main()->update();
} else {
i = imageLoadings.find(reply);
if (i != imageLoadings.cend()) {
d = i.value();
imageLoadings.erase(i);
QPixmap thumb;
QByteArray format;
QByteArray data(reply->readAll());
{
QBuffer buffer(&data);
QImageReader reader(&buffer);
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
reader.setAutoTransform(true);
#endif
thumb = QPixmap::fromImageReader(&reader, Qt::ColorOnly);
format = reader.format();
thumb.setDevicePixelRatio(cRetinaFactor());
if (format.isEmpty()) format = QByteArray("JPG");
}
d->loading = false;
d->thumb = thumb.isNull() ? (*black) : ImagePtr(thumb, format);
serverRedirects.remove(d);
if (App::main()) App::main()->update();
}
}
}
void ImageLinkManager::onFailed(QNetworkReply *reply) {
if (!manager) return;
ImageLinkData *d = 0;
QMap<QNetworkReply*, ImageLinkData*>::iterator i = dataLoadings.find(reply);
if (i != dataLoadings.cend()) {
d = i.value();
dataLoadings.erase(i);
} else {
i = imageLoadings.find(reply);
if (i != imageLoadings.cend()) {
d = i.value();
imageLoadings.erase(i);
}
}
DEBUG_LOG(("Network Error: failed to get data for image link %1, error %2").arg(d ? d->id : 0).arg(reply->errorString()));
if (d) {
failed(d);
}
}
void ImageLinkManager::failed(ImageLinkData *data) {
data->loading = false;
data->thumb = *black;
serverRedirects.remove(data);
}
void ImageLinkData::load() {
if (!thumb->isNull()) return thumb->load(false, false);
if (loading) return;
loading = true;
manager.getData(this);
}
HistoryImageLink::HistoryImageLink(const QString &url, const QString &title, const QString &description) : HistoryMedia(),
_title(st::msgMinWidth),
_description(st::msgMinWidth) {

View file

@ -1859,54 +1859,6 @@ private:
int16 _pixw, _pixh;
};
void initImageLinkManager();
void reinitImageLinkManager();
void deinitImageLinkManager();
enum ImageLinkType {
InvalidImageLink = 0,
GoogleMapsLink
};
struct ImageLinkData {
ImageLinkData(const QString &id) : id(id), type(InvalidImageLink), loading(false) {
}
QString id;
ImagePtr thumb;
ImageLinkType type;
bool loading;
void load();
};
class ImageLinkManager : public QObject {
Q_OBJECT
public:
ImageLinkManager() : manager(0), black(0) {
}
void init();
void reinit();
void deinit();
void getData(ImageLinkData *data);
~ImageLinkManager() {
deinit();
}
public slots:
void onFinished(QNetworkReply *reply);
void onFailed(QNetworkReply *reply);
private:
void failed(ImageLinkData *data);
QNetworkAccessManager *manager;
QMap<QNetworkReply*, ImageLinkData*> dataLoadings, imageLoadings;
QMap<ImageLinkData*, int32> serverRedirects;
ImagePtr *black;
};
class HistoryImageLink : public HistoryMedia {
public:

View file

@ -5327,7 +5327,7 @@ void HistoryWidget::onCheckMentionDropdown() {
}
if (_contextBot) {
_emojiPan.showContextResults(_contextBot, start);
_emojiPan.queryContextBot(_contextBot, start);
if (!_attachMention.isHidden()) {
_attachMention.hideStart();
}

View file

@ -1281,33 +1281,31 @@ LayoutOverviewLink::Link::Link(const QString &url, const QString &text)
, lnk(linkFromUrl(url)) {
}
LayoutContextItem::LayoutContextItem(ContextResult *result)
LayoutContextItem::LayoutContextItem(ContextResult *result, DocumentData *doc, PhotoData *photo)
: _result(result)
, _doc(0)
, _position(0) {
}
LayoutContextItem::LayoutContextItem(DocumentData *doc)
: _result(0)
, _doc(doc)
, _photo(photo)
, _position(0) {
}
void LayoutContextItem::setPosition(int32 position, int32 width) {
void LayoutContextItem::setPosition(int32 position) {
_position = position;
resizeGetHeight(width);
}
int32 LayoutContextItem::position() const {
return _position;
}
ContextResult *LayoutContextItem::result() const {
return _result;
}
DocumentData *LayoutContextItem::document() const {
return _doc;
}
ContextResult *LayoutContextItem::result() const {
return _result;
PhotoData *LayoutContextItem::photo() const {
return _photo;
}
void LayoutContextItem::preload() {
@ -1316,27 +1314,37 @@ void LayoutContextItem::preload() {
_result->photo->thumb->load();
} else if (_result->doc) {
_result->doc->thumb->load();
} else if (!_result->thumb_url.isEmpty()) {
_result->thumb->load();
}
} else if (_doc) {
_doc->thumb->load();
} else if (_photo) {
_photo->medium->load();
}
}
LayoutContextGif::LayoutContextGif(DocumentData *data, bool saved) : LayoutContextItem(data)
LayoutContextGif::LayoutContextGif(ContextResult *result, DocumentData *doc, bool saved) : LayoutContextItem(result, doc, 0)
, _state(0)
, _gif(0)
, _send(new SendContextItemLink())
, _delete(saved ? new DeleteSavedGifLink(data) : 0)
, _delete((doc && saved) ? new DeleteSavedGifLink(doc) : 0)
, _animation(0) {
}
void LayoutContextGif::initDimensions() {
_maxw = st::emojiPanWidth - st::emojiScroll.width - st::savedGifsLeft;
_minh = st::savedGifHeight + st::savedGifsSkip;
int32 w = content_width(), h = content_height();
if (w <= 0 || h <= 0) {
_maxw = 0;
} else {
w = w * st::inlineMediaHeight / h;
_maxw = qMax(w, int32(st::inlineResultsMinWidth));
}
_minh = st::inlineMediaHeight + st::inlineResultsSkip;
}
void LayoutContextGif::setPosition(int32 position, int32 width) {
LayoutContextItem::setPosition(position, width);
void LayoutContextGif::setPosition(int32 position) {
LayoutContextItem::setPosition(position);
if (_position < 0) {
if (gif()) delete _gif;
_gif = 0;
@ -1357,12 +1365,12 @@ void DeleteSavedGifLink::onClick(Qt::MouseButton button) const {
}
void LayoutContextGif::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
_doc->automaticLoad(0);
content_automaticLoad();
bool loaded = _doc->loaded(), displayLoading = _doc->displayLoading();
bool loaded = content_loaded(), loading = content_loading(), displayLoading = content_displayLoading();
if (loaded && !gif() && _gif != BadClipReader) {
LayoutContextGif *that = const_cast<LayoutContextGif*>(this);
that->_gif = new ClipReader(_doc->location(), _doc->data(), func(that, &LayoutContextGif::clipCallback));
that->_gif = new ClipReader(content_location(), content_data(), func(that, &LayoutContextGif::clipCallback));
if (gif()) _gif->setAutoplay();
}
@ -1370,12 +1378,12 @@ void LayoutContextGif::paint(Painter &p, const QRect &clip, uint32 selection, co
if (displayLoading) {
ensureAnimation();
if (!_animation->radial.animating()) {
_animation->radial.start(_doc->progress());
_animation->radial.start(content_progress());
}
}
bool radial = isRadialAnimation(context->ms);
int32 height = st::savedGifHeight;
int32 height = st::inlineMediaHeight;
QSize frame = countFrameSize();
QRect r(0, 0, _width, height);
@ -1385,20 +1393,12 @@ void LayoutContextGif::paint(Painter &p, const QRect &clip, uint32 selection, co
t_assert(ctx);
p.drawPixmap(r.topLeft(), _gif->current(frame.width(), frame.height(), _width, height, ctx->paused ? 0 : context->ms));
} else {
if (!_doc->thumb->isNull()) {
if (_doc->thumb->loaded()) {
if (_thumb.width() != _width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
const_cast<LayoutContextGif*>(this)->_thumb = _doc->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, _width, height);
}
} else {
_doc->thumb->load();
}
}
prepareThumb(_width, height, frame);
p.drawPixmap(r.topLeft(), _thumb);
}
if (radial || (!_gif && !loaded && !_doc->loading()) || (_gif == BadClipReader)) {
float64 radialOpacity = (radial && loaded && !_doc->uploading()) ? _animation->radial.opacity() : 1;
if (radial || (!_gif && !loaded && !loading) || (_gif == BadClipReader)) {
float64 radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1;
if (_animation && _animation->_a_over.animating(context->ms)) {
float64 over = _animation->_a_over.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
@ -1410,9 +1410,9 @@ void LayoutContextGif::paint(Painter &p, const QRect &clip, uint32 selection, co
p.setOpacity(radialOpacity);
style::sprite icon;
if (_doc->loaded() && !radial) {
if (loaded && !radial) {
icon = st::msgFileInPlay;
} else if (radial || _doc->loading()) {
} else if (radial || loading) {
icon = st::msgFileInCancel;
} else {
icon = st::msgFileInDownload;
@ -1436,8 +1436,8 @@ void LayoutContextGif::paint(Painter &p, const QRect &clip, uint32 selection, co
}
void LayoutContextGif::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
if (x >= 0 && x < _width && y >= 0 && y < st::savedGifHeight) {
if ((rtl() ? _width - x : x) >= _width - st::stickerPanDelete.pxWidth() && y < st::stickerPanDelete.pxHeight()) {
if (x >= 0 && x < _width && y >= 0 && y < st::inlineMediaHeight) {
if (_delete && (rtl() ? _width - x : x) >= _width - st::stickerPanDelete.pxWidth() && y < st::stickerPanDelete.pxHeight()) {
link = _delete;
} else {
link = _send;
@ -1446,15 +1446,15 @@ void LayoutContextGif::getState(TextLinkPtr &link, HistoryCursorState &cursor, i
}
void LayoutContextGif::linkOver(const TextLinkPtr &link) {
if (link == _delete) {
if (_delete && link == _delete) {
if (!(_state & StateDeleteOver)) {
EnsureAnimation(_a_deleteOver, 0, func(this, &LayoutContextGif::update));
_state |= StateDeleteOver;
_a_deleteOver.start(1, st::stickersRowDuration);
}
}
if (link == _delete || link == _send) {
if (!_doc->loaded()) {
if ((_delete && link == _delete) || link == _send) {
if (!content_loaded()) {
ensureAnimation();
if (!(_state & StateOver)) {
EnsureAnimation(_animation->_a_over, 0, func(this, &LayoutContextGif::update));
@ -1466,15 +1466,15 @@ void LayoutContextGif::linkOver(const TextLinkPtr &link) {
}
void LayoutContextGif::linkOut(const TextLinkPtr &link) {
if (link == _delete) {
if (_delete && link == _delete) {
if (_state & StateDeleteOver) {
EnsureAnimation(_a_deleteOver, 1, func(this, &LayoutContextGif::update));
_state &= ~StateDeleteOver;
_a_deleteOver.start(0, st::stickersRowDuration);
}
}
if (link == _delete || link == _send) {
if (!_doc->loaded()) {
if ((_delete && link == _delete) || link == _send) {
if (!content_loaded()) {
ensureAnimation();
if (_state & StateOver) {
EnsureAnimation(_animation->_a_over, 1, func(this, &LayoutContextGif::update));
@ -1487,7 +1487,7 @@ void LayoutContextGif::linkOut(const TextLinkPtr &link) {
QSize LayoutContextGif::countFrameSize() const {
bool animating = (gif() && _gif->ready());
int32 framew = animating ? _gif->width() : _doc->thumb->width(), frameh = animating ? _gif->height() : _doc->thumb->height(), height = st::savedGifHeight;
int32 framew = animating ? _gif->width() : content_width(), frameh = animating ? _gif->height() : content_height(), height = st::inlineMediaHeight;
if (framew * height > frameh * _width) {
if (framew < st::maxStickerSize || frameh > height) {
if (frameh > height || (framew * height / frameh) <= st::maxStickerSize) {
@ -1516,6 +1516,26 @@ LayoutContextGif::~LayoutContextGif() {
deleteAndMark(_animation);
}
void LayoutContextGif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
if (_doc && !_doc->thumb->isNull()) {
if (_doc->thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
const_cast<LayoutContextGif*>(this)->_thumb = _doc->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height);
}
} else {
_doc->thumb->load();
}
} else if (_result && !_result->thumb_url.isEmpty()) {
if (_result->thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
const_cast<LayoutContextGif*>(this)->_thumb = _result->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height);
}
} else {
_result->thumb->load();
}
}
}
void LayoutContextGif::ensureAnimation() const {
if (!_animation) {
_animation = new AnimationData(animation(const_cast<LayoutContextGif*>(this), &LayoutContextGif::step_radial));
@ -1533,8 +1553,8 @@ void LayoutContextGif::step_radial(uint64 ms, bool timer) {
if (timer) {
update();
} else {
_animation->radial.update(_doc->progress(), !_doc->loading() || _doc->loaded(), ms);
if (!_animation->radial.animating() && _doc->loaded()) {
_animation->radial.update(content_progress(), !content_loading() || content_loaded(), ms);
if (!_animation->radial.animating() && content_loaded()) {
delete _animation;
_animation = 0;
}
@ -1548,15 +1568,15 @@ void LayoutContextGif::clipCallback(ClipReaderNotification notification) {
if (_gif->state() == ClipError) {
delete _gif;
_gif = BadClipReader;
_doc->forget();
content_forget();
} else if (_gif->ready() && !_gif->started()) {
int32 height = st::savedGifHeight;
int32 height = st::inlineMediaHeight;
QSize frame = countFrameSize();
_gif->start(frame.width(), frame.height(), _width, height, false);
} else if (_gif->paused() && !Ui::isContextItemVisible(this)) {
delete _gif;
_gif = 0;
_doc->forget();
content_forget();
}
}
@ -1576,3 +1596,71 @@ void LayoutContextGif::update() {
Ui::repaintContextItem(this);
}
}
int32 LayoutContextGif::content_width() const {
if (_doc) {
if (_doc->dimensions.width() > 0) {
return _doc->dimensions.width();
}
if (!_doc->thumb->isNull()) {
return _doc->thumb->width();
}
} else if (_result) {
return _result->width;
}
return 0;
}
int32 LayoutContextGif::content_height() const {
if (_doc) {
if (_doc->dimensions.height() > 0) {
return _doc->dimensions.height();
}
if (!_doc->thumb->isNull()) {
return _doc->thumb->height();
}
} else if (_result) {
return _result->height;
}
return 0;
}
bool LayoutContextGif::content_loading() const {
return _doc ? _doc->loading() : _result->loading();
}
bool LayoutContextGif::content_displayLoading() const {
return _doc ? _doc->displayLoading() : _result->displayLoading();
}
bool LayoutContextGif::content_loaded() const {
return _doc ? _doc->loaded() : _result->loaded();
}
float64 LayoutContextGif::content_progress() const {
return _doc ? _doc->progress() : _result->progress();
}
void LayoutContextGif::content_automaticLoad() const {
if (_doc) {
_doc->automaticLoad(0);
} else {
_result->automaticLoadGif();
}
}
void LayoutContextGif::content_forget() {
if (_doc) {
_doc->forget();
} else {
_result->forget();
}
}
FileLocation LayoutContextGif::content_location() const {
return _doc ? _doc->location() : FileLocation();
}
QByteArray LayoutContextGif::content_data() const {
return _doc ? _doc->data() : _result->data();
}

View file

@ -490,19 +490,24 @@ struct ContextResult;
class LayoutContextItem : public LayoutItem {
public:
LayoutContextItem(ContextResult *result);
LayoutContextItem(DocumentData *doc);
LayoutContextItem(ContextResult *result, DocumentData *doc, PhotoData *photo);
virtual void setPosition(int32 position, int32 width);
virtual void setPosition(int32 position);
int32 position() const;
DocumentData *document() const;
virtual bool fullLine() const {
return true;
}
ContextResult *result() const;
DocumentData *document() const;
PhotoData *photo() const;
void preload();
protected:
ContextResult *_result;
DocumentData *_doc;
PhotoData *_photo;
int32 _position; // < 0 means removed from layout
@ -532,11 +537,15 @@ private:
class LayoutContextGif : public LayoutContextItem {
public:
LayoutContextGif(DocumentData *data, bool saved);
LayoutContextGif(ContextResult *result, DocumentData *doc, bool saved);
virtual void setPosition(int32 position, int32 width);
virtual void setPosition(int32 position);
virtual void initDimensions();
virtual bool fullLine() const {
return false;
}
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
virtual void linkOver(const TextLinkPtr &lnk);
@ -547,6 +556,17 @@ public:
private:
QSize countFrameSize() const;
int32 content_width() const;
int32 content_height() const;
bool content_loading() const;
bool content_displayLoading() const;
bool content_loaded() const;
float64 content_progress() const;
void content_automaticLoad() const;
void content_forget();
FileLocation content_location() const;
QByteArray content_data() const;
enum StateFlags {
StateOver = 0x01,
StateDeleteOver = 0x02,
@ -559,6 +579,7 @@ private:
return (!_gif || _gif == BadClipReader) ? false : true;
}
QPixmap _thumb;
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
void ensureAnimation() const;
bool isRadialAnimation(uint64 ms) const;

View file

@ -1833,6 +1833,234 @@ WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &u
, pendingTill(pendingTill) {
}
namespace {
ImageLinkManager manager;
}
void ImageLinkManager::init() {
if (manager) delete manager;
manager = new QNetworkAccessManager();
App::setProxySettings(*manager);
connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*)));
connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(onFailed(QNetworkReply*)));
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
if (black) delete black;
QImage b(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
{
QPainter p(&b);
p.fillRect(QRect(0, 0, cIntRetinaFactor(), cIntRetinaFactor()), st::white->b);
}
QPixmap p = QPixmap::fromImage(b, Qt::ColorOnly);
p.setDevicePixelRatio(cRetinaFactor());
black = new ImagePtr(p, "PNG");
}
void ImageLinkManager::reinit() {
if (manager) App::setProxySettings(*manager);
}
void ImageLinkManager::deinit() {
if (manager) {
delete manager;
manager = 0;
}
if (black) {
delete black;
black = 0;
}
dataLoadings.clear();
imageLoadings.clear();
}
void initImageLinkManager() {
manager.init();
}
void reinitImageLinkManager() {
manager.reinit();
}
void deinitImageLinkManager() {
manager.deinit();
}
void ImageLinkManager::getData(ImageLinkData *data) {
if (!manager) {
DEBUG_LOG(("App Error: getting image link data without manager init!"));
return failed(data);
}
QString url;
switch (data->type) {
case GoogleMapsLink: {
int32 w = st::locationSize.width(), h = st::locationSize.height();
int32 zoom = 13, scale = 1;
if (cScale() == dbisTwo || cRetina()) {
scale = 2;
} else {
w = convertScale(w);
h = convertScale(h);
}
url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + data->id.mid(9) + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + data->id.mid(9) + qsl("&sensor=false");
QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
imageLoadings[reply] = data;
} break;
default: {
failed(data);
} break;
}
}
void ImageLinkManager::onFinished(QNetworkReply *reply) {
if (!manager) return;
if (reply->error() != QNetworkReply::NoError) return onFailed(reply);
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (statusCode.isValid()) {
int status = statusCode.toInt();
if (status == 301 || status == 302) {
QString loc = reply->header(QNetworkRequest::LocationHeader).toString();
if (!loc.isEmpty()) {
QMap<QNetworkReply*, ImageLinkData*>::iterator i = dataLoadings.find(reply);
if (i != dataLoadings.cend()) {
ImageLinkData *d = i.value();
if (serverRedirects.constFind(d) == serverRedirects.cend()) {
serverRedirects.insert(d, 1);
} else if (++serverRedirects[d] > MaxHttpRedirects) {
DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc));
return onFailed(reply);
}
dataLoadings.erase(i);
dataLoadings.insert(manager->get(QNetworkRequest(loc)), d);
return;
} else if ((i = imageLoadings.find(reply)) != imageLoadings.cend()) {
ImageLinkData *d = i.value();
if (serverRedirects.constFind(d) == serverRedirects.cend()) {
serverRedirects.insert(d, 1);
} else if (++serverRedirects[d] > MaxHttpRedirects) {
DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc));
return onFailed(reply);
}
imageLoadings.erase(i);
imageLoadings.insert(manager->get(QNetworkRequest(loc)), d);
return;
}
}
}
if (status != 200) {
DEBUG_LOG(("Network Error: Bad HTTP status received in onFinished() for image link: %1").arg(status));
return onFailed(reply);
}
}
ImageLinkData *d = 0;
QMap<QNetworkReply*, ImageLinkData*>::iterator i = dataLoadings.find(reply);
if (i != dataLoadings.cend()) {
d = i.value();
dataLoadings.erase(i);
QJsonParseError e;
QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &e);
if (e.error != QJsonParseError::NoError) {
DEBUG_LOG(("JSON Error: Bad json received in onFinished() for image link"));
return onFailed(reply);
}
switch (d->type) {
case GoogleMapsLink: failed(d); break;
}
if (App::main()) App::main()->update();
} else {
i = imageLoadings.find(reply);
if (i != imageLoadings.cend()) {
d = i.value();
imageLoadings.erase(i);
QPixmap thumb;
QByteArray format;
QByteArray data(reply->readAll());
{
QBuffer buffer(&data);
QImageReader reader(&buffer);
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
reader.setAutoTransform(true);
#endif
thumb = QPixmap::fromImageReader(&reader, Qt::ColorOnly);
format = reader.format();
thumb.setDevicePixelRatio(cRetinaFactor());
if (format.isEmpty()) format = QByteArray("JPG");
}
d->loading = false;
d->thumb = thumb.isNull() ? (*black) : ImagePtr(thumb, format);
serverRedirects.remove(d);
if (App::main()) App::main()->update();
}
}
}
void ImageLinkManager::onFailed(QNetworkReply *reply) {
if (!manager) return;
ImageLinkData *d = 0;
QMap<QNetworkReply*, ImageLinkData*>::iterator i = dataLoadings.find(reply);
if (i != dataLoadings.cend()) {
d = i.value();
dataLoadings.erase(i);
} else {
i = imageLoadings.find(reply);
if (i != imageLoadings.cend()) {
d = i.value();
imageLoadings.erase(i);
}
}
DEBUG_LOG(("Network Error: failed to get data for image link %1, error %2").arg(d ? d->id : 0).arg(reply->errorString()));
if (d) {
failed(d);
}
}
void ImageLinkManager::failed(ImageLinkData *data) {
data->loading = false;
data->thumb = *black;
serverRedirects.remove(data);
}
void ImageLinkData::load() {
if (!thumb->isNull()) return thumb->load(false, false);
if (loading) return;
loading = true;
manager.getData(this);
}
void ContextResult::automaticLoadGif() const {
}
QByteArray ContextResult::data() const {
return _data;
}
bool ContextResult::loading() const {
return false;
}
bool ContextResult::loaded() const {
return false;
}
bool ContextResult::displayLoading() const {
return false;
}
void ContextResult::forget() {
}
float64 ContextResult::progress() const {
return 0.;
}
void PeerLink::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton && App::main()) {
if (peer() && peer()->isChannel() && App::main()->historyPeer() != peer()) {

View file

@ -1289,6 +1289,93 @@ struct WebPageData {
};
void initImageLinkManager();
void reinitImageLinkManager();
void deinitImageLinkManager();
enum ImageLinkType {
InvalidImageLink = 0,
GoogleMapsLink
};
struct ImageLinkData {
ImageLinkData(const QString &id) : id(id), type(InvalidImageLink), loading(false) {
}
QString id;
ImagePtr thumb;
ImageLinkType type;
bool loading;
void load();
};
class ImageLinkManager : public QObject {
Q_OBJECT
public:
ImageLinkManager() : manager(0), black(0) {
}
void init();
void reinit();
void deinit();
void getData(ImageLinkData *data);
~ImageLinkManager() {
deinit();
}
public slots:
void onFinished(QNetworkReply *reply);
void onFailed(QNetworkReply *reply);
private:
void failed(ImageLinkData *data);
QNetworkAccessManager *manager;
QMap<QNetworkReply*, ImageLinkData*> dataLoadings, imageLoadings;
QMap<ImageLinkData*, int32> serverRedirects;
ImagePtr *black;
};
class ContextResult {
public:
ContextResult(uint64 queryId)
: queryId(queryId)
, doc(0)
, photo(0)
, width(0)
, height(0)
, duration(0)
, noWebPage(false) {
}
uint64 queryId;
QString id, type;
DocumentData *doc;
PhotoData *photo;
QString title, description, url, thumb_url;
QString content_type, content_url;
int32 width, height, duration;
QString message; // botContextMessageText
bool noWebPage;
EntitiesInText entities;
QString caption; // if message.isEmpty() use botContextMessageMediaAuto
ImagePtr thumb;
void automaticLoadGif() const;
QByteArray data() const;
bool loading() const;
bool loaded() const;
bool displayLoading() const;
void forget();
float64 progress() const;
private:
QByteArray _data;
};
typedef QList<ContextResult*> ContextResults;
QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir());
MsgId clientMsgId();

View file

@ -255,10 +255,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_history.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_historywidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -389,6 +385,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_structs.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_sysbuttons.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -513,10 +513,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_history.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_historywidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -647,6 +643,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_structs.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_sysbuttons.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -797,10 +797,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_history.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_historywidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@ -931,6 +927,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_structs.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_sysbuttons.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@ -1625,18 +1625,24 @@
<ClInclude Include="SourceFiles\gui\style_core.h" />
<ClInclude Include="SourceFiles\gui\text.h" />
<CustomBuild Include="SourceFiles\history.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing history.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" "-fstdafx.h" "-f../../SourceFiles/history.h"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing history.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl_debug\Debug\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" "-fstdafx.h" "-f../../SourceFiles/history.h"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing history.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" "-fstdafx.h" "-f../../SourceFiles/history.h"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">
</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">
</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">
</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</Command>
</CustomBuild>
<CustomBuild Include="SourceFiles\historywidget.h">
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing historywidget.h...</Message>
@ -2018,7 +2024,20 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="SourceFiles\settings.h" />
<ClInclude Include="SourceFiles\structs.h" />
<CustomBuild Include="SourceFiles\structs.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing structs.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/structs.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing structs.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/structs.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl_debug\Debug\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing structs.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/structs.h" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui"</Command>
</CustomBuild>
<ClInclude Include="SourceFiles\style.h" />
<CustomBuild Include="SourceFiles\sysbuttons.h">
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing sysbuttons.h...</Message>

View file

@ -663,15 +663,6 @@
<ClCompile Include="GeneratedFiles\Release\moc_usernamebox.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_history.cpp">
<Filter>Generated Files\Deploy</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_history.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_history.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\types.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -897,6 +888,15 @@
<ClCompile Include="SourceFiles\layout.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_structs.cpp">
<Filter>Generated Files\Deploy</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_structs.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_structs.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SourceFiles\stdafx.h">
@ -977,9 +977,6 @@
<ClInclude Include="SourceFiles\pspecific_mac_p.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\structs.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\numbers.h">
<Filter>Source Files</Filter>
</ClInclude>
@ -1210,6 +1207,9 @@
<CustomBuild Include="SourceFiles\layout.h">
<Filter>Source Files</Filter>
</CustomBuild>
<CustomBuild Include="SourceFiles\structs.h">
<Filter>Source Files</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<None Include="SourceFiles\langs\lang_it.strings">