fixed mail links in Win10, include muted chats in the unread badge setting, shared links overview and search, version 0.8.53.dev

This commit is contained in:
John Preston 2015-08-28 18:15:56 +03:00
parent bfde1d2143
commit 9a51e2c7e3
37 changed files with 1253 additions and 211 deletions

View File

@ -1,11 +1,11 @@
@echo OFF
set "AppVersionStrMajor=0.8"
set "AppVersion=8052"
set "AppVersionStrSmall=0.8.52"
set "AppVersionStr=0.8.52"
set "AppVersionStrFull=0.8.52.0"
set "DevChannel=0"
set "AppVersion=8053"
set "AppVersionStrSmall=0.8.53"
set "AppVersionStr=0.8.53"
set "AppVersionStrFull=0.8.53.0"
set "DevChannel=1"
if %DevChannel% neq 0 goto preparedev

View File

@ -188,6 +188,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_settings_show_preview" = "Show message preview";
"lng_settings_use_windows" = "Use Windows notifications";
"lng_settings_sound_notify" = "Play sound";
"lng_settings_include_muted" = "Include muted chats in the unread badge";
"lng_notification_preview" = "You have a new message";
@ -386,6 +387,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_files_header" = "Files overview";
"lng_profile_audios" = "{count:_not_used_|# voice message|# voice messages} »";
"lng_profile_audios_header" = "Voice messages overview";
"lng_profile_shared_links" = "{count:_not_used_|# shared link|# shared links} »";
"lng_profile_shared_links_header" = "Shared links overview";
"lng_profile_audio_files_header" = "Playlist";
"lng_profile_show_all_types" = "Show all types";
"lng_profile_copy_phone" = "Copy phone number";
@ -443,6 +446,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_media_type_videos" = "Video files";
"lng_media_type_files" = "Files";
"lng_media_type_audios" = "Voice messages";
"lng_media_type_links" = "Shared links";
"lng_media_open_with" = "Open With";
"lng_media_download" = "Download";

View File

@ -1451,6 +1451,10 @@ dropdownMediaAudios: iconedButton(dropdownMediaDocuments) {
icon: sprite(62px, 348px, 24px, 24px);
downIcon: sprite(62px, 348px, 24px, 24px);
}
dropdownMediaLinks: iconedButton(dropdownMediaDocuments) {
icon: sprite(372px, 414px, 24px, 24px);
downIcon: sprite(62px, 348px, 24px, 24px);
}
dragFont: font(28px semibold);
dragSubfont: font(20px semibold);
@ -2002,3 +2006,15 @@ playerDuration: 200;
playlistHoverBg: #f2f2f2;
playlistPadding: 10px;
linksSearchMargin: margins(20px, 20px, 20px, 0px);
linksMaxWidth: 520px;
linksLetterFont: font(24px);
linksMargin: 5px;
linksBorder: 1px;
linksBorderColor: #eaeaea;
linksDateColor: #000;
linksDateMargin: 15px;
linksPhotoCheck: sprite(184px, 196px, 16px, 16px);
linksPhotoChecked: sprite(168px, 196px, 16px, 16px);

View File

@ -1843,6 +1843,12 @@ namespace App {
prepareCorners(BotKeyboardCorners, st::msgRadius, st::botKbBg);
prepareCorners(BotKeyboardOverCorners, st::msgRadius, st::botKbOverBg);
prepareCorners(BotKeyboardDownCorners, st::msgRadius, st::botKbDownBg);
prepareCorners(PhotoSelectOverlayCorners, st::msgRadius, st::overviewPhotoSelectOverlay);
prepareCorners(DocRedCorners, st::msgRadius, st::mvDocRedColor);
prepareCorners(DocYellowCorners, st::msgRadius, st::mvDocYellowColor);
prepareCorners(DocGreenCorners, st::msgRadius, st::mvDocGreenColor);
prepareCorners(DocBlueCorners, st::msgRadius, st::mvDocBlueColor);
prepareCorners(MessageInCorners, st::msgRadius, st::msgInBg, &st::msgInShadow);
prepareCorners(MessageInSelectedCorners, st::msgRadius, st::msgInSelectBg, &st::msgInSelectShadow);

View File

@ -58,6 +58,12 @@ enum RoundCorners {
BotKeyboardCorners,
BotKeyboardOverCorners,
BotKeyboardDownCorners,
PhotoSelectOverlayCorners,
DocRedCorners,
DocYellowCorners,
DocGreenCorners,
DocBlueCorners,
InShadowCorners, // for photos without bg
InSelectedShadowCorners,

View File

@ -673,8 +673,8 @@ void Application::checkMapVersion() {
if (Local::oldMapVersion() < AppVersion) {
if (Local::oldMapVersion()) {
QString versionFeatures;
if (cDevVersion() && Local::oldMapVersion() < 8050) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Bug fixes in Windows notifications\n\xe2\x80\x94 Fixed input methods on Linux (Fcitx and IBus)");// .replace('@', qsl("@") + QChar(0x200D));
if (cDevVersion() && Local::oldMapVersion() < 8053) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Include muted chats in the unread badge setting\n\xe2\x80\x94 Shared links overview and search in shared media");// .replace('@', qsl("@") + QChar(0x200D));
} else if (!cDevVersion() && Local::oldMapVersion() < 8052) {
versionFeatures = lang(lng_new_version_minor).trimmed();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 222 KiB

View File

@ -16,13 +16,13 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
#include "stdafx.h"
#include "application.h"
#include "pspecific.h"
#include "autoupdater.h"
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
#ifdef Q_OS_WIN
typedef DWORD VerInt;
typedef WCHAR VerChar;

View File

@ -17,9 +17,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#pragma once
static const int32 AppVersion = 8052;
static const wchar_t *AppVersionStr = L"0.8.52";
static const bool DevVersion = false;
static const int32 AppVersion = 8053;
static const wchar_t *AppVersionStr = L"0.8.53";
static const bool DevVersion = true;
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop";
@ -81,6 +81,7 @@ enum {
AutoSearchTimeout = 900, // 0.9 secs
SearchPerPage = 50,
SearchManyPerPage = 100,
LinksOverviewPerPage = 12,
MediaOverviewStartPerPage = 5,
MediaOverviewPreloadCount = 4,

View File

@ -1700,7 +1700,6 @@ bool DialogsWidget::onSearchMessages(bool searchCache) {
return false;
}
void DialogsWidget::onNeedSearchMessages() {
if (!onSearchMessages(true)) {
_searchTimer.start(AutoSearchTimeout);

View File

@ -20,6 +20,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "lang.h"
#include "pspecific.h"
#include <private/qharfbuzz_p.h>
namespace {
@ -788,6 +790,15 @@ void TextLink::onClick(Qt::MouseButton button) const {
}
}
void EmailLink::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
QUrl url(qstr("mailto:") + _email);
if (!QDesktopServices::openUrl(url)) {
psOpenFile(url.toString(QUrl::FullyEncoded), true);
}
}
}
void MentionLink::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
App::openUserByName(_tag.mid(1), true);

View File

@ -369,11 +369,7 @@ public:
return _email;
}
void onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
QDesktopServices::openUrl(qsl("mailto:") + _email);
}
}
void onClick(Qt::MouseButton button) const;
const QString &readable() const {
return _email;

View File

@ -644,12 +644,24 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, boo
}
const MTPMessageMedia *media = 0;
const QVector<MTPMessageEntity> *entities = 0;
switch (msg.type()) {
case mtpc_message: media = &msg.c_message().vmedia; break;
case mtpc_message:
media = &msg.c_message().vmedia;
entities = msg.c_message().has_entities() ? (&msg.c_message().ventities.c_vector().v) : 0;
break;
}
if (media) {
existing->updateMedia(*media);
}
if (entities && !existing->hasTextLinks()) { // index forwarded messages to links overview
existing->setText(qs(msg.c_message().vmessage), linksFromMTP(*entities));
existing->initDimensions(0);
if (App::main()) App::main()->itemResized(existing);
if (existing->hasTextLinks()) {
existing->history()->addToOverview(existing, OverviewLinks);
}
}
return (returnExisting || regged) ? existing : 0;
}
@ -888,6 +900,24 @@ void History::createInitialDateBlock(const QDateTime &date) {
push_front(dateBlock); // date block
}
void History::addToOverview(HistoryItem *item, MediaOverviewType type) {
if (_overviewIds[type].constFind(item->id) == _overviewIds[type].cend()) {
_overview[type].push_back(item->id);
_overviewIds[type].insert(item->id, NullType());
if (_overviewCount[type] > 0) ++_overviewCount[type];
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, type);
}
}
bool History::addToOverviewFront(HistoryItem *item, MediaOverviewType type) {
if (_overviewIds[type].constFind(item->id) == _overviewIds[type].cend()) {
_overview[type].push_front(item->id);
_overviewIds[type].insert(item->id, NullType());
return true;
}
return false;
}
HistoryItem *History::doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg) {
if (!adding) {
if (newBlock) delete to;
@ -928,31 +958,14 @@ HistoryItem *History::doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *
HistoryMediaType mt = media->type();
MediaOverviewType t = mediaToOverviewType(mt);
if (t != OverviewCount) {
if (_overviewIds[t].constFind(adding->id) == _overviewIds[t].cend()) {
_overview[t].push_back(adding->id);
_overviewIds[t].insert(adding->id, NullType());
if (_overviewCount[t] > 0) ++_overviewCount[t];
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, t);
}
addToOverview(adding, t);
if (mt == MediaTypeDocument && static_cast<HistoryDocument*>(media)->document()->song()) {
t = OverviewAudioDocuments;
if (_overviewIds[t].constFind(adding->id) == _overviewIds[t].cend()) {
_overview[t].push_back(adding->id);
_overviewIds[t].insert(adding->id, NullType());
if (_overviewCount[t] > 0) ++_overviewCount[t];
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, t);
}
addToOverview(adding, OverviewAudioDocuments);
}
}
}
if (adding->hasTextLinks()) {
MediaOverviewType t = OverviewLinks;
if (_overviewIds[t].constFind(adding->id) == _overviewIds[t].cend()) {
_overview[t].push_back(adding->id);
_overviewIds[t].insert(adding->id, NullType());
if (_overviewCount[t] > 0) ++_overviewCount[t];
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, t);
}
addToOverview(adding, OverviewLinks);
}
if (adding->from()->id) {
if (peer->chat) {
@ -1102,28 +1115,14 @@ void History::addToFront(const QVector<MTPMessage> &slice) {
HistoryMediaType mt = media->type();
MediaOverviewType t = mediaToOverviewType(mt);
if (t != OverviewCount) {
if (_overviewIds[t].constFind(item->id) == _overviewIds[t].cend()) {
_overview[t].push_front(item->id);
_overviewIds[t].insert(item->id, NullType());
mask |= (1 << t);
}
if (addToOverviewFront(item, t)) mask |= (1 << t);
if (mt == MediaTypeDocument && static_cast<HistoryDocument*>(media)->document()->song()) {
t = OverviewAudioDocuments;
if (_overviewIds[t].constFind(item->id) == _overviewIds[t].cend()) {
_overview[t].push_front(item->id);
_overviewIds[t].insert(item->id, NullType());
mask |= (1 << t);
}
if (addToOverviewFront(item, OverviewAudioDocuments)) mask |= (1 << OverviewAudioDocuments);
}
}
}
if (item->hasTextLinks()) {
MediaOverviewType t = OverviewLinks;
if (_overviewIds[t].constFind(item->id) == _overviewIds[t].cend()) {
_overview[t].push_front(item->id);
_overviewIds[t].insert(item->id, NullType());
mask |= (1 << t);
}
if (addToOverviewFront(item, OverviewLinks)) mask |= (1 << OverviewLinks);
}
if (item->from()->id) {
if (lastAuthors) { // chats
@ -1348,7 +1347,7 @@ void History::setUnreadCount(int32 newUnreadCount, bool psUpdate) {
App::histories().unreadFull += newUnreadCount - unreadCount;
if (mute) App::histories().unreadMuted += newUnreadCount - unreadCount;
unreadCount = newUnreadCount;
if (psUpdate) App::wnd()->updateCounter();
if (psUpdate && (!mute || cIncludeMuted())) App::wnd()->updateCounter();
if (unreadBar) unreadBar->setCount(unreadCount);
}
}
@ -5273,6 +5272,12 @@ void HistoryMessage::setText(const QString &text, const LinksInText &links) {
}
}
void HistoryMessage::getTextWithLinks(QString &text, LinksInText &links) {
if (_text.isEmpty()) return;
links = _text.calcLinksInText();
text = _text.original();
}
void HistoryMessage::draw(QPainter &p, uint32 selection) const {
textstyleSet(&(out() ? st::outTextStyle : st::inTextStyle));

View File

@ -185,6 +185,8 @@ struct History : public QList<HistoryBlock*> {
void addToBack(const QVector<MTPMessage> &slice);
void createInitialDateBlock(const QDateTime &date);
HistoryItem *doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg);
void addToOverview(HistoryItem *item, MediaOverviewType type);
bool addToOverviewFront(HistoryItem *item, MediaOverviewType type);
void newItemAdded(HistoryItem *item);
void unregTyping(UserData *from);
@ -782,6 +784,8 @@ public:
}
virtual void setText(const QString &text, const LinksInText &links) {
}
virtual void getTextWithLinks(QString &text, LinksInText &links) {
}
virtual QString time() const {
return QString();
}
@ -1181,6 +1185,10 @@ public:
}
ImagePtr replyPreview();
WebPageData *webpage() {
return data;
}
private:
WebPageData *data;
TextLinkPtr _openl, _photol;
@ -1328,6 +1336,7 @@ public:
HistoryMedia *getMedia(bool inOverview = false) const;
void setMedia(const MTPmessageMedia &media);
void setText(const QString &text, const LinksInText &links);
void getTextWithLinks(QString &text, LinksInText &links);
QString time() const {
return _time;

View File

@ -730,6 +730,14 @@ namespace {
cSetSoundNotify(v == 1);
} break;
case dbiIncludeMuted: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
cSetIncludeMuted(v == 1);
} break;
case dbiDesktopNotify: {
qint32 v;
stream >> v;
@ -1281,7 +1289,7 @@ namespace {
_writeMap(WriteMapFast);
}
uint32 size = 13 * (sizeof(quint32) + sizeof(qint32));
uint32 size = 14 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath());
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
@ -1295,6 +1303,7 @@ namespace {
data.stream << quint32(dbiReplaceEmojis) << qint32(cReplaceEmojis() ? 1 : 0);
data.stream << quint32(dbiDefaultAttach) << qint32(cDefaultAttach());
data.stream << quint32(dbiSoundNotify) << qint32(cSoundNotify());
data.stream << quint32(dbiIncludeMuted) << qint32(cIncludeMuted());
data.stream << quint32(dbiDesktopNotify) << qint32(cDesktopNotify());
data.stream << quint32(dbiNotifyView) << qint32(cNotifyView());
data.stream << quint32(dbiWindowsNotifications) << qint32(cWindowsNotifications());

View File

@ -1183,6 +1183,7 @@ void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
case OverviewVideos: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaVideos, lang(lng_media_type_videos))), SIGNAL(clicked()), this, SLOT(onVideosSelect())); break;
case OverviewDocuments: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaDocuments, lang(lng_media_type_files))), SIGNAL(clicked()), this, SLOT(onDocumentsSelect())); break;
case OverviewAudios: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaAudios, lang(lng_media_type_audios))), SIGNAL(clicked()), this, SLOT(onAudiosSelect())); break;
case OverviewLinks: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaLinks, lang(lng_media_type_links))), SIGNAL(clicked()), this, SLOT(onLinksSelect())); break;
}
}
}
@ -1203,6 +1204,9 @@ void MainWidget::itemRemoved(HistoryItem *item) {
if (history.peer() == item->history()->peer) {
history.itemRemoved(item);
}
if (overview && overview->peer() == item->history()->peer) {
overview->itemRemoved(item);
}
itemRemovedGif(item);
if (!_toForward.isEmpty()) {
SelectedItemSet::iterator i = _toForward.find(item->id);
@ -2240,9 +2244,13 @@ void MainWidget::sentDataReceived(uint64 randomId, const MTPmessages_SentMessage
if (!text.isEmpty() && !links.isEmpty()) {
item = App::histItemById(d.vid.v);
if (item) {
bool was = item->hasTextLinks();
item->setText(text, links);
item->initDimensions(0);
itemResized(item);
if (!was && item->hasTextLinks()) {
item->history()->addToOverview(item, OverviewLinks);
}
}
}
}
@ -2273,9 +2281,13 @@ void MainWidget::sentDataReceived(uint64 randomId, const MTPmessages_SentMessage
//if (!text.isEmpty() && !links.isEmpty()) {
// item = App::histItemById(d.vid.v);
// if (item) {
// bool was = item->hasTextLinks();
// item->setText(text, links);
// item->initDimensions(0);
// itemResized(item);
// if (!was && item->hasTextLinks()) {
// item->history()->addToOverview(item, OverviewLinks);
// }
// }
//}
}
@ -2544,6 +2556,11 @@ void MainWidget::onAudiosSelect() {
_mediaType.hideStart();
}
void MainWidget::onLinksSelect() {
if (overview) overview->switchType(OverviewLinks);
_mediaType.hideStart();
}
TopBarWidget *MainWidget::topBar() {
return &_topBar;
}
@ -3389,7 +3406,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates) {
return;
}
bool out = (d.vflags.v & MTPDmessage_flag_out);
HistoryItem *item = App::histories().addToBack(MTP_message(d.vflags, d.vid, out ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(out ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, MTPnullEntities));
HistoryItem *item = App::histories().addToBack(MTP_message(d.vflags, d.vid, out ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(out ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}
@ -3409,7 +3426,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates) {
_byPtsUpdates.insert(ptsKey(SkippedUpdates), updates);
return;
}
HistoryItem *item = App::histories().addToBack(MTP_message(d.vflags, d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, MTPnullEntities));
HistoryItem *item = App::histories().addToBack(MTP_message(d.vflags, d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}

View File

@ -429,6 +429,7 @@ public slots:
void onVideosSelect();
void onDocumentsSelect();
void onAudiosSelect();
void onLinksSelect();
void onForwardCancel(QObject *obj = 0);

File diff suppressed because it is too large Load Diff

View File

@ -25,9 +25,14 @@ public:
OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const PeerData *peer, MediaOverviewType type);
void activate();
void clear();
int32 itemTop(MsgId msgId) const;
bool preloadLocal();
void preloadMore();
bool event(QEvent *e);
void touchEvent(QTouchEvent *e);
void paintEvent(QPaintEvent *e);
@ -75,6 +80,7 @@ public slots:
void onUpdateSelected();
void openContextUrl();
void copyContextUrl();
void cancelContextDownload();
void showContextInFolder();
void saveContextFile();
@ -85,12 +91,19 @@ public slots:
void forwardMessage();
void selectMessage();
void onSearchUpdate();
void onCancel();
bool onCancelSearch();
void onMenuDestroy(QObject *obj);
void onTouchSelect();
void onTouchScrollTimer();
void onDragExec();
bool onSearchMessages(bool searchCache = false);
void onNeedSearchMessages();
private:
void fixItemIndex(int32 &current, MsgId msgId) const;
@ -122,11 +135,11 @@ private:
// photos
int32 _photosInRow, _photosToAdd, _vsize;
typedef struct {
struct CachedSize {
int32 vsize;
bool medium;
QPixmap pix;
} CachedSize;
};
typedef QMap<PhotoData*, CachedSize> CachedSizes;
CachedSizes _cached;
bool _selMode;
@ -134,16 +147,65 @@ private:
// audio documents
int32 _audioLeft, _audioWidth, _audioHeight;
// other
typedef struct _CachedItem {
_CachedItem() : msgid(0), y(0) {
// shared links
int32 _linksLeft, _linksWidth;
struct Link {
Link() : width(0) {
}
_CachedItem(MsgId msgid, const QDate &date, int32 y) : msgid(msgid), date(date), y(y) {
Link(const QString &url, const QString &text) : url(url), text(text), width(st::msgFont->m.width(text)) {
}
QString url, text;
int32 width;
};
struct CachedLink {
CachedLink() : titleWidth(0), page(0), pixw(0), pixh(0), text(st::msgMinWidth) {
}
CachedLink(HistoryItem *item);
int32 countHeight(int32 w);
QString title, letter;
int32 titleWidth;
WebPageData *page;
int32 pixw, pixh;
Text text;
QVector<Link> urls;
};
typedef QMap<MsgId, CachedLink*> CachedLinks;
CachedLinks _links;
FlatInput _search;
IconedButton _cancelSearch;
QVector<MsgId> _results;
int32 _itemsToBeLoaded;
QTimer _searchTimer;
QString _searchQuery;
bool _inSearch, _searchFull;
mtpRequestId _searchRequest;
History::MediaOverview _searchResults;
MsgId _lastSearchId;
int32 _searchedCount;
void searchReceived(bool fromStart, const MTPmessages_Messages &result, mtpRequestId req);
bool searchFailed(const RPCError &error, mtpRequestId req);
typedef QMap<QString, MTPmessages_Messages> SearchCache;
SearchCache _searchCache;
typedef QMap<mtpRequestId, QString> SearchQueries;
SearchQueries _searchQueries;
CachedLink *cachedLink(HistoryItem *item);
// other
struct CachedItem {
CachedItem() : msgid(0), y(0) {
}
CachedItem(MsgId msgid, const QDate &date, int32 y) : msgid(msgid), date(date), y(y) {
}
MsgId msgid;
QDate date;
int32 y;
} CachedItem;
CachedLink *link;
};
typedef QVector<CachedItem> CachedItems;
CachedItems _items;
@ -166,9 +228,14 @@ private:
int32 _dragItemIndex;
MsgId _mousedItem;
int32 _mousedItemIndex;
int32 _lnkOverIndex, _lnkDownIndex; // for OverviewLinks, 0 - none, -1 - photo or title, > 0 - lnk index
uint16 _dragSymbol;
bool _dragWasInactive;
QString urlByIndex(MsgId msgid, int32 index, int32 lnkIndex) const;
bool urlIsEmail(const QString &url) const;
QString _contextMenuUrl;
TextLinkPtr _contextMenuLnk;
MsgId _dragSelFrom, _dragSelTo;
@ -202,6 +269,7 @@ public:
void contextMenuEvent(QContextMenuEvent *e);
void scrollBy(int32 add);
void scrollReset();
void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
void topBarShadowParams(int32 &x, float64 &o);

View File

@ -59,10 +59,6 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
// shared media
_allMediaTypes(false),
_mediaShowAll(this, lang(lng_profile_show_all_types)),
_mediaPhotos(this, QString()),
_mediaVideos(this, QString()),
_mediaDocuments(this, QString()),
_mediaAudios(this, QString()),
// actions
_searchInPeer(this, lang(lng_profile_search_messages)),
@ -161,14 +157,11 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
// shared media
connect(&_mediaShowAll, SIGNAL(clicked()), this, SLOT(onMediaShowAll()));
connect(&_mediaPhotos, SIGNAL(clicked()), this, SLOT(onMediaPhotos()));
connect(&_mediaVideos, SIGNAL(clicked()), this, SLOT(onMediaVideos()));
connect(&_mediaDocuments, SIGNAL(clicked()), this, SLOT(onMediaDocuments()));
connect(&_mediaAudios, SIGNAL(clicked()), this, SLOT(onMediaAudios()));
_mediaLinks[OverviewPhotos] = &_mediaPhotos;
_mediaLinks[OverviewVideos] = &_mediaVideos;
_mediaLinks[OverviewDocuments] = &_mediaDocuments;
_mediaLinks[OverviewAudios] = &_mediaAudios;
connect((_mediaButtons[OverviewPhotos] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaPhotos()));
connect((_mediaButtons[OverviewVideos] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaVideos()));
connect((_mediaButtons[OverviewDocuments] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaDocuments()));
connect((_mediaButtons[OverviewAudios] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaAudios()));
connect((_mediaButtons[OverviewLinks] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaLinks()));
App::main()->preloadOverviews(_peer);
// actions
@ -216,7 +209,7 @@ void ProfileInner::loadProfilePhotos(int32 yFrom) {
int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5;
MTP::clearLoaderPriorities();
int32 partfrom = _mediaAudios.y() + _mediaAudios.height() + st::profileHeaderSkip;
int32 partfrom = _mediaButtons[OverviewAudios]->y() + _mediaButtons[OverviewAudios]->height() + st::profileHeaderSkip;
yFrom -= partfrom;
yTo -= partfrom;
@ -361,6 +354,10 @@ void ProfileInner::onMediaAudios() {
App::main()->showMediaOverview(_peer, OverviewAudios);
}
void ProfileInner::onMediaLinks() {
App::main()->showMediaOverview(_peer, OverviewLinks);
}
void ProfileInner::onInvitationLink() {
QApplication::clipboard()->setText(_peerChat->invitationUrl);
App::wnd()->showLayer(new ConfirmBox(lang(lng_group_invite_copied), true));
@ -652,7 +649,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
if (!_allMediaTypes) {
break;
}
top += _mediaLinks[i]->height() + st::setLittleSkip;
top += _mediaButtons[i]->height() + st::setLittleSkip;
}
}
if (_allMediaTypes) {
@ -660,13 +657,13 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
top -= st::setLittleSkip;
} else {
p.drawText(_left, top + st::linkFont->ascent, lang(oneState < 0 ? lng_profile_loading : lng_profile_no_media));
top += _mediaLinks[OverviewPhotos]->height();
top += _mediaButtons[OverviewPhotos]->height();
}
} else {
if (!oneState) {
p.drawText(_left, top + st::linkFont->ascent, lang(lng_profile_no_media));
}
top += _mediaLinks[OverviewPhotos]->height();
top += _mediaButtons[OverviewPhotos]->height();
}
// actions
@ -934,13 +931,13 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
if (_allMediaTypes) {
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
if (count > 0) {
if (wasCount) top += _mediaLinks[i]->height() + st::setLittleSkip;
if (wasCount) top += _mediaButtons[i]->height() + st::setLittleSkip;
wasCount = count;
}
}
_mediaLinks[i]->move(_left, top);
_mediaButtons[i]->move(_left, top);
}
top += _mediaLinks[OverviewPhotos]->height();
top += _mediaButtons[OverviewPhotos]->height();
// actions
top += st::profileHeaderSkip;
@ -1131,17 +1128,17 @@ void ProfileInner::showAll() {
if (count > 0 || count < 0) {
first = true;
} else if (!_allMediaTypes) {
_mediaLinks[i]->hide();
_mediaButtons[i]->hide();
continue;
}
if (count > 0) {
_mediaLinks[i]->setText(overviewLinkText(i, count));
_mediaLinks[i]->show();
_mediaButtons[i]->setText(overviewLinkText(i, count));
_mediaButtons[i]->show();
} else {
_mediaLinks[i]->hide();
_mediaButtons[i]->hide();
}
} else {
_mediaLinks[i]->hide();
_mediaButtons[i]->hide();
}
}
if (_allMediaTypes || !manyCounts) {
@ -1208,6 +1205,7 @@ QString ProfileInner::overviewLinkText(int32 type, int32 count) {
case OverviewVideos: return lng_profile_videos(lt_count, count);
case OverviewDocuments: return lng_profile_files(lt_count, count);
case OverviewAudios: return lng_profile_audios(lt_count, count);
case OverviewLinks: return lng_profile_shared_links(lt_count, count);
}
return QString();
}

View File

@ -92,6 +92,7 @@ public slots:
void onMediaVideos();
void onMediaDocuments();
void onMediaAudios();
void onMediaLinks();
void onMenuDestroy(QObject *obj);
void onCopyPhone();
@ -149,8 +150,8 @@ private:
// shared media
bool _allMediaTypes;
LinkButton _mediaShowAll, _mediaPhotos, _mediaVideos, _mediaDocuments, _mediaAudios;
LinkButton *_mediaLinks[OverviewCount];
LinkButton _mediaShowAll;
LinkButton *_mediaButtons[OverviewCount];
QString overviewLinkText(int32 type, int32 count);
// actions

View File

@ -252,8 +252,8 @@ namespace {
#define GTK_ALPHA 3
QImage _trayIconImageGen() {
int32 counter = App::histories().unreadFull, counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = (App::histories().unreadMuted >= counter);
int32 counter = App::histories().unreadFull - (cIncludeMuted() ? 0 : App::histories().unreadMuted), counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = cIncludeMuted() ? (App::histories().unreadMuted >= counter) : false;
if (_trayIconImage.isNull() || _trayIconImage.width() != _trayIconSize || muted != _trayIconMuted || counterSlice != _trayIconCount) {
if (_trayIconImageBack.isNull() || _trayIconImageBack.width() != _trayIconSize) {
_trayIconImageBack = App::wnd()->iconLarge().scaled(_trayIconSize, _trayIconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
@ -288,8 +288,8 @@ namespace {
}
QString _trayIconImageFile() {
int32 counter = App::histories().unreadFull, counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = (App::histories().unreadMuted >= counter);
int32 counter = App::histories().unreadFull - (cIncludeMuted() ? 0 : App::histories().unreadMuted), counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = cIncludeMuted() ? (App::histories().unreadMuted >= counter) : false;
QString name = cWorkingDir() + qsl("tdata/ticons/ico%1_%2_%3.png").arg(muted ? "mute" : "").arg(_trayIconSize).arg(counterSlice);
QFileInfo info(name);
@ -641,7 +641,7 @@ void PsMainWindow::psUpdateIndicator() {
void PsMainWindow::psUpdateCounter() {
setWindowIcon(wndIcon);
int32 counter = App::histories().unreadFull;
int32 counter = App::histories().unreadFull - (cIncludeMuted() ? 0 : App::histories().unreadMuted);
setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram"));
if (_psUnityLauncherEntry) {
@ -665,8 +665,10 @@ void PsMainWindow::psUpdateCounter() {
ps_gtk_status_icon_set_from_pixbuf(_trayIcon, _trayPixbuf);
}
} else if (trayIcon) {
int32 counter = App::histories().unreadFull;
style::color bg = (App::histories().unreadMuted < counter) ? st::counterBG : st::counterMuteBG;
int32 counter = App::histories().unreadFull - (cIncludeMuted() ? 0 : App::histories().unreadMuted);
bool muted = cIncludeMuted() ? (App::histories().unreadMuted >= counter) : false;
style::color bg = muted ? st::counterMuteBG : st::counterBG;
QIcon iconSmall;
iconSmall.addPixmap(QPixmap::fromImage(iconWithCounter(16, counter, bg, true), Qt::ColorOnly));
iconSmall.addPixmap(QPixmap::fromImage(iconWithCounter(32, counter, bg, true), Qt::ColorOnly));

View File

@ -174,7 +174,7 @@ void _placeCounter(QImage &img, int size, int count, style::color bg, style::col
}
void PsMainWindow::psUpdateCounter() {
int32 counter = App::histories().unreadFull;
int32 counter = App::histories().unreadFull - (cIncludeMuted() ? 0 : App::histories().unreadMuted);
setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram"));
setWindowIcon(wndIcon);
@ -183,14 +183,16 @@ void PsMainWindow::psUpdateCounter() {
_private.setWindowBadge(counter ? cnt : QString());
if (trayIcon) {
bool dm = objc_darkMode(), important = (App::histories().unreadMuted < counter);
style::color bg = important ? st::counterBG : st::counterMuteBG;
bool muted = cIncludeMuted() ? (App::histories().unreadMuted >= counter) : false;
bool dm = objc_darkMode();
style::color bg = muted ? st::counterMuteBG : st::counterBG;
QIcon icon;
QImage img(psTrayIcon(dm)), imgsel(psTrayIcon(true));
img.detach();
imgsel.detach();
int32 size = cRetina() ? 44 : 22;
_placeCounter(img, size, counter, bg, (dm && !important) ? st::counterMacInvColor : st::counterColor);
_placeCounter(img, size, counter, bg, (dm && muted) ? st::counterMacInvColor : st::counterColor);
_placeCounter(imgsel, size, counter, st::white, st::counterMacInvColor);
icon.addPixmap(QPixmap::fromImage(img, Qt::ColorOnly));
icon.addPixmap(QPixmap::fromImage(imgsel, Qt::ColorOnly), QIcon::Selected);

View File

@ -1117,8 +1117,10 @@ static HICON _qt_createHIcon(const QIcon &icon, int xSize, int ySize) {
}
void PsMainWindow::psUpdateCounter() {
int32 counter = App::histories().unreadFull;
style::color bg = (App::histories().unreadMuted < counter) ? st::counterBG : st::counterMuteBG;
int32 counter = App::histories().unreadFull - (cIncludeMuted() ? 0 : App::histories().unreadMuted);
bool muted = cIncludeMuted() ? (App::histories().unreadMuted >= counter) : false;
style::color bg = muted ? st::counterMuteBG : st::counterBG;
QIcon iconSmall, iconBig;
iconSmall.addPixmap(QPixmap::fromImage(iconWithCounter(16, counter, bg, true), Qt::ColorOnly));
iconSmall.addPixmap(QPixmap::fromImage(iconWithCounter(32, counter, bg, true), Qt::ColorOnly));
@ -2123,12 +2125,14 @@ bool psShowOpenWithMenu(int x, int y, const QString &file) {
}
void psOpenFile(const QString &name, bool openWith) {
std::wstring wname = QDir::toNativeSeparators(name).toStdWString();
bool mailtoScheme = name.startsWith(qstr("mailto:"));
std::wstring wname = mailtoScheme ? name.toStdWString() : QDir::toNativeSeparators(name).toStdWString();
if (openWith && useOpenAs) {
if (shOpenWithDialog) {
OPENASINFO info;
info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC;
if (mailtoScheme) info.oaifInFlags |= OAIF_FILE_IS_URI | OAIF_URL_PROTOCOL;
info.pcszClass = NULL;
info.pcszFile = wname.c_str();
shOpenWithDialog(0, &info);

View File

@ -40,6 +40,7 @@ QString gLangErrors;
QString gDialogLastPath, gDialogHelperPath; // optimize QFileDialog
bool gSoundNotify = true;
bool gIncludeMuted = true;
bool gDesktopNotify = true;
DBINotifyView gNotifyView = dbinvShowPreview;
bool gWindowsNotifications = true;

View File

@ -96,6 +96,7 @@ DeclareSetting(QPixmapPointer, ChatDogImage);
DeclareSetting(bool, TileBackground);
DeclareSetting(bool, SoundNotify);
DeclareSetting(bool, IncludeMuted);
DeclareSetting(bool, NeedConfigResave);
DeclareSetting(bool, DesktopNotify);
DeclareSetting(DBINotifyView, NotifyView);

View File

@ -124,6 +124,7 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
_messagePreview(this, lang(lng_settings_show_preview), cNotifyView() <= dbinvShowPreview),
_windowsNotifications(this, lang(lng_settings_use_windows), cWindowsNotifications()),
_soundNotify(this, lang(lng_settings_sound_notify), cSoundNotify()),
_includeMuted(this, lang(lng_settings_include_muted), cIncludeMuted()),
// general
_changeLanguage(this, lang(lng_settings_change_lang)),
@ -225,6 +226,7 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
connect(&_messagePreview, SIGNAL(changed()), this, SLOT(onMessagePreview()));
connect(&_windowsNotifications, SIGNAL(changed()), this, SLOT(onWindowsNotifications()));
connect(&_soundNotify, SIGNAL(changed()), this, SLOT(onSoundNotify()));
connect(&_includeMuted, SIGNAL(changed()), this, SLOT(onIncludeMuted()));
// general
connect(&_changeLanguage, SIGNAL(clicked()), this, SLOT(onChangeLanguage()));
@ -431,7 +433,8 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
if (App::wnd()->psHasNativeNotifications() && cPlatform() == dbipWindows) {
top += _windowsNotifications.height() + st::setSectionSkip;
}
top += _soundNotify.height();
top += _soundNotify.height() + st::setSectionSkip;
top += _includeMuted.height();
}
// general
@ -662,7 +665,8 @@ void SettingsInner::resizeEvent(QResizeEvent *e) {
if (App::wnd()->psHasNativeNotifications() && cPlatform() == dbipWindows) {
_windowsNotifications.move(_left, top); top += _windowsNotifications.height() + st::setSectionSkip;
}
_soundNotify.move(_left, top); top += _soundNotify.height();
_soundNotify.move(_left, top); top += _soundNotify.height() + st::setSectionSkip;
_includeMuted.move(_left, top); top += _includeMuted.height();
}
// general
@ -976,12 +980,14 @@ void SettingsInner::showAll() {
_windowsNotifications.hide();
}
_soundNotify.show();
_includeMuted.show();
} else {
_desktopNotify.hide();
_senderName.hide();
_messagePreview.hide();
_windowsNotifications.hide();
_soundNotify.hide();
_includeMuted.hide();
}
// general
@ -1443,6 +1449,12 @@ void SettingsInner::onSoundNotify() {
Local::writeUserSettings();
}
void SettingsInner::onIncludeMuted() {
cSetIncludeMuted(_includeMuted.checked());
if (App::wnd()) App::wnd()->updateCounter();
Local::writeUserSettings();
}
void SettingsInner::onWindowsNotifications() {
cSetWindowsNotifications(!cWindowsNotifications());
App::wnd()->notifyClearFast();

View File

@ -125,6 +125,7 @@ public slots:
void onScaleChange();
void onSoundNotify();
void onIncludeMuted();
void onDesktopNotify();
void onSenderName();
void onMessagePreview();
@ -206,7 +207,7 @@ private:
LinkButton _chooseUsername;
// notifications
FlatCheckbox _desktopNotify, _senderName, _messagePreview, _windowsNotifications, _soundNotify;
FlatCheckbox _desktopNotify, _senderName, _messagePreview, _windowsNotifications, _soundNotify, _includeMuted;
// general
LinkButton _changeLanguage;

View File

@ -258,8 +258,10 @@ void TitleWidget::updateWideMode() {
void TitleWidget::updateCounter() {
if (cWideMode() || !MTP::authedId()) return;
int32 counter = App::histories().unreadFull;
style::color bg = (App::histories().unreadMuted < counter) ? st::counterBG : st::counterMuteBG;
int32 counter = App::histories().unreadFull - (cIncludeMuted() ? 0 : App::histories().unreadMuted);
bool muted = cIncludeMuted() ? (App::histories().unreadMuted >= counter) : false;
style::color bg = muted ? st::counterMuteBG : st::counterBG;
if (counter > 0) {
int32 size = cRetina() ? -32 : -16;

View File

@ -275,6 +275,7 @@ enum DataBlockId {
dbiTryIPv6 = 0x28,
dbiSongVolume = 0x29,
dbiWindowsNotifications = 0x30,
dbiIncludeMuted = 0x31,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,

View File

@ -11,7 +11,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.8.52</string>
<string>0.8.53</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>CFBundleSignature</key>

Binary file not shown.

View File

@ -1707,7 +1707,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.8.52;
CURRENT_PROJECT_VERSION = 0.8.53;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
@ -1725,7 +1725,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 0.8.52;
CURRENT_PROJECT_VERSION = 0.8.53;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@ -1751,10 +1751,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.8.52;
CURRENT_PROJECT_VERSION = 0.8.53;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 0.8;
DYLIB_CURRENT_VERSION = 0.8.52;
DYLIB_CURRENT_VERSION = 0.8.53;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@ -1885,10 +1885,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.8.52;
CURRENT_PROJECT_VERSION = 0.8.53;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.8;
DYLIB_CURRENT_VERSION = 0.8.52;
DYLIB_CURRENT_VERSION = 0.8.53;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;

View File

@ -1,2 +1,2 @@
echo 0.8 8052 0.8.52 0
echo 0.8 8053 0.8.53 1
# AppVersionStrMajor AppVersion AppVersionStr DevChannel

View File

@ -11566,6 +11566,22 @@ index da0ba27..1d42b79 100644
void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f)
{
m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time.
diff --git a/qtbase/src/plugins/platforms/windows/qwindowsservices.cpp b/qtbase/src/plugins/platforms/windows/qwindowsservices.cpp
index cc697ba..8e15e86 100644
--- a/qtbase/src/plugins/platforms/windows/qwindowsservices.cpp
+++ b/qtbase/src/plugins/platforms/windows/qwindowsservices.cpp
@@ -125,8 +125,9 @@ static inline bool launchMail(const QUrl &url)
}
// Pass the url as the parameter. Should use QProcess::startDetached(),
// but that cannot handle a Windows command line [yet].
- command.replace(QStringLiteral("%1"), url.toString(QUrl::FullyEncoded));
- if (debug)
+ if (command.indexOf(QStringLiteral("%1")) < 0) return false;
+ command.replace(QStringLiteral("%1"), url.toString(QUrl::FullyEncoded));
+ if (debug)
qDebug() << __FUNCTION__ << "Launching" << command;
//start the process
PROCESS_INFORMATION pi;
diff --git a/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp b/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp
index 543c081..d80429b 100644
--- a/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp

View File

@ -0,0 +1,160 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#define QT_NO_URL_CAST_FROM_STRING
#include "qwindowsservices.h"
#include "qtwindows_additional.h"
#include <QtCore/QUrl>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <shlobj.h>
#ifndef Q_OS_WINCE
# include <intshcut.h>
#endif
QT_BEGIN_NAMESPACE
enum { debug = 0 };
static inline bool shellExecute(const QUrl &url)
{
#ifndef Q_OS_WINCE
const QString nativeFilePath =
url.isLocalFile() ? QDir::toNativeSeparators(url.toLocalFile()) : url.toString(QUrl::FullyEncoded);
const quintptr result = (quintptr)ShellExecute(0, 0, (wchar_t*)nativeFilePath.utf16(), 0, 0, SW_SHOWNORMAL);
// ShellExecute returns a value greater than 32 if successful
if (result <= 32) {
qWarning("ShellExecute '%s' failed (error %s).", qPrintable(url.toString()), qPrintable(QString::number(result)));
return false;
}
return true;
#else
Q_UNUSED(url);
return false;
#endif
}
// Retrieve the commandline for the default mail client. It contains a
// placeholder %1 for the URL. The default key used below is the
// command line for the mailto: shell command.
static inline QString mailCommand()
{
enum { BufferSize = sizeof(wchar_t) * MAX_PATH };
const wchar_t mailUserKey[] = L"Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\mailto\\UserChoice";
wchar_t command[MAX_PATH] = {0};
// Check if user has set preference, otherwise use default.
HKEY handle;
QString keyName;
if (!RegOpenKeyEx(HKEY_CURRENT_USER, mailUserKey, 0, KEY_READ, &handle)) {
DWORD bufferSize = BufferSize;
if (!RegQueryValueEx(handle, L"Progid", 0, 0, reinterpret_cast<unsigned char*>(command), &bufferSize))
keyName = QString::fromWCharArray(command);
RegCloseKey(handle);
}
if (keyName.isEmpty())
keyName = QStringLiteral("mailto");
keyName += QStringLiteral("\\Shell\\Open\\Command");
if (debug)
qDebug() << __FUNCTION__ << "keyName=" << keyName;
command[0] = 0;
if (!RegOpenKeyExW(HKEY_CLASSES_ROOT, (const wchar_t*)keyName.utf16(), 0, KEY_READ, &handle)) {
DWORD bufferSize = BufferSize;
RegQueryValueEx(handle, L"", 0, 0, reinterpret_cast<unsigned char*>(command), &bufferSize);
RegCloseKey(handle);
}
if (!command[0])
return QString();
#ifndef Q_OS_WINCE
wchar_t expandedCommand[MAX_PATH] = {0};
return ExpandEnvironmentStrings(command, expandedCommand, MAX_PATH) ?
QString::fromWCharArray(expandedCommand) : QString::fromWCharArray(command);
#else
return QString();
#endif
}
static inline bool launchMail(const QUrl &url)
{
QString command = mailCommand();
if (command.isEmpty()) {
qWarning("Cannot launch '%s': There is no mail program installed.", qPrintable(url.toString()));
return false;
}
//Make sure the path for the process is in quotes
const QChar doubleQuote = QLatin1Char('"');
if (!command.startsWith(doubleQuote)) {
const int exeIndex = command.indexOf(QStringLiteral(".exe "), 0, Qt::CaseInsensitive);
if (exeIndex != -1) {
command.insert(exeIndex + 4, doubleQuote);
command.prepend(doubleQuote);
}
}
// Pass the url as the parameter. Should use QProcess::startDetached(),
// but that cannot handle a Windows command line [yet].
if (command.indexOf(QStringLiteral("%1")) < 0) return false;
command.replace(QStringLiteral("%1"), url.toString(QUrl::FullyEncoded));
if (debug)
qDebug() << __FUNCTION__ << "Launching" << command;
//start the process
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess(NULL, (wchar_t*)command.utf16(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
qErrnoWarning("Unable to launch '%s'", qPrintable(command));
return false;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
}
bool QWindowsServices::openUrl(const QUrl &url)
{
const QString scheme = url.scheme();
if (scheme == QLatin1String("mailto") && launchMail(url))
return true;
return shellExecute(url);
}
bool QWindowsServices::openDocument(const QUrl &url)
{
return shellExecute(url);
}
QT_END_NAMESPACE