Compare commits

...

49 Commits

Author SHA1 Message Date
John Preston
5b9cdbd98a dev version 0.8.39 - Qt 5.5.0, repeat button in audio play 2015-07-14 22:07:21 +03:00
John Preston
8bb376798e removed old warning disable for clang 2015-07-14 16:18:37 +03:00
John Preston
7d51682edd moving to Qt 5.5.0 2015-07-14 15:21:13 +03:00
John Preston
f37159911c Merge branch 'dev' of https://github.com/telegramdesktop/tdesktop into dev 2015-07-13 20:56:55 +03:00
John Preston
4f7f569ddd fixed double play of audio after download complete 2015-07-13 20:56:44 +03:00
John Preston
b352d38acf multimedia keys handle added 2015-07-13 20:55:59 +03:00
John Preston
5663841742 Merge branch 'dev' of https://github.com/telegramdesktop/tdesktop into dev 2015-07-13 14:14:19 +03:00
John Preston
8e2943fe11 filling optimized 2015-07-13 14:14:15 +03:00
John Preston
5595570dfe optimized emoji insert 2015-07-13 14:08:17 +03:00
John Preston
afa28e9754 optimized emoji insertion 2015-07-13 13:45:09 +03:00
John Preston
5a38cb4581 fixed crash 2015-07-12 18:39:56 +03:00
John Preston
cf119568a1 version 0.8.38 graphics changed 2015-07-03 21:03:47 +03:00
John Preston
8b1195df8d Merge branch 'dev' of https://github.com/telegramdesktop/tdesktop into dev 2015-07-03 19:20:15 +03:00
John Preston
7021156732 version 0.8.38 stable with media playback and force_reply in conversations with bots 2015-07-03 19:19:46 +03:00
John Preston
4f2ff9e343 added padding in player, bot commands description QString -> Text (emoji support) 2015-07-03 18:55:22 +03:00
John Preston
3dc7c3e776 playerwidget added to .xcodeproj and .pro files, version 0.8.37.dev 2015-07-03 14:00:11 +03:00
John Preston
e509c14ed1 Merge branch 'master' of https://github.com/telegramdesktop/tdesktop into dev 2015-07-03 13:48:39 +03:00
John Preston
a65ef6fb00 preparing version 0.8.37.dev 2015-07-03 13:48:28 +03:00
John Preston
4c1d12fa70 langs updated 2015-07-03 13:46:48 +03:00
John Preston
1268774517 audio player done 2015-07-03 11:47:16 +03:00
John Preston
61a2a44584 Merge branch 'master' of https://github.com/telegramdesktop/tdesktop into dev 2015-07-01 01:59:21 +03:00
John Preston
89d68cab3e version 0.8.36 prepared 2015-07-01 00:27:56 +03:00
John Preston
f7d55005c4 audio documents playback added, audio documents suppress on voice message, and both suppress on notify added 2015-07-01 00:07:05 +03:00
John Preston
387694f477 langs updated for 0.8.35.dev 2015-06-30 09:40:35 +03:00
John Preston
bc58c73fb4 improved deadlock fix 0.8.35.dev version 2015-06-30 01:22:14 +03:00
John Preston
a4223ec3e0 Merge branch 'master' of https://github.com/telegramdesktop/tdesktop 2015-06-30 01:09:29 +03:00
John Preston
d57f6a973f version 0.8.35.dev ready with some optimizations 2015-06-30 01:09:23 +03:00
John Preston
24ffa08d6e langs updated 2015-06-30 01:06:40 +03:00
John Preston
4b2fccf762 changelog for stable version added 2015-06-29 15:47:25 +03:00
John Preston
da5887fbb5 fixed two layout bugs 2015-06-29 15:43:41 +03:00
John Preston
9926357af5 fixed one deadlock, langs change name -> username 2015-06-29 15:25:28 +03:00
John Preston
ef9aaf659c fixed drag-n-drop in OS X for 0.8.34.dev version 2015-06-28 18:41:13 +03:00
John Preston
dd797d5d46 Merge branch 'master' of https://github.com/telegramdesktop/tdesktop 2015-06-28 16:16:30 +03:00
John Preston
9c91bc1677 QDrag exec moved to timeout for 0.8.34.dev 2015-06-28 16:16:25 +03:00
John Preston
4f3aaa3e7f fixed overview for 0.8.34.dev 2015-06-28 16:15:07 +03:00
John Preston
51451181f8 Merge branch 'master' of https://github.com/telegramdesktop/tdesktop 2015-06-28 15:37:43 +03:00
John Preston
405dfbebae forward by drag-n-drop from media overview, fixed video overview, stickers enlarged and optimized, preparing version 0.8.34.dev 2015-06-28 15:37:10 +03:00
John Preston
8e82b8894d forward-by-drag-n-drop done for images, documents, stickers and messages-by-date 2015-06-27 16:02:00 +03:00
John Preston
b84101b12e Merge branch 'master' of https://github.com/telegramdesktop/tdesktop 2015-06-26 12:08:20 +03:00
John Preston
5182c58292 langs updated 2015-06-26 12:08:14 +03:00
John Preston
d81d6bbeaa drag-n-drop files to dialogs list 2015-06-26 12:07:59 +03:00
John Preston
ddac19788f fixed ipv6 edit in mac/linux for version 0.8.33.dev 2015-06-25 22:05:20 +03:00
John Preston
990c085fc5 version 0.8.33.dev changelog added 2015-06-25 21:08:20 +03:00
John Preston
2940561ee2 added IPv6 setting checkbox in Connection Type box in Settings, version 0.8.33.dev 2015-06-25 21:04:40 +03:00
John Preston
890352ef97 version 0.8.32 crashfix + ipv6 disabled because of KIS 2015-06-25 13:12:38 +03:00
John Preston
88c44caf9d 0.8.31.dev version ready 2015-06-24 23:05:14 +03:00
John Preston
3f6664c82a version 0.8.30.dev fixed commands list 2015-06-24 21:40:32 +03:00
John Preston
793a2ec90c version 0.8.30 with bots support and forward-by-dragndrop 2015-06-24 20:24:48 +03:00
John Preston
780d00bd8c langs updated 2015-06-24 14:10:05 +03:00
127 changed files with 21137 additions and 17860 deletions

View File

@@ -1,20 +1,21 @@
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
DevChannel=`./Version.sh | awk -F " " '{print $3}'`
AppVersionStrMajor=`./Version.sh | awk -F " " '{print $1}'`
AppVersion=`./Version.sh | awk -F " " '{print $2}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $3}'`
DevChannel=`./Version.sh | awk -F " " '{print $4}'`
DevPostfix=''
if [ "$DevChannel" != "0" ]; then
DevPostfix='.dev'
fi
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr$DevPostfix/tlinuxupd$AppVersion" ]; then
if [ ! -f "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tlinuxupd$AppVersion" ]; then
echo "tlinuxupd$AppVersion not found!";
exit 1
fi
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.tar.xz" ]; then
if [ ! -f "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.tar.xz" ]; then
echo "tsetup.$AppVersionStr$DevPostfix.tar.xz not found!"
exit 1
fi
scp ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/tlinuxupd$AppVersion tmaster:tdesktop/www/tlinux/
scp ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.tar.xz tmaster:tdesktop/www/tlinux/
scp ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tlinuxupd$AppVersion tmaster:tdesktop/www/tlinux/
scp ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.tar.xz tmaster:tdesktop/www/tlinux/

View File

@@ -1,21 +1,22 @@
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
DevChannel=`./Version.sh | awk -F " " '{print $3}'`
AppVersionStrMajor=`./Version.sh | awk -F " " '{print $1}'`
AppVersion=`./Version.sh | awk -F " " '{print $2}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $3}'`
DevChannel=`./Version.sh | awk -F " " '{print $4}'`
DevPostfix=''
if [ "$DevChannel" != "0" ]; then
DevPostfix='.dev'
fi
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr$DevPostfix/tlinux32upd$AppVersion" ]; then
if [ ! -f "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tlinux32upd$AppVersion" ]; then
echo "tlinux32upd$AppVersion not found!"
exit 1
fi
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr$DevPostfix/tsetup32.$AppVersionStr$DevPostfix.tar.xz" ]; then
if [ ! -f "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup32.$AppVersionStr$DevPostfix.tar.xz" ]; then
echo "tsetup32.$AppVersionStr$DevPostfix.zip not found!"
exit 1
fi
scp ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/tlinux32upd$AppVersion tmaster:tdesktop/www/tlinux32/
scp ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/tsetup32.$AppVersionStr$DevPostfix.tar.xz tmaster:tdesktop/www/tlinux32/
scp ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tlinux32upd$AppVersion tmaster:tdesktop/www/tlinux32/
scp ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup32.$AppVersionStr$DevPostfix.tar.xz tmaster:tdesktop/www/tlinux32/

View File

@@ -1,38 +1,50 @@
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
DevChannel=`./Version.sh | awk -F " " '{print $3}'`
AppVersionStrMajor=`./Version.sh | awk -F " " '{print $1}'`
AppVersion=`./Version.sh | awk -F " " '{print $2}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $3}'`
DevChannel=`./Version.sh | awk -F " " '{print $4}'`
DevPostfix=''
if [ "$DevChannel" != "0" ]; then
DevPostfix='.dev'
fi
if [ ! -f "./../Mac/Release/deploy/$AppVersionStr$DevPostfix/tmacupd$AppVersion" ]; then
echo "tmacupd$AppVersion not found!"
exit 1
if [ ! -f "./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tmacupd$AppVersion" ]; then
echo "tmacupd$AppVersion not found!"
exit 1
fi
if [ ! -f "./../Mac/Release/deploy/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.dmg" ]; then
echo "tsetup.$AppVersionStr$DevPostfix.dmg not found!"
exit 1
if [ ! -f "./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.dmg" ]; then
echo "tsetup.$AppVersionStr$DevPostfix.dmg not found!"
exit 1
fi
if [ ! -f "./../../tother/tsetup/tupdate$AppVersion" ]; then
echo "tupdate$AppVersion not found!"
exit 1
if [ ! -f "./../../tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tupdate$AppVersion" ]; then
echo "tupdate$AppVersion not found!"
exit 1
fi
if [ ! -f "./../../tother/tsetup/tportable.$AppVersionStr$DevPostfix.zip" ]; then
echo "tportable.$AppVersionStr$DevPostfix.zip not found!"
exit 1
if [ ! -f "./../../tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tportable.$AppVersionStr$DevPostfix.zip" ]; then
echo "tportable.$AppVersionStr$DevPostfix.zip not found!"
exit 1
fi
if [ ! -f "./../../tother/tsetup/tsetup.$AppVersionStr$DevPostfix.exe" ]; then
echo "tsetup.$AppVersionStr$DevPostfix.exe not found!"
exit 1
if [ ! -f "./../../tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.exe" ]; then
echo "tsetup.$AppVersionStr$DevPostfix.exe not found!"
exit 1
fi
scp ./../Mac/Release/deploy/$AppVersionStr$DevPostfix/tmacupd$AppVersion tmaster:tdesktop/www/tmac/
scp ./../Mac/Release/deploy/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.dmg tmaster:tdesktop/www/tmac/
scp ./../../tother/tsetup/tupdate$AppVersion tmaster:tdesktop/www/tsetup/
scp ./../../tother/tsetup/tportable.$AppVersionStr$DevPostfix.zip tmaster:tdesktop/www/tsetup/
scp ./../../tother/tsetup/tsetup.$AppVersionStr$DevPostfix.exe tmaster:tdesktop/www/tsetup/
if [ ! -d "./../../../Dropbox/Telegram/deploy/$AppVersionStrMajor" ]; then
mkdir "./../../../Dropbox/Telegram/deploy/$AppVersionStrMajor"
fi
scp ./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tmacupd$AppVersion tmaster:tdesktop/www/tmac/
scp ./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.dmg tmaster:tdesktop/www/tmac/
scp ./../../tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tupdate$AppVersion tmaster:tdesktop/www/tsetup/
scp ./../../tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tportable.$AppVersionStr$DevPostfix.zip tmaster:tdesktop/www/tsetup/
scp ./../../tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.exe tmaster:tdesktop/www/tsetup/
mv -v ./../../tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix ./../../../Dropbox/Telegram/deploy/$AppVersionStrMajor/
cp -v ./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tmacupd$AppVersion ./../../../Dropbox/Telegram/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
cp -v ./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.dmg ./../../../Dropbox/Telegram/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
cp -rv ./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram.app.dSYM ./../../../Dropbox/Telegram/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/

View File

@@ -1,26 +1,39 @@
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
DevChannel=`./Version.sh | awk -F " " '{print $3}'`
AppVersionStrMajor=`./Version.sh | awk -F " " '{print $1}'`
AppVersion=`./Version.sh | awk -F " " '{print $2}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $3}'`
DevChannel=`./Version.sh | awk -F " " '{print $4}'`
DevPostfix=''
if [ "$DevChannel" != "0" ]; then
DevPostfix='.dev'
fi
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStr$DevPostfix/tupdate$AppVersion" ]; then
echo "tupdate$AppVersion not found!"
exit 1
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tupdate$AppVersion" ]; then
echo "tupdate$AppVersion not found!"
exit 1
fi
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStr$DevPostfix/tportable.$AppVersionStr$DevPostfix.zip" ]; then
echo "tportable.$AppVersionStr$DevPostfix.zip not found!"
exit 1
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tportable.$AppVersionStr$DevPostfix.zip" ]; then
echo "tportable.$AppVersionStr$DevPostfix.zip not found!"
exit 1
fi
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.exe" ]; then
echo "tsetup.$AppVersionStr$DevPostfix.exe not found!"
exit 1
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.exe" ]; then
echo "tsetup.$AppVersionStr$DevPostfix.exe not found!"
exit 1
fi
cp -v ./../Win32/Deploy/deploy/$AppVersionStr$DevPostfix/tupdate$AppVersion /z/TBuild/tother/tsetup/
cp -v ./../Win32/Deploy/deploy/$AppVersionStr$DevPostfix/tportable.$AppVersionStr$DevPostfix.zip /z/TBuild/tother/tsetup/
cp -v ./../Win32/Deploy/deploy/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.exe /z/TBuild/tother/tsetup/
if [ ! -d "/z/TBuild/tother/tsetup/$AppVersionStrMajor" ]; then
mkdir "/z/TBuild/tother/tsetup/$AppVersionStrMajor"
fi
if [ ! -d "/z/TBuild/tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix" ]; then
mkdir "/z/TBuild/tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix"
fi
cp -v ./../Win32/Deploy/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tupdate$AppVersion /z/TBuild/tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
cp -v ./../Win32/Deploy/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tportable.$AppVersionStr$DevPostfix.zip /z/TBuild/tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
cp -v ./../Win32/Deploy/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.exe /z/TBuild/tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
cp -v ./../Win32/Deploy/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram.pdb /z/TBuild/tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
cp -v ./../Win32/Deploy/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Updater.exe /z/TBuild/tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
cp -v ./../Win32/Deploy/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Updater.pdb /z/TBuild/tother/tsetup/$AppVersionStrMajor/$AppVersionStr$DevPostfix/

View File

@@ -105,7 +105,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Qt5Cored.lib;Qt5Guid.lib;qtharfbuzzngd.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Qt5Cored.lib;Qt5Guid.lib;qtharfbuzzngd.lib;qtpcred.lib;qtfreetyped.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<ProfileGuidedDatabase>$(IntDir)$(TargetName).pgd</ProfileGuidedDatabase>
@@ -123,7 +123,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;glu32.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;glu32.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;qtpcre.lib;qtfreetype.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<ProfileGuidedDatabase>$(IntDir)$(TargetName).pgd</ProfileGuidedDatabase>
@@ -142,7 +142,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;glu32.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;glu32.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;qtpcre.lib;qtfreetype.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<ProfileGuidedDatabase>$(IntDir)$(TargetName).pgd</ProfileGuidedDatabase>

View File

@@ -105,7 +105,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Qt5Cored.lib;Qt5Guid.lib;qtharfbuzzngd.lib;Qt5Widgetsd.lib;Qt5Networkd.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Qt5Cored.lib;Qt5Guid.lib;qtharfbuzzngd.lib;qtpcred.lib;qtfreetyped.lib;Qt5Widgetsd.lib;Qt5Networkd.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<ProfileGuidedDatabase>$(IntDir)$(TargetName).pgd</ProfileGuidedDatabase>
@@ -123,7 +123,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;qtpcre.lib;qtfreetype.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
@@ -140,7 +140,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;qtpcre.lib;qtfreetype.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>

View File

@@ -126,7 +126,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Qt5Cored.lib;Qt5Guid.lib;qtharfbuzzngd.lib;Qt5Widgetsd.lib;Qt5Networkd.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Qt5Cored.lib;Qt5Guid.lib;qtharfbuzzngd.lib;qtpcred.lib;qtfreetyped.lib;Qt5Widgetsd.lib;Qt5Networkd.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<ProfileGuidedDatabase>$(IntDir)$(TargetName).pgd</ProfileGuidedDatabase>
@@ -145,7 +145,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;qtpcre.lib;qtfreetype.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
@@ -162,7 +162,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;qtpcre.lib;qtfreetype.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>

View File

@@ -113,7 +113,7 @@
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>.\..\..\Libraries\lzma\C\Util\LzmaLib\Release;$(QTDIR)\lib;.\..\..\Libraries\zlib-1.2.8\contrib\vstudio\vc11\x86\ZlibStatRelease;.\..\..\Libraries\OpenSSL-Win32\lib\VC\static;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;zlibstat.lib;libeay32MT.lib;Qt5Core.lib;LzmaLib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;zlibstat.lib;libeay32MT.lib;Qt5Core.lib;qtpcre.lib;LzmaLib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ImageHasSafeExceptionHandlers>
</ImageHasSafeExceptionHandlers>

View File

@@ -1,6 +1,7 @@
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
DevChannel=`./Version.sh | awk -F " " '{print $3}'`
AppVersionStrMajor=`./Version.sh | awk -F " " '{print $1}'`
AppVersion=`./Version.sh | awk -F " " '{print $2}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $3}'`
DevChannel=`./Version.sh | awk -F " " '{print $4}'`
DevPostfix=''
DevParam=''
if [ "$DevChannel" != "0" ]; then
@@ -8,12 +9,12 @@ if [ "$DevChannel" != "0" ]; then
DevParam='-dev'
fi
if [ -d "./../Linux/Release/deploy/$AppVersionStr.dev" ]; then
if [ -d "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr.dev" ]; then
echo "Deploy folder for version $AppVersionStr.dev already exists!"
exit 1
fi
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
if [ -d "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr" ]; then
echo "Deploy folder for version $AppVersionStr already exists!"
exit 1
fi
@@ -40,12 +41,17 @@ echo "Packer done!"
if [ ! -d "./../Linux/Release/deploy" ]; then
mkdir "./../Linux/Release/deploy"
fi
if [ ! -d "./../Linux/Release/deploy/$AppVersionStrMajor" ]; then
mkdir "./../Linux/Release/deploy/$AppVersionStrMajor"
fi
echo "Copying Telegram, Updater and tlinuxupd$AppVersion to deploy/$AppVersionStr$DevPostfix..";
mkdir "./../Linux/Release/deploy/$AppVersionStr$DevPostfix"
mkdir "./../Linux/Release/deploy/$AppVersionStr$DevPostfix/Telegram"
mv ./../Linux/Release/Telegram ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/Telegram/
mv ./../Linux/Release/Updater ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/Telegram/
mv ./../Linux/Release/tlinuxupd$AppVersion ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/
cd ./../Linux/Release/deploy/$AppVersionStr$DevPostfix && tar -cJvf tsetup.$AppVersionStr$DevPostfix.tar.xz Telegram/ && cd ./../../../../Telegram
mkdir "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix"
mkdir "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram"
mv ./../Linux/Release/Telegram ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram/
mv ./../Linux/Release/Updater ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram/
mv ./../Linux/Release/tlinuxupd$AppVersion ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
cd ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix && tar -cJvf tsetup.$AppVersionStr$DevPostfix.tar.xz Telegram/ && cd ./../../../../../Telegram
echo "Version $AppVersionStr$DevPostfix prepared!";

View File

@@ -1,6 +1,7 @@
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
DevChannel=`./Version.sh | awk -F " " '{print $3}'`
AppVersionStrMajor=`./Version.sh | awk -F " " '{print $1}'`
AppVersion=`./Version.sh | awk -F " " '{print $2}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $3}'`
DevChannel=`./Version.sh | awk -F " " '{print $4}'`
DevPostfix=''
DevParam=''
if [ "$DevChannel" != "0" ]; then
@@ -8,12 +9,12 @@ if [ "$DevChannel" != "0" ]; then
DevParam='-dev'
fi
if [ -d "./../Linux/Release/deploy/$AppVersionStr.dev" ]; then
if [ -d "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr.dev" ]; then
echo "Deploy folder for version $AppVersionStr.dev already exists!"
exit 1
fi
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
if [ -d "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr" ]; then
echo "Deploy folder for version $AppVersionStr already exists!"
exit 1
fi
@@ -40,12 +41,17 @@ echo "Packer done!"
if [ ! -d "./../Linux/Release/deploy" ]; then
mkdir "./../Linux/Release/deploy"
fi
if [ ! -d "./../Linux/Release/deploy/$AppVersionStrMajor" ]; then
mkdir "./../Linux/Release/deploy/$AppVersionStrMajor"
fi
echo "Copying Telegram, Updater and tlinux32upd$AppVersion to deploy/$AppVersionStr$DevPostfix..";
mkdir "./../Linux/Release/deploy/$AppVersionStr$DevPostfix"
mkdir "./../Linux/Release/deploy/$AppVersionStr$DevPostfix/Telegram"
mv ./../Linux/Release/Telegram ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/Telegram/
mv ./../Linux/Release/Updater ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/Telegram/
mv ./../Linux/Release/tlinux32upd$AppVersion ./../Linux/Release/deploy/$AppVersionStr$DevPostfix/
cd ./../Linux/Release/deploy/$AppVersionStr$DevPostfix && tar -cJvf tsetup32.$AppVersionStr$DevPostfix.tar.xz Telegram/ && cd ./../../../../Telegram
mkdir "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix"
mkdir "./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram"
mv ./../Linux/Release/Telegram ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram/
mv ./../Linux/Release/Updater ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram/
mv ./../Linux/Release/tlinux32upd$AppVersion ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
cd ./../Linux/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix && tar -cJvf tsetup32.$AppVersionStr$DevPostfix.tar.xz Telegram/ && cd ./../../../../../Telegram
echo "Version $AppVersionStr$DevPostfix prepared!";

View File

@@ -1,6 +1,7 @@
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
DevChannel=`./Version.sh | awk -F " " '{print $3}'`
AppVersionStrMajor=`./Version.sh | awk -F " " '{print $1}'`
AppVersion=`./Version.sh | awk -F " " '{print $2}'`
AppVersionStr=`./Version.sh | awk -F " " '{print $3}'`
DevChannel=`./Version.sh | awk -F " " '{print $4}'`
DevPostfix=''
DevParam=''
if [ "$DevChannel" != "0" ]; then
@@ -12,12 +13,12 @@ echo ""
echo "Preparing version $AppVersionStr$DevPostfix.."
echo ""
if [ -d "./../Mac/Release/deploy/$AppVersionStr.dev" ]; then
if [ -d "./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr.dev" ]; then
echo "Deploy folder for version $AppVersionStr.dev already exists!"
exit 1
fi
if [ -d "./../Mac/Release/deploy/$AppVersionStr" ]; then
if [ -d "./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr" ]; then
echo "Deploy folder for version $AppVersionStr already exists!"
exit 1
fi
@@ -73,19 +74,23 @@ hdiutil convert tsetup.dmg -format UDZO -imagekey zlib-level=9 -ov -o tsetup.$Ap
cd ./../../Telegram
cd ./../Mac/Release && ./Packer.app/Contents/MacOS/Packer -path Telegram.app -version $AppVersion $DevParam && cd ./../../Telegram
if [ ! -d "./../Mac/Release/deploy/" ]; then
if [ ! -d "./../Mac/Release/deploy" ]; then
mkdir "./../Mac/Release/deploy"
fi
echo "Copying Telegram.app and tmacupd$AppVersion to deploy/$AppVersionStr..";
mkdir "./../Mac/Release/deploy/$AppVersionStr$DevPostfix"
mkdir "./../Mac/Release/deploy/$AppVersionStr$DevPostfix/Telegram"
cp -r ./../Mac/Release/Telegram.app ./../Mac/Release/deploy/$AppVersionStr$DevPostfix/Telegram/
mv ./../Mac/Release/Telegram.app.dSYM ./../Mac/Release/deploy/$AppVersionStr$DevPostfix/
if [ ! -d "./../Mac/Release/deploy/$AppVersionStrMajor" ]; then
mkdir "./../Mac/Release/deploy/$AppVersionStrMajor"
fi
echo "Copying Telegram.app and tmacupd$AppVersion to deploy/$AppVersionStrMajor/$AppVersionStr..";
mkdir "./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix"
mkdir "./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram"
cp -r ./../Mac/Release/Telegram.app ./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/Telegram/
mv ./../Mac/Release/Telegram.app.dSYM ./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
rm ./../Mac/Release/Telegram.app/Contents/MacOS/Telegram
rm ./../Mac/Release/Telegram.app/Contents/Frameworks/Updater
rm -rf ./../Mac/Release/Telegram.app/Contents/_CodeSignature
mv ./../Mac/Release/tmacupd$AppVersion ./../Mac/Release/deploy/$AppVersionStr$DevPostfix/
mv ./../Mac/Release/tsetup.$AppVersionStr$DevPostfix.dmg ./../Mac/Release/deploy/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.dmg
mv ./../Mac/Release/tmacupd$AppVersion ./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/
mv ./../Mac/Release/tsetup.$AppVersionStr$DevPostfix.dmg ./../Mac/Release/deploy/$AppVersionStrMajor/$AppVersionStr$DevPostfix/tsetup.$AppVersionStr$DevPostfix.dmg
echo "Version $AppVersionStr$DevPostfix prepared!";

View File

@@ -1,9 +1,10 @@
@echo OFF
set "AppVersion=8029"
set "AppVersionStrSmall=0.8.29"
set "AppVersionStr=0.8.29"
set "AppVersionStrFull=0.8.29.0"
set "AppVersionStrMajor=0.8"
set "AppVersion=8039"
set "AppVersionStrSmall=0.8.39"
set "AppVersionStr=0.8.39"
set "AppVersionStrFull=0.8.39.0"
set "DevChannel=1"
if %DevChannel% neq 0 goto preparedev
@@ -23,8 +24,8 @@ echo.
echo Preparing version %AppVersionStr%%DevPostfix%..
echo.
if exist ..\Win32\Deploy\deploy\%AppVersionStr%\ goto error_exist1
if exist ..\Win32\Deploy\deploy\%AppVersionStr%.dev\ goto error_exist2
if exist ..\Win32\Deploy\deploy\%AppVersionStrMajor%\%AppVersionStr%\ goto error_exist1
if exist ..\Win32\Deploy\deploy\%AppVersionStrMajor%\%AppVersionStr%.dev\ goto error_exist2
if exist ..\Win32\Deploy\tupdate%AppVersion% goto error_exist3
set "PATH=%PATH%;C:\Program Files\7-Zip;C:\Program Files (x86)\Inno Setup 5"
@@ -46,17 +47,18 @@ call Packer.exe -version %AppVersion% -path Telegram.exe -path Updater.exe %DevP
if %errorlevel% neq 0 goto error1
if not exist deploy mkdir deploy
mkdir deploy\%AppVersionStr%%DevPostfix%
mkdir deploy\%AppVersionStr%%DevPostfix%\Telegram
if not exist deploy\%AppVersionStrMajor% mkdir deploy\%AppVersionStrMajor%
mkdir deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%
mkdir deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%\Telegram
move Telegram.exe deploy\%AppVersionStr%%DevPostfix%\Telegram\
move Updater.exe deploy\%AppVersionStr%%DevPostfix%\
move Telegram.pdb deploy\%AppVersionStr%%DevPostfix%\
move Updater.pdb deploy\%AppVersionStr%%DevPostfix%\
move tsetup.%AppVersionStr%%DevPostfix%.exe deploy\%AppVersionStr%%DevPostfix%\
move tupdate%AppVersion% deploy\%AppVersionStr%%DevPostfix%\
move Telegram.exe deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%\Telegram\
move Updater.exe deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%\
move Telegram.pdb deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%\
move Updater.pdb deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%\
move tsetup.%AppVersionStr%%DevPostfix%.exe deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%\
move tupdate%AppVersion% deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%\
cd deploy\%AppVersionStr%%DevPostfix%
cd deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%
7z a -mx9 tportable.%AppVersionStr%%DevPostfix%.zip Telegram\
if %errorlevel% neq 0 goto error2
@@ -64,11 +66,11 @@ echo .
echo Version %AppVersionStr%%DevPostfix% is ready for deploy!
echo .
cd ..\..\..\..\Telegram
cd ..\..\..\..\..\Telegram
goto eof
:error2
cd ..\..
cd ..\..\..
:error1
cd ..\..\Telegram
echo ERROR occured!

View File

@@ -166,11 +166,11 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_username_title" = "Change username";
"lng_username_about" = "You can choose a username on Telegram.\nIf you do, other people will be able to find\nyou by this username and contact you\nwithout knowing your phone number.\n\nYou can use a-z, 0-9 and underscores.\nMinimum length is 5 characters.";
"lng_username_invalid" = "This name is invalid.";
"lng_username_occupied" = "This name is already occupied.";
"lng_username_too_short" = "This name is too short.";
"lng_username_bad_symbols" = "This name has bad symbols.";
"lng_username_available" = "This name is available.";
"lng_username_invalid" = "This username is invalid.";
"lng_username_occupied" = "This username is already occupied.";
"lng_username_too_short" = "This username is too short.";
"lng_username_bad_symbols" = "This username has bad symbols.";
"lng_username_available" = "This username is available.";
"lng_username_not_found" = "User @{user} not found.";
"lng_settings_section_contact_info" = "Contact info";
@@ -301,13 +301,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_connection_type" = "Connection type:";
"lng_connection_auto_connecting" = "Default (connecting..)";
"lng_connection_auto" = "Default ({type} used)";
"lng_connection_http_proxy" = "HTTP with proxy";
"lng_connection_tcp_proxy" = "TCP with proxy";
"lng_connection_auto" = "Default ({transport} used)";
"lng_connection_proxy_connecting" = "Connecting through proxy..";
"lng_connection_proxy" = "{transport} with proxy";
"lng_connection_header" = "Connection type";
"lng_connection_auto_rb" = "Auto (TCP if available or HTTP)";
"lng_connection_http_proxy_rb" = "HTTP with custom http-proxy";
"lng_connection_tcp_proxy_rb" = "TCP with custom socks5-proxy";
"lng_connection_try_ipv6" = "Try connecting through IPv6";
"lng_connection_host_ph" = "Hostname";
"lng_connection_port_ph" = "Port";
"lng_connection_user_ph" = "Username";
@@ -367,6 +368,7 @@ 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_audio_files_header" = "Playlist";
"lng_profile_show_all_types" = "Show all types";
"lng_profile_copy_phone" = "Copy phone number";
@@ -601,7 +603,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_new_version_wrap" = "Telegram Desktop was updated to version {version}\n\n{changes}\n\nFull version history is available here:\n{link}";
"lng_new_version_minor" = "— Bug fixes and other minor improvements";
"lng_new_version_text" = "This new version includes support for bots using the new bot API, free for everyone. If you're an engineer, create your own bots for games, services or integrations.\n\nLearn more at {blog_link}";
"lng_new_version_text" = "— Improved in-app media playback\n— Bug fixes and other minor improvements";
"lng_menu_insert_unicode" = "Insert Unicode control character";

View File

@@ -868,6 +868,8 @@ defaultTextStyle: textStyle {
lineHeight: 0px;
}
serviceTextStyle: textStyle(defaultTextStyle) {
lnkFlags: msgServiceFont;
lnkOverFlags: font(fsize semibold underline);
lnkColor: msgServiceColor;
lnkDownColor: msgServiceColor;
selectBg: msgServiceSelectBg;
@@ -913,6 +915,8 @@ mediaDocOutImg: sprite(6px, 146px, 48px, 48px);
mediaDocInImg: sprite(56px, 146px, 48px, 48px);
mediaAudioOutImg: sprite(106px, 146px, 48px, 48px);
mediaAudioInImg: sprite(156px, 146px, 48px, 48px);
mediaMusicOutImg: sprite(322px, 345px, 48px, 48px);
mediaMusicInImg: sprite(322px, 395px, 48px, 48px);
mediaPlayOutImg: sprite(122px, 341px, 48px, 48px);
mediaPlayInImg: sprite(172px, 341px, 48px, 48px);
mediaPauseOutImg: sprite(222px, 341px, 48px, 48px);
@@ -961,9 +965,9 @@ btnSend: flatButton(btnDefFlat) {
width: -32px;
height: 46px;
textTop: 13px;
overTextTop: 13px;
downTextTop: 14px;
textTop: 12px;
overTextTop: 12px;
downTextTop: 13px;
font: font(16px);
overFont: font(16px);
@@ -985,26 +989,32 @@ btnAttachPhoto: iconedButton(btnAttachDocument) {
}
btnAttachEmoji: iconedButton(btnAttachDocument) {
overBgColor: white;
icon: sprite(363px, 344px, 21px, 22px);
icon: sprite(374px, 344px, 21px, 22px);
iconPos: point(6px, 12px);
downIcon: sprite(363px, 344px, 21px, 22px);
downIcon: sprite(374px, 344px, 21px, 22px);
downIconPos: point(6px, 12px);
width: 33px;
}
btnBotKbShow: iconedButton(btnAttachEmoji) {
icon: sprite(375px, 74px, 21px, 16px);
iconPos: point(6px, 16px);
downIcon: sprite(375px, 74px, 21px, 16px);
downIconPos: point(6px, 16px);
icon: sprite(375px, 74px, 21px, 21px);
iconPos: point(6px, 12px);
downIcon: sprite(375px, 74px, 21px, 21px);
downIconPos: point(6px, 12px);
}
btnBotCmdStart: iconedButton(btnAttachEmoji) {
icon: sprite(354px, 74px, 21px, 21px);
iconPos: point(6px, 12px);
downIcon: sprite(354px, 74px, 21px, 21px);
downIconPos: point(6px, 12px);
}
btnBotKbHide: iconedButton(btnAttachEmoji) {
icon: sprite(352px, 74px, 23px, 14px);
icon: sprite(373px, 95px, 23px, 14px);
iconPos: point(5px, 17px);
downIcon: sprite(352px, 74px, 23px, 14px);
downIcon: sprite(373px, 95px, 23px, 14px);
downIconPos: point(5px, 17px);
}
btnRecordAudio: sprite(363px, 366px, 16px, 24px);
btnRecordAudio: sprite(379px, 390px, 16px, 24px);
btnRecordAudioActive: sprite(379px, 366px, 16px, 24px);
recordSignalColor: #f17077;
recordSignalMin: 5px;
@@ -1140,7 +1150,7 @@ notifyTextTop: 7px;
notifySlowHideFunc: transition(easeInCirc);
notifyWaitShortHide: 0;
notifyWaitLongHide: 20000;
notifyFastAnim: 100;
notifyFastAnim: 150;
notifyFastAnimFunc: transition(linear);
notifyWidth: 316px;
notifyHeight: 80px;
@@ -1527,30 +1537,22 @@ stickersScroll: flatScroll(newScroll) {
emojiScroll: flatScroll(newScroll) {
deltat: 48px;
}
emojiRecent: sprite(0px, 196px, 21px, 22px);
emojiRecentOver: sprite(287px, 220px, 21px, 22px);
emojiRecentActive: sprite(287px, 242px, 21px, 22px);
emojiPeople: sprite(21px, 196px, 21px, 22px);
emojiPeopleOver: sprite(308px, 220px, 21px, 22px);
emojiPeopleActive: sprite(308px, 242px, 21px, 22px);
emojiNature: sprite(42px, 196px, 21px, 22px);
emojiNatureOver: sprite(245px, 264px, 21px, 22px);
emojiRecentOver: sprite(0px, 196px, 21px, 22px);
emojiRecentActive: sprite(245px, 264px, 21px, 22px);
emojiPeopleOver: sprite(21px, 196px, 21px, 22px);
emojiPeopleActive: sprite(266px, 264px, 21px, 22px);
emojiNatureOver: sprite(42px, 196px, 21px, 22px);
emojiNatureActive: sprite(245px, 286px, 21px, 22px);
emojiFood: sprite(63px, 196px, 21px, 22px);
emojiFoodOver: sprite(266px, 264px, 21px, 22px);
emojiFoodOver: sprite(63px, 196px, 21px, 22px);
emojiFoodActive: sprite(266px, 286px, 21px, 22px);
emojiCelebration: sprite(84px, 196px, 21px, 22px);
emojiCelebrationOver: sprite(287px, 264px, 21px, 22px);
emojiCelebrationOver: sprite(84px, 196px, 21px, 22px);
emojiCelebrationActive: sprite(287px, 286px, 21px, 22px);
emojiActivity: sprite(126px, 196px, 21px, 22px);
emojiActivityOver: sprite(321px, 344px, 21px, 22px);
emojiActivityActive: sprite(321px, 366px, 21px, 22px);
emojiTravel: sprite(105px, 196px, 21px, 22px);
emojiTravelOver: sprite(308px, 264px, 21px, 22px);
emojiActivityOver: sprite(126px, 196px, 21px, 22px);
emojiActivityActive: sprite(287px, 264px, 21px, 22px);
emojiTravelOver: sprite(105px, 196px, 21px, 22px);
emojiTravelActive: sprite(308px, 286px, 21px, 22px);
emojiObjects: sprite(147px, 196px, 21px, 22px);
emojiObjectsOver: sprite(342px, 344px, 21px, 22px);
emojiObjectsActive: sprite(342px, 366px, 21px, 22px);
emojiObjectsOver: sprite(147px, 196px, 21px, 22px);
emojiObjectsActive: sprite(308px, 264px, 21px, 22px);
emojiPanCategories: #f7f7f7;
@@ -1559,7 +1561,7 @@ rbEmoji: flatCheckbox {
bgColor: emojiPanCategories;
disColor: emojiPanCategories;
width: 36px;
width: 42px;
height: 46px;
textTop: 0px;
@@ -1570,7 +1572,7 @@ rbEmoji: flatCheckbox {
cursor: cursor(pointer);
disabledCursor: cursor(default);
imagePos: point(8px, 12px);
imagePos: point(11px, 12px);
}
rbEmojiRecent: flatCheckbox(rbEmoji) {
imageRect: emojiRecentOver;
@@ -1636,16 +1638,17 @@ rbEmojiObjects: flatCheckbox(rbEmoji) {
disImageRect: emojiObjectsOver;
chkDisImageRect: emojiObjectsActive;
}
emojiPanPadding: 10px;
emojiPanSize: size(39px, 35px);
emojiPanFullSize: size(300px, 321px);
emojiPanPadding: 12px;
emojiPanSize: size(45px, 41px);
emojiPanWidth: 345px;
emojiPanMaxHeight: 366px;
emojiPanDuration: 200;
emojiPanHover: #f0f4f7;
emojiPanHeader: 42px;
emojiPanHeaderFont: font(fsize semibold);
emojiPanHeaderColor: #999;
emojiPanHeaderLeft: 17px;
emojiPanHeaderLeft: 22px;
emojiPanHeaderTop: 12px;
emojiPanHeaderBg: #fffffff2;
@@ -1659,7 +1662,7 @@ emojiSwitchStickers: sprite(318px, 328px, 8px, 12px);
emojiSwitchEmoji: sprite(310px, 328px, 8px, 12px);
emojiSwitchColor: #42a8db;
stickerPanSize: size(55px, 55px);
stickerPanSize: size(64px, 64px);
stickerPanPadding: 11px;
stickerPanDelete: sprite(123px, 132px, 12px, 12px);
stickerPanDeleteOpacity: 0.5;
@@ -1718,11 +1721,11 @@ mvControlMargin: 0px;
mvControlSize: 90px;
mvIconSize: size(60px, 56px);
mvLeft: sprite(320px, 400px, 12px, 22px);
mvRight: sprite(332px, 400px, 12px, 22px);
mvClose: sprite(344px, 400px, 18px, 18px);
mvSave: sprite(362px, 400px, 14px, 19px);
mvMore: sprite(376px, 400px, 5px, 21px);
mvLeft: sprite(320px, 445px, 12px, 22px);
mvRight: sprite(332px, 445px, 12px, 22px);
mvClose: sprite(344px, 445px, 18px, 18px);
mvSave: sprite(362px, 445px, 14px, 19px);
mvMore: sprite(376px, 445px, 5px, 21px);
mvDropdown: dropdown(dropdownDef) {
shadow: sprite(0px, 0px, 0px, 0px);
@@ -1961,3 +1964,36 @@ webPagePhotoSize: 100px;
webPagePhotoDelta: 8px;
botDescSkip: 8px;
suppressAll: 0.2;
suppressSong: 0.05;
playerHeight: 44px;
playerBg: #e4e9ef;
playerFg: #54748f;
playerTimeFg: #a4afba;
playerLineHeight: 3px;
playerMoverSize: size(2px, 7px);
playerLineActive: #6389a8;
playerLineInactive: #bac7d4;
playerSkip: 8px;
playerNameStyle: textStyle(defaultTextStyle) {
lnkColor: #6389a8;
lnkDownColor: #6389a8;
lnkFlags: font(fsize semibold);
lnkOverFlags: font(fsize semibold);
}
playerPlay: sprite(377px, 109px, 19px, 22px);
playerPause: sprite(379px, 131px, 17px, 20px);
playerNext: sprite(374px, 151px, 22px, 14px);
playerPrev: sprite(374px, 165px, 22px, 14px);
playerClose: sprite(361px, 97px, 12px, 12px);
playerFull: sprite(365px, 109px, 12px, 12px);
playerRepeat: sprite(365px, 121px, 12px, 14px);
playerVolume: sprite(352px, 179px, 44px, 12px);
playerInactiveOpacity: 0.8;
playerUnavailableOpacity: 0.3;
playerDuration: 200;
playlistHoverBg: #f2f2f2;
playlistPadding: 10px;

View File

@@ -23,6 +23,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include <QtCore/QDir>
#include <QtCore/QStringList>
#include <QtCore/QBuffer>
#include <QtCore/QDataStream>
#include <zlib.h>

View File

@@ -83,91 +83,6 @@ void ApiWrap::requestReplyTo(HistoryReply *reply, MsgId to) {
if (!req.req) _replyToTimer.start(1);
}
void ApiWrap::requestFullPeer(PeerData *peer) {
if (!peer || _fullRequests.contains(peer)) return;
mtpRequestId req;
if (peer->chat) {
req = MTP::send(MTPmessages_GetFullChat(MTP_int(App::chatFromPeer(peer->id))), rpcDone(&ApiWrap::gotChatFull, peer), rpcFail(&ApiWrap::gotPeerFailed, peer));
} else {
req = MTP::send(MTPusers_GetFullUser(peer->asUser()->inputUser), rpcDone(&ApiWrap::gotUserFull, peer), rpcFail(&ApiWrap::gotPeerFailed, peer));
}
_fullRequests.insert(peer, req);
}
void ApiWrap::requestWebPageDelayed(WebPageData *page) {
if (page->pendingTill <= 0) return;
_webPagesPending.insert(page, 0);
int32 left = (page->pendingTill - unixtime()) * 1000;
if (!_webPagesTimer.isActive() || left <= _webPagesTimer.remainingTime()) {
_webPagesTimer.start((left < 0 ? 0 : left) + 1);
}
}
void ApiWrap::clearWebPageRequest(WebPageData *page) {
_webPagesPending.remove(page);
if (_webPagesPending.isEmpty() && _webPagesTimer.isActive()) _webPagesTimer.stop();
}
void ApiWrap::clearWebPageRequests() {
_webPagesPending.clear();
_webPagesTimer.stop();
}
void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result) {
const MTPDmessages_chatFull &d(result.c_messages_chatFull());
const MTPDchatFull &f(d.vfull_chat.c_chatFull());
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
App::feedParticipants(f.vparticipants);
const QVector<MTPBotInfo> &v(f.vbot_info.c_vector().v);
for (QVector<MTPBotInfo>::const_iterator i = v.cbegin(), e = v.cend(); i < e; ++i) {
switch (i->type()) {
case mtpc_botInfo: {
const MTPDbotInfo &b(i->c_botInfo());
UserData *user = App::userLoaded(b.vuser_id.v);
if (user) {
user->setBotInfo(*i);
emit fullPeerUpdated(user);
}
} break;
}
}
PhotoData *photo = App::feedPhoto(f.vchat_photo);
ChatData *chat = peer->asChat();
if (chat) {
if (photo) {
chat->photoId = photo->id;
photo->chat = chat;
}
chat->invitationUrl = (f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString();
}
App::main()->gotNotifySetting(MTP_inputNotifyPeer(peer->input), f.vnotify_settings);
_fullRequests.remove(peer);
emit fullPeerUpdated(peer);
}
void ApiWrap::gotUserFull(PeerData *peer, const MTPUserFull &result) {
const MTPDuserFull &d(result.c_userFull());
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser));
App::feedPhoto(d.vprofile_photo);
App::feedUserLink(MTP_int(App::userFromPeer(peer->id)), d.vlink.c_contacts_link().vmy_link, d.vlink.c_contacts_link().vforeign_link);
App::main()->gotNotifySetting(MTP_inputNotifyPeer(peer->input), d.vnotify_settings);
peer->asUser()->setBotInfo(d.vbot_info);
_fullRequests.remove(peer);
emit fullPeerUpdated(peer);
}
bool ApiWrap::gotPeerFailed(PeerData *peer, const RPCError &error) {
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
_fullRequests.remove(peer);
return true;
}
void ApiWrap::resolveReplyTo() {
if (_replyToRequests.isEmpty()) return;
@@ -186,34 +101,6 @@ void ApiWrap::resolveReplyTo() {
}
}
void ApiWrap::resolveWebPages() {
QVector<MTPint> ids;
const WebPageItems &items(App::webPageItems());
ids.reserve(_webPagesPending.size());
int32 t = unixtime(), m = INT_MAX;
for (WebPagesPending::const_iterator i = _webPagesPending.cbegin(), e = _webPagesPending.cend(); i != e; ++i) {
if (i.value()) continue;
if (i.key()->pendingTill <= t) {
WebPageItems::const_iterator j = items.constFind(i.key());
if (j != items.cend() && !j.value().isEmpty()) {
ids.push_back(MTP_int(j.value().begin().key()->id));
}
} else {
m = qMin(m, i.key()->pendingTill - t);
}
}
if (!ids.isEmpty()) {
mtpRequestId req = MTP::send(MTPmessages_GetMessages(MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotWebPages));
for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) {
if (i.value()) continue;
if (i.key()->pendingTill <= t) {
i.value() = req;
}
}
}
if (m < INT_MAX) _webPagesTimer.start(m * 1000);
}
void ApiWrap::gotReplyTo(const MTPmessages_Messages &msgs, mtpRequestId req) {
switch (msgs.type()) {
case mtpc_messages_messages:
@@ -244,6 +131,298 @@ void ApiWrap::gotReplyTo(const MTPmessages_Messages &msgs, mtpRequestId req) {
}
}
void ApiWrap::requestFullPeer(PeerData *peer) {
if (!peer || _fullPeerRequests.contains(peer)) return;
mtpRequestId req;
if (peer->chat) {
req = MTP::send(MTPmessages_GetFullChat(MTP_int(App::chatFromPeer(peer->id))), rpcDone(&ApiWrap::gotChatFull, peer), rpcFail(&ApiWrap::gotPeerFullFailed, peer));
} else {
req = MTP::send(MTPusers_GetFullUser(peer->asUser()->inputUser), rpcDone(&ApiWrap::gotUserFull, peer), rpcFail(&ApiWrap::gotPeerFullFailed, peer));
}
_fullPeerRequests.insert(peer, req);
}
void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result) {
const MTPDmessages_chatFull &d(result.c_messages_chatFull());
const MTPDchatFull &f(d.vfull_chat.c_chatFull());
const QVector<MTPChat> &vc(d.vchats.c_vector().v);
bool badVersion = (!vc.isEmpty() && vc.at(0).type() == mtpc_chat && vc.at(0).c_chat().vversion.v < peer->asChat()->version);
App::feedUsers(d.vusers, false);
App::feedChats(d.vchats, false);
App::feedParticipants(f.vparticipants, false, false);
const QVector<MTPBotInfo> &v(f.vbot_info.c_vector().v);
for (QVector<MTPBotInfo>::const_iterator i = v.cbegin(), e = v.cend(); i < e; ++i) {
switch (i->type()) {
case mtpc_botInfo: {
const MTPDbotInfo &b(i->c_botInfo());
UserData *user = App::userLoaded(b.vuser_id.v);
if (user) {
user->setBotInfo(*i);
App::clearPeerUpdated(user);
emit fullPeerUpdated(user);
}
} break;
}
}
PhotoData *photo = App::feedPhoto(f.vchat_photo);
ChatData *chat = peer->asChat();
if (chat) {
if (photo) {
chat->photoId = photo->id;
photo->chat = chat;
} else {
chat->photoId = 0;
}
chat->invitationUrl = (f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString();
}
App::main()->gotNotifySetting(MTP_inputNotifyPeer(peer->input), f.vnotify_settings);
_fullPeerRequests.remove(peer);
if (badVersion) {
peer->asChat()->version = vc.at(0).c_chat().vversion.v;
requestPeer(peer);
}
App::clearPeerUpdated(peer);
emit fullPeerUpdated(peer);
App::emitPeerUpdated();
}
void ApiWrap::gotUserFull(PeerData *peer, const MTPUserFull &result) {
const MTPDuserFull &d(result.c_userFull());
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser), false);
App::feedPhoto(d.vprofile_photo);
App::feedUserLink(MTP_int(App::userFromPeer(peer->id)), d.vlink.c_contacts_link().vmy_link, d.vlink.c_contacts_link().vforeign_link, false);
App::main()->gotNotifySetting(MTP_inputNotifyPeer(peer->input), d.vnotify_settings);
peer->asUser()->setBotInfo(d.vbot_info);
_fullPeerRequests.remove(peer);
App::clearPeerUpdated(peer);
emit fullPeerUpdated(peer);
App::emitPeerUpdated();
}
bool ApiWrap::gotPeerFullFailed(PeerData *peer, const RPCError &error) {
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
_fullPeerRequests.remove(peer);
return true;
}
void ApiWrap::requestPeer(PeerData *peer) {
if (!peer || _fullPeerRequests.contains(peer) || _peerRequests.contains(peer)) return;
mtpRequestId req;
if (peer->chat) {
req = MTP::send(MTPmessages_GetChats(MTP_vector<MTPint>(1, MTP_int(App::chatFromPeer(peer->id)))), rpcDone(&ApiWrap::gotChat, peer), rpcFail(&ApiWrap::gotPeerFailed, peer));
} else {
req = MTP::send(MTPusers_GetUsers(MTP_vector<MTPInputUser>(1, peer->asUser()->inputUser)), rpcDone(&ApiWrap::gotUser, peer), rpcFail(&ApiWrap::gotPeerFailed, peer));
}
_peerRequests.insert(peer, req);
}
void ApiWrap::gotChat(PeerData *peer, const MTPmessages_Chats &result) {
_peerRequests.remove(peer);
if (result.type() == mtpc_messages_chats) {
const QVector<MTPChat> &v(result.c_messages_chats().vchats.c_vector().v);
bool badVersion = (!v.isEmpty() && v.at(0).type() == mtpc_chat && v.at(0).c_chat().vversion.v < peer->asChat()->version);
ChatData *chat = App::feedChats(result.c_messages_chats().vchats);
if (chat == peer) {
if (badVersion) {
peer->asChat()->version = v.at(0).c_chat().vversion.v;
requestPeer(peer);
}
}
}
}
void ApiWrap::gotUser(PeerData *peer, const MTPVector<MTPUser> &result) {
_peerRequests.remove(peer);
UserData *user = App::feedUsers(result);
if (user == peer) {
}
}
bool ApiWrap::gotPeerFailed(PeerData *peer, const RPCError &error) {
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
_peerRequests.remove(peer);
return true;
}
void ApiWrap::scheduleStickerSetRequest(uint64 setId, uint64 access) {
if (!_stickerSetRequests.contains(setId)) {
_stickerSetRequests.insert(setId, qMakePair(access, 0));
}
}
void ApiWrap::requestStickerSets() {
for (QMap<uint64, QPair<uint64, mtpRequestId> >::iterator i = _stickerSetRequests.begin(), j = i, e = _stickerSetRequests.end(); i != e; i = j) {
if (i.value().second) continue;
++j;
int32 wait = (j == e) ? 0 : 10;
i.value().second = MTP::send(MTPmessages_GetStickerSet(MTP_inputStickerSetID(MTP_long(i.key()), MTP_long(i.value().first))), rpcDone(&ApiWrap::gotStickerSet, i.key()), rpcFail(&ApiWrap::gotStickerSetFail, i.key()), 0, wait);
}
}
void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) {
_stickerSetRequests.remove(setId);
if (result.type() != mtpc_messages_stickerSet) return;
const MTPDmessages_stickerSet &d(result.c_messages_stickerSet());
if (d.vset.type() != mtpc_stickerSet) return;
const MTPDstickerSet &s(d.vset.c_stickerSet());
StickerSets &sets(cRefStickerSets());
StickerSets::iterator it = sets.find(setId);
if (it == sets.cend()) return;
it->access = s.vaccess_hash.v;
it->hash = s.vhash.v;
it->shortName = qs(s.vshort_name);
QString title = qs(s.vtitle);
if ((it->flags & MTPDstickerSet_flag_official) && !title.compare(qstr("Great Minds"), Qt::CaseInsensitive)) {
title = lang(lng_stickers_default_set);
}
it->title = title;
it->flags = s.vflags.v;
const QVector<MTPDocument> &d_docs(d.vdocuments.c_vector().v);
StickerSets::iterator custom = sets.find(CustomStickerSetId);
QSet<DocumentData*> found;
int32 wasCount = -1;
for (int32 i = 0, l = d_docs.size(); i != l; ++i) {
DocumentData *doc = App::feedDocument(d_docs.at(i));
if (!doc || !doc->sticker()) continue;
if (wasCount < 0) wasCount = it->stickers.size();
if (it->stickers.indexOf(doc) < 0) {
it->stickers.push_back(doc);
} else {
found.insert(doc);
}
if (custom != sets.cend()) {
int32 index = custom->stickers.indexOf(doc);
if (index >= 0) {
custom->stickers.removeAt(index);
}
}
}
if (custom != sets.cend() && custom->stickers.isEmpty()) {
sets.erase(custom);
custom = sets.end();
}
bool writeRecent = false;
RecentStickerPack &recent(cGetRecentStickers());
if (wasCount < 0) { // no stickers received
for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
cRefStickerSetsOrder().removeOne(setId);
sets.erase(it);
} else {
for (int32 j = 0, l = wasCount; j < l;) {
if (found.contains(it->stickers.at(j))) {
++j;
} else {
for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) {
if (it->stickers.at(j) == i->first) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
it->stickers.removeAt(j);
--l;
}
}
if (it->stickers.isEmpty()) {
cRefStickerSetsOrder().removeOne(setId);
sets.erase(it);
}
}
if (writeRecent) {
Local::writeUserSettings();
}
Local::writeStickers();
if (App::main()) emit App::main()->stickersUpdated();
}
bool ApiWrap::gotStickerSetFail(uint64 setId, const RPCError &error) {
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
_stickerSetRequests.remove(setId);
return true;
}
void ApiWrap::requestWebPageDelayed(WebPageData *page) {
if (page->pendingTill <= 0) return;
_webPagesPending.insert(page, 0);
int32 left = (page->pendingTill - unixtime()) * 1000;
if (!_webPagesTimer.isActive() || left <= _webPagesTimer.remainingTime()) {
_webPagesTimer.start((left < 0 ? 0 : left) + 1);
}
}
void ApiWrap::clearWebPageRequest(WebPageData *page) {
_webPagesPending.remove(page);
if (_webPagesPending.isEmpty() && _webPagesTimer.isActive()) _webPagesTimer.stop();
}
void ApiWrap::clearWebPageRequests() {
_webPagesPending.clear();
_webPagesTimer.stop();
}
void ApiWrap::resolveWebPages() {
QVector<MTPint> ids;
const WebPageItems &items(App::webPageItems());
ids.reserve(_webPagesPending.size());
int32 t = unixtime(), m = INT_MAX;
for (WebPagesPending::const_iterator i = _webPagesPending.cbegin(), e = _webPagesPending.cend(); i != e; ++i) {
if (i.value()) continue;
if (i.key()->pendingTill <= t) {
WebPageItems::const_iterator j = items.constFind(i.key());
if (j != items.cend() && !j.value().isEmpty()) {
ids.push_back(MTP_int(j.value().begin().key()->id));
}
} else {
m = qMin(m, i.key()->pendingTill - t);
}
}
if (!ids.isEmpty()) {
mtpRequestId req = MTP::send(MTPmessages_GetMessages(MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotWebPages));
for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) {
if (i.value()) continue;
if (i.key()->pendingTill <= t) {
i.value() = req;
}
}
}
if (m < INT_MAX) _webPagesTimer.start(m * 1000);
}
void ApiWrap::gotWebPages(const MTPmessages_Messages &msgs, mtpRequestId req) {
const QVector<MTPMessage> *v = 0;
switch (msgs.type()) {

View File

@@ -31,11 +31,15 @@ public:
void requestReplyTo(HistoryReply *reply, MsgId to);
void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer);
void requestWebPageDelayed(WebPageData *page);
void clearWebPageRequest(WebPageData *page);
void clearWebPageRequests();
void scheduleStickerSetRequest(uint64 setId, uint64 access);
void requestStickerSets();
~ApiWrap();
signals:
@@ -62,13 +66,22 @@ private:
void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result);
void gotUserFull(PeerData *peer, const MTPUserFull &result);
bool gotPeerFullFailed(PeerData *peer, const RPCError &err);
typedef QMap<PeerData*, mtpRequestId> PeerRequests;
PeerRequests _fullPeerRequests;
void gotChat(PeerData *peer, const MTPmessages_Chats &result);
void gotUser(PeerData *peer, const MTPVector<MTPUser> &result);
bool gotPeerFailed(PeerData *peer, const RPCError &err);
typedef QMap<PeerData*, mtpRequestId> FullRequests;
FullRequests _fullRequests;
PeerRequests _peerRequests;
void gotWebPages(const MTPmessages_Messages &result, mtpRequestId req);
typedef QMap<WebPageData*, mtpRequestId> WebPagesPending;
WebPagesPending _webPagesPending;
SingleTimer _webPagesTimer;
QMap<uint64, QPair<uint64, mtpRequestId> > _stickerSetRequests;
void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result);
bool gotStickerSetFail(uint64 setId, const RPCError &error);
};

View File

@@ -37,6 +37,9 @@ namespace {
typedef QMap<PeerData*, bool> MutedPeers;
MutedPeers mutedPeers;
typedef QMap<PeerData*, bool> UpdatedPeers;
UpdatedPeers updatedPeers;
typedef QHash<PhotoId, PhotoData*> PhotosData;
PhotosData photosData;
@@ -312,7 +315,11 @@ namespace App {
return lng_status_lastseen_date(lt_date, dOnline.date().toString(qsl("dd.MM.yy")));
}
bool onlineColorUse(int32 online, int32 now) {
bool onlineColorUse(UserData *user, int32 now) {
if (isServiceUser(user->id) || user->botInfo) {
return false;
}
int32 online = user->onlineTill;
if (online <= 0) {
switch (online) {
case 0:
@@ -326,7 +333,7 @@ namespace App {
return (online > now);
}
UserData *feedUsers(const MTPVector<MTPUser> &users) {
UserData *feedUsers(const MTPVector<MTPUser> &users, bool emitPeerUpdated) {
UserData *data = 0;
const QVector<MTPUser> &v(users.c_vector().v);
for (QVector<MTPUser>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
@@ -424,19 +431,25 @@ namespace App {
if (data->contact < 0 && !data->phone.isEmpty() && int32(data->id & 0xFFFFFFFF) != MTP::authedId()) {
data->contact = 0;
}
if (data->contact > 0 && !wasContact) {
App::main()->addNewContact(data->id & 0xFFFFFFFF, false);
} else if (wasContact && data->contact <= 0) {
App::main()->removeContact(data);
}
if (App::main()) {
if (data->contact > 0 && !wasContact) {
App::main()->addNewContact(data->id & 0xFFFFFFFF, false);
} else if (wasContact && data->contact <= 0) {
App::main()->removeContact(data);
}
if (App::main()) App::main()->peerUpdated(data);
if (emitPeerUpdated) {
App::main()->peerUpdated(data);
} else {
markPeerUpdated(data);
}
}
}
return data;
}
ChatData *feedChats(const MTPVector<MTPChat> &chats) {
ChatData *feedChats(const MTPVector<MTPChat> &chats, bool emitPeerUpdated) {
ChatData *data = 0;
const QVector<MTPChat> &v(chats.c_vector().v);
for (QVector<MTPChat>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
@@ -503,24 +516,31 @@ namespace App {
data->loaded = true;
data->updateName(title.trimmed(), QString(), QString());
if (App::main()) App::main()->peerUpdated(data);
if (App::main()) {
if (emitPeerUpdated) {
App::main()->peerUpdated(data);
} else {
markPeerUpdated(data);
}
}
}
return data;
}
void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos) {
void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos, bool emitPeerUpdated) {
ChatData *chat = 0;
switch (p.type()) {
case mtpc_chatParticipantsForbidden: {
const MTPDchatParticipantsForbidden &d(p.c_chatParticipantsForbidden());
ChatData *chat = App::chat(d.vchat_id.v);
chat = App::chat(d.vchat_id.v);
chat->count = -1;
if (App::main()) App::main()->peerUpdated(chat);
} break;
case mtpc_chatParticipants: {
const MTPDchatParticipants &d(p.c_chatParticipants());
ChatData *chat = App::chat(d.vchat_id.v);
chat = App::chat(d.vchat_id.v);
chat->admin = d.vadmin_id.v;
if (chat->version <= d.vversion.v) {
if (!requestBotInfos || chat->version <= d.vversion.v) { // !requestBotInfos is true on getFullChat result
chat->version = d.vversion.v;
const QVector<MTPChatParticipant> &v(d.vparticipants.c_vector().v);
chat->count = v.size();
@@ -564,13 +584,19 @@ namespace App {
if (App::main()) App::main()->updateBotKeyboard();
}
}
if (App::main()) App::main()->peerUpdated(chat);
}
} break;
}
if (chat && App::main()) {
if (emitPeerUpdated) {
App::main()->peerUpdated(chat);
} else {
markPeerUpdated(chat);
}
}
}
void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d) {
void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d, bool emitPeerUpdated) {
ChatData *chat = App::chat(d.vchat_id.v);
if (chat->version <= d.vversion.v && chat->count >= 0) {
chat->version = d.vversion.v;
@@ -597,11 +623,17 @@ namespace App {
chat->botStatus = 0;
chat->count++;
}
if (App::main()) App::main()->peerUpdated(chat);
if (App::main()) {
if (emitPeerUpdated) {
App::main()->peerUpdated(chat);
} else {
markPeerUpdated(chat);
}
}
}
}
void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d) {
void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d, bool emitPeerUpdated) {
ChatData *chat = App::chat(d.vchat_id.v);
if (chat->version <= d.vversion.v && chat->count > 0) {
chat->version = d.vversion.v;
@@ -641,7 +673,13 @@ namespace App {
chat->botStatus = 0;
chat->count--;
}
if (App::main()) App::main()->peerUpdated(chat);
if (App::main()) {
if (emitPeerUpdated) {
App::main()->peerUpdated(chat);
} else {
markPeerUpdated(chat);
}
}
}
}
@@ -737,6 +775,9 @@ namespace App {
History *h = App::historyLoaded(peer);
if (h) {
h->outboxRead(upTo);
if (!h->peer->chat) {
h->peer->asUser()->madeAction();
}
}
}
@@ -757,23 +798,30 @@ namespace App {
}
}
void feedUserLinks(const MTPVector<MTPcontacts_Link> &links) {
void feedUserLinks(const MTPVector<MTPcontacts_Link> &links, bool emitPeerUpdated) {
const QVector<MTPcontacts_Link> &v(links.c_vector().v);
for (QVector<MTPcontacts_Link>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
const MTPDcontacts_link &dv(i->c_contacts_link());
feedUsers(MTP_vector<MTPUser>(1, dv.vuser));
UserData *user = feedUsers(MTP_vector<MTPUser>(1, dv.vuser), false);
MTPint userId(MTP_int(0));
switch (dv.vuser.type()) {
case mtpc_userEmpty: userId = dv.vuser.c_userEmpty().vid; break;
case mtpc_user: userId = dv.vuser.c_user().vid; break;
}
if (userId.v) {
feedUserLink(userId, dv.vmy_link, dv.vforeign_link);
feedUserLink(userId, dv.vmy_link, dv.vforeign_link, false);
}
if (user && App::main()) {
if (emitPeerUpdated) {
App::main()->peerUpdated(user);
} else {
markPeerUpdated(user);
}
}
}
}
void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink) {
void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink, bool emitPeerUpdated) {
UserData *user = userLoaded(userId.v);
if (user) {
bool wasContact = (user->contact > 0);
@@ -808,7 +856,32 @@ namespace App {
}
}
user->setName(textOneLine(user->firstName), textOneLine(user->lastName), (user->contact || isServiceUser(user->id) || user->phone.isEmpty()) ? QString() : App::formatPhone(user->phone), textOneLine(user->username));
if (App::main()) App::main()->peerUpdated(user);
if (App::main()) {
if (emitPeerUpdated) {
App::main()->peerUpdated(user);
} else {
markPeerUpdated(user);
}
}
}
}
void markPeerUpdated(PeerData *data) {
updatedPeers.insert(data, true);
}
void clearPeerUpdated(PeerData *data) {
updatedPeers.remove(data);
}
void emitPeerUpdated() {
if (!updatedPeers.isEmpty() && App::main()) {
UpdatedPeers upd = updatedPeers;
updatedPeers.clear();
for (UpdatedPeers::const_iterator i = upd.cbegin(), e = upd.cend(); i != e; ++i) {
App::main()->peerUpdated(i.key());
}
}
}
@@ -1222,7 +1295,7 @@ namespace App {
}
convert->id = document;
convert->status = FileReady;
sentSticker = !!convert->sticker;
sentSticker = !!convert->sticker();
}
convert->access = access;
if (!convert->date && date) {
@@ -1236,20 +1309,20 @@ namespace App {
if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height())) {
convert->thumb = thumb;
}
if (convert->sticker && !attributes.isEmpty() && (convert->sticker->alt.isEmpty() || convert->sticker->set.type() == mtpc_inputStickerSetEmpty)) {
if (convert->sticker() && !attributes.isEmpty() && (convert->sticker()->alt.isEmpty() || convert->sticker()->set.type() == mtpc_inputStickerSetEmpty)) {
for (QVector<MTPDocumentAttribute>::const_iterator i = attributes.cbegin(), e = attributes.cend(); i != e; ++i) {
if (i->type() == mtpc_documentAttributeSticker) {
const MTPDdocumentAttributeSticker &d(i->c_documentAttributeSticker());
if (d.valt.c_string().v.length() > 0) {
convert->sticker->alt = qs(d.valt);
convert->sticker->set = d.vstickerset;
convert->sticker()->alt = qs(d.valt);
convert->sticker()->set = d.vstickerset;
}
}
}
}
}
if (convert->sticker && !convert->sticker->loc.dc && thumbLocation.dc) {
convert->sticker->loc = thumbLocation;
if (convert->sticker() && !convert->sticker()->loc.dc && thumbLocation.dc) {
convert->sticker()->loc = thumbLocation;
}
if (convert->location.check()) {
@@ -1263,7 +1336,7 @@ namespace App {
result = convert;
} else {
result = new DocumentData(document, access, date, attributes, mime, thumb, dc, size);
if (result->sticker) result->sticker->loc = thumbLocation;
if (result->sticker()) result->sticker()->loc = thumbLocation;
}
documentsData.insert(document, result);
} else {
@@ -1281,19 +1354,19 @@ namespace App {
if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height())) {
result->thumb = thumb;
}
if (result->sticker && !attributes.isEmpty() && (result->sticker->alt.isEmpty() || result->sticker->set.type() == mtpc_inputStickerSetEmpty)) {
if (result->sticker() && !attributes.isEmpty() && (result->sticker()->alt.isEmpty() || result->sticker()->set.type() == mtpc_inputStickerSetEmpty)) {
for (QVector<MTPDocumentAttribute>::const_iterator i = attributes.cbegin(), e = attributes.cend(); i != e; ++i) {
if (i->type() == mtpc_documentAttributeSticker) {
const MTPDdocumentAttributeSticker &d(i->c_documentAttributeSticker());
if (d.valt.c_string().v.length() > 0) {
result->sticker->alt = qs(d.valt);
result->sticker->set = d.vstickerset;
result->sticker()->alt = qs(d.valt);
result->sticker()->set = d.vstickerset;
}
}
}
}
if (result->sticker && !result->sticker->loc.dc && thumbLocation.dc) {
result->sticker->loc = thumbLocation;
if (result->sticker() && !result->sticker()->loc.dc && thumbLocation.dc) {
result->sticker()->loc = thumbLocation;
}
}
}
@@ -1546,6 +1619,7 @@ namespace App {
historyClearMsgs();
randomData.clear();
mutedPeers.clear();
updatedPeers.clear();
for (PeersData::const_iterator i = peersData.cbegin(), e = peersData.cend(); i != e; ++i) {
delete *i;
}
@@ -1573,7 +1647,6 @@ namespace App {
if (api()) api()->clearWebPageRequests();
cSetRecentStickers(RecentStickerPack());
cSetStickersHash(QByteArray());
cSetEmojiStickers(EmojiStickersMap());
cSetStickerSets(StickerSets());
cSetStickerSetsOrder(StickerSetsOrder());
cSetLastStickersUpdate(0);

View File

@@ -105,20 +105,25 @@ namespace App {
int32 onlineForSort(UserData *user, int32 now);
int32 onlineWillChangeIn(UserData *user, int32 nowOnServer);
QString onlineText(UserData *user, int32 nowOnServer, bool precise = false);
bool onlineColorUse(int32 online, int32 now);
bool onlineColorUse(UserData *user, int32 now);
UserData *feedUsers(const MTPVector<MTPUser> &users); // returns last user
ChatData *feedChats(const MTPVector<MTPChat> &chats); // returns last chat
void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos = false);
void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d);
void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d);
UserData *feedUsers(const MTPVector<MTPUser> &users, bool emitPeerUpdated = true); // returns last user
ChatData *feedChats(const MTPVector<MTPChat> &chats, bool emitPeerUpdated = true); // returns last chat
void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos, bool emitPeerUpdated = true);
void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d, bool emitPeerUpdated = true);
void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d, bool emitPeerUpdated = true);
void feedMsgs(const MTPVector<MTPMessage> &msgs, int msgsState = 0); // 2 - new read message, 1 - new unread message, 0 - not new message, -1 - searched message
void feedWereRead(const QVector<MTPint> &msgsIds);
void feedInboxRead(const PeerId &peer, int32 upTo);
void feedOutboxRead(const PeerId &peer, int32 upTo);
void feedWereDeleted(const QVector<MTPint> &msgsIds);
void feedUserLinks(const MTPVector<MTPcontacts_Link> &links);
void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink);
void feedUserLinks(const MTPVector<MTPcontacts_Link> &links, bool emitPeerUpdated = true);
void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink, bool emitPeerUpdated = true);
void markPeerUpdated(PeerData *data);
void clearPeerUpdated(PeerData *data);
void emitPeerUpdated();
int32 maxMsgId();
ImagePtr image(const MTPPhotoSize &size);

View File

@@ -48,28 +48,43 @@ namespace {
}
}
class EventFilterForMac : public QObject {
class EventFilterForKeys : public QObject {
public:
EventFilterForMac(QObject *parent) : QObject(parent) {
EventFilterForKeys(QObject *parent) : QObject(parent) {
}
bool eventFilter(QObject *o, QEvent *e) {
if (e->type() == QEvent::KeyPress) {
QKeyEvent *ev = static_cast<QKeyEvent*>(e);
if (ev->key() == Qt::Key_W && (ev->modifiers() & (Qt::MetaModifier | Qt::ControlModifier))) {
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
App::wnd()->minimizeToTray();
return true;
} else {
App::wnd()->hide();
App::wnd()->updateIsActive(cOfflineBlurTimeout());
App::wnd()->updateGlobalMenu();
if (cPlatform() == dbipMac) {
if (ev->key() == Qt::Key_W && (ev->modifiers() & (Qt::MetaModifier | Qt::ControlModifier))) {
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
App::wnd()->minimizeToTray();
return true;
} else {
App::wnd()->hide();
App::wnd()->updateIsActive(cOfflineBlurTimeout());
App::wnd()->updateGlobalMenu();
return true;
}
} else if (ev->key() == Qt::Key_M && (ev->modifiers() & (Qt::MetaModifier | Qt::ControlModifier))) {
App::wnd()->setWindowState(Qt::WindowMinimized);
return true;
}
} else if (ev->key() == Qt::Key_M && (ev->modifiers() & (Qt::MetaModifier | Qt::ControlModifier))) {
App::wnd()->setWindowState(Qt::WindowMinimized);
return true;
}
if (ev->key() == Qt::Key_MediaPlay) {
if (App::main()) App::main()->player()->playPressed();
} else if (ev->key() == Qt::Key_MediaPause) {
if (App::main()) App::main()->player()->pausePressed();
} else if (ev->key() == Qt::Key_MediaTogglePlayPause) {
if (App::main()) App::main()->player()->playPausePressed();
} else if (ev->key() == Qt::Key_MediaStop) {
if (App::main()) App::main()->player()->stopPressed();
} else if (ev->key() == Qt::Key_MediaPrevious) {
if (App::main()) App::main()->player()->prevPressed();
} else if (ev->key() == Qt::Key_MediaNext) {
if (App::main()) App::main()->player()->nextPressed();
}
}
return QObject::eventFilter(o, e);
@@ -95,9 +110,8 @@ Application::Application(int &argc, char **argv) : PsApplication(argc, argv),
}
mainApp = this;
if (cPlatform() == dbipMac) {
installEventFilter(new EventFilterForMac(this));
}
installEventFilter(new EventFilterForKeys(this));
QFontDatabase::addApplicationFont(qsl(":/gui/art/fonts/OpenSans-Regular.ttf"));
QFontDatabase::addApplicationFont(qsl(":/gui/art/fonts/OpenSans-Bold.ttf"));
@@ -640,10 +654,10 @@ void Application::checkMapVersion() {
psRegisterCustomScheme();
if (Local::oldMapVersion()) {
QString versionFeatures;
if (DevChannel && Local::oldMapVersion() < 8029) {
versionFeatures = lang(lng_new_version_minor);// QString::fromUtf8("\xe2\x80\x94 IPv6 connections support\n\xe2\x80\x94 Bug fixes and minor stuff");// .replace('@', qsl("@") + QChar(0x200D));
} else if (!DevChannel && Local::oldMapVersion() < 8024) {
versionFeatures = lng_new_version_text(lt_blog_link, qsl("https://telegram.org/blog/bot-revolution"));// lang(lng_new_version_text).trimmed();
if (DevChannel && Local::oldMapVersion() < 8039) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Moved to Qt 5.5\n\xe2\x80\x94 Some bugfixes and optimizations\n\xe2\x80\x94 In OS X 10.10.3 location marks sent from mobile should be displayed now");// .replace('@', qsl("@") + QChar(0x200D));
} else if (!DevChannel && Local::oldMapVersion() < 8038) {
versionFeatures = lang(lng_new_version_text).trimmed();
}
if (!versionFeatures.isEmpty()) {
versionFeatures = lng_new_version_wrap(lt_version, QString::fromStdWString(AppVersionStr), lt_changes, versionFeatures, lt_link, qsl("https://desktop.telegram.org/#changelog"));

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

After

Width:  |  Height:  |  Size: 220 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -25,14 +25,19 @@ void audioPlayNotify();
void audioFinish();
enum AudioPlayerState {
AudioPlayerStopped,
AudioPlayerStoppedAtStart,
AudioPlayerStarting,
AudioPlayerPlaying,
AudioPlayerFinishing,
AudioPlayerPausing,
AudioPlayerPaused,
AudioPlayerResuming,
AudioPlayerStopped = 0x01,
AudioPlayerStoppedAtEnd = 0x02,
AudioPlayerStoppedAtError = 0x03,
AudioPlayerStoppedAtStart = 0x04,
AudioPlayerStoppedMask = 0x07,
AudioPlayerStarting = 0x08,
AudioPlayerPlaying = 0x10,
AudioPlayerFinishing = 0x18,
AudioPlayerPausing = 0x20,
AudioPlayerPaused = 0x28,
AudioPlayerPausedAtEnd = 0x30,
AudioPlayerResuming = 0x38,
};
class AudioPlayerFader;
@@ -45,39 +50,68 @@ public:
AudioPlayer();
void play(AudioData *audio);
void pauseresume();
void play(const AudioMsgId &audio, int64 position = 0);
void play(const SongMsgId &song, int64 position = 0);
void pauseresume(MediaOverviewType type, bool fast = false);
void seek(int64 position); // type == OverviewDocuments
void stop(MediaOverviewType type);
void currentState(AudioMsgId *audio, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0);
void currentState(SongMsgId *song, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0);
void clearStoppedAtStart(const AudioMsgId &audio);
void clearStoppedAtStart(const SongMsgId &song);
void currentState(AudioData **audio, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0);
void clearStoppedAtStart(AudioData *audio);
void resumeDevice();
~AudioPlayer();
public slots:
void onError(AudioData *audio);
void onError(const AudioMsgId &audio);
void onError(const SongMsgId &song);
void onStopped(const AudioMsgId &audio);
void onStopped(const SongMsgId &song);
signals:
void updated(AudioData *audio);
void stopped(AudioData *audio);
void updated(const AudioMsgId &audio);
void updated(const SongMsgId &song);
void stopped(const AudioMsgId &audio);
void stopped(const SongMsgId &song);
void stoppedOnError(const AudioMsgId &audio);
void stoppedOnError(const SongMsgId &song);
void loaderOnStart(const AudioMsgId &audio, qint64 position);
void loaderOnStart(const SongMsgId &song, qint64 position);
void loaderOnCancel(const AudioMsgId &audio);
void loaderOnCancel(const SongMsgId &song);
void faderOnTimer();
void loaderOnStart(AudioData *audio);
void loaderOnCancel(AudioData *audio);
void suppressSong();
void unsuppressSong();
void suppressAll();
void songVolumeChanged();
private:
bool updateCurrentStarted(int32 pos = -1);
bool fadedStop(MediaOverviewType type, bool *fadedStart = 0);
bool updateCurrentStarted(MediaOverviewType type, int32 pos = -1);
bool checkCurrentALError(MediaOverviewType type);
struct Msg {
Msg() : audio(0), position(0), duration(0), frequency(AudioVoiceMsgFrequency), skipStart(0), skipEnd(0), loading(0), started(0),
Msg() : position(0), duration(0), frequency(AudioVoiceMsgFrequency), skipStart(0), skipEnd(0), loading(0), started(0),
state(AudioPlayerStopped), source(0), nextBuffer(0) {
memset(buffers, 0, sizeof(buffers));
memset(samplesCount, 0, sizeof(samplesCount));
}
AudioData *audio;
QString fname;
QByteArray data;
int64 position, duration;
@@ -92,9 +126,25 @@ private:
uint32 buffers[3];
int64 samplesCount[3];
};
struct AudioMsg : public Msg {
AudioMsg() {
}
AudioMsgId audio;
};
struct SongMsg : public Msg {
SongMsg() {
}
SongMsgId song;
};
int32 _current;
Msg _data[AudioVoiceMsgSimultaneously];
void currentState(Msg *current, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency);
void setStoppedState(Msg *current, AudioPlayerState state = AudioPlayerStopped);
int32 _audioCurrent;
AudioMsg _audioData[AudioVoiceMsgSimultaneously];
int32 _songCurrent;
SongMsg _songData[AudioSongSimultaneously];
QMutex _mutex;
@@ -154,10 +204,14 @@ public:
signals:
void error(AudioData *audio);
void playPositionUpdated(AudioData *audio);
void audioStopped(AudioData *audio);
void needToPreload(AudioData *audio);
void error(const AudioMsgId &audio);
void error(const SongMsgId &audio);
void playPositionUpdated(const AudioMsgId &audio);
void playPositionUpdated(const SongMsgId &audio);
void audioStopped(const AudioMsgId &audio);
void audioStopped(const SongMsgId &audio);
void needToPreload(const AudioMsgId &audio);
void needToPreload(const SongMsgId &audio);
void stopPauseDevice();
@@ -168,12 +222,30 @@ public slots:
void onPauseTimer();
void onPauseTimerStop();
void onSuppressSong();
void onUnsuppressSong();
void onSuppressAll();
void onSongVolumeChanged();
private:
enum {
EmitError = 0x01,
EmitStopped = 0x02,
EmitPositionUpdated = 0x04,
EmitNeedToPreload = 0x08,
};
int32 updateOnePlayback(AudioPlayer::Msg *m, bool &hasPlaying, bool &hasFading, float64 suppressGain, bool suppressGainChanged);
void setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state = AudioPlayerStopped);
QTimer _timer, _pauseTimer;
QMutex _pauseMutex;
bool _pauseFlag, _paused;
bool _suppressAll, _suppressAllAnim, _suppressSong, _suppressSongAnim, _songVolumeChanged;
anim::fvalue _suppressAllGain, _suppressSongGain;
uint64 _suppressAllStart, _suppressSongStart;
};
class AudioPlayerLoader;
@@ -187,22 +259,46 @@ public:
signals:
void error(AudioData *audio);
void error(const AudioMsgId &audio);
void error(const SongMsgId &song);
void needToCheck();
public slots:
void onInit();
void onStart(AudioData *audio);
void onLoad(AudioData *audio);
void onCancel(AudioData *audio);
void onStart(const AudioMsgId &audio, qint64 position);
void onStart(const SongMsgId &audio, qint64 position);
void onLoad(const AudioMsgId &audio);
void onLoad(const SongMsgId &audio);
void onCancel(const AudioMsgId &audio);
void onCancel(const SongMsgId &audio);
private:
typedef QMap<AudioData*, AudioPlayerLoader*> Loaders;
Loaders _loaders;
AudioMsgId _audio;
AudioPlayerLoader *_audioLoader;
void loadError(Loaders::iterator i);
SongMsgId _song;
AudioPlayerLoader *_songLoader;
void emitError(MediaOverviewType type);
void clear(MediaOverviewType type);
void setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state = AudioPlayerStopped);
AudioMsgId clearAudio();
SongMsgId clearSong();
enum SetupError {
SetupErrorAtStart = 0,
SetupErrorNotPlaying = 1,
SetupErrorLoadedFull = 2,
SetupNoErrorStarted = 3,
};
void loadData(MediaOverviewType type, const void *objId, qint64 position);
AudioPlayerLoader *setupLoader(MediaOverviewType type, const void *objId, SetupError &err, qint64 position);
AudioPlayer::Msg *checkLoader(MediaOverviewType type);
};
@@ -239,3 +335,5 @@ private:
QByteArray _captured;
};
MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat);

View File

@@ -33,7 +33,8 @@ ConnectionBox::ConnectionBox() :
_passwordInput(this, st::inpConnectionPassword, lang(lng_connection_password_ph), cConnectionProxy().password),
_autoRadio(this, qsl("conn_type"), dbictAuto, lang(lng_connection_auto_rb), (cConnectionType() == dbictAuto)),
_httpProxyRadio(this, qsl("conn_type"), dbictHttpProxy, lang(lng_connection_http_proxy_rb), (cConnectionType() == dbictHttpProxy)),
_tcpProxyRadio(this, qsl("conn_type"), dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), (cConnectionType() == dbictTcpProxy)) {
_tcpProxyRadio(this, qsl("conn_type"), dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), (cConnectionType() == dbictTcpProxy)),
_tryIPv6(this, lang(lng_connection_try_ipv6), cTryIPv6()) {
connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave()));
connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose()));
@@ -51,6 +52,7 @@ void ConnectionBox::hideAll() {
_autoRadio.hide();
_httpProxyRadio.hide();
_tcpProxyRadio.hide();
_tryIPv6.hide();
_hostInput.hide();
_portInput.hide();
@@ -65,8 +67,9 @@ void ConnectionBox::showAll() {
_autoRadio.show();
_httpProxyRadio.show();
_tcpProxyRadio.show();
_tryIPv6.show();
int32 h = st::boxTitleHeight + st::connectionSkip + _autoRadio.height() + st::connectionSkip + _httpProxyRadio.height() + st::connectionSkip + _tcpProxyRadio.height() + st::connectionSkip;
int32 h = st::boxTitleHeight + st::connectionSkip + _autoRadio.height() + st::connectionSkip + _httpProxyRadio.height() + st::connectionSkip + _tcpProxyRadio.height() + st::connectionSkip + st::lineWidth + st::connectionSkip + _tryIPv6.height() + st::connectionSkip;
if (_httpProxyRadio.checked() || _tcpProxyRadio.checked()) {
h += 2 * st::boxPadding.top() + 2 * _hostInput.height();
_hostInput.show();
@@ -99,6 +102,9 @@ void ConnectionBox::paintEvent(QPaintEvent *e) {
paintTitle(p, lang(lng_connection_header), true);
// paint separator
p.fillRect(st::boxPadding.left(), _tryIPv6.y() - st::connectionSkip - st::lineWidth, width() - st::boxPadding.left() - st::boxPadding.right(), st::lineWidth, st::scrollDef.shColor->b);
// paint shadow
p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b);
@@ -128,10 +134,11 @@ void ConnectionBox::resizeEvent(QResizeEvent *e) {
_passwordInput.move(width() - st::boxPadding.right() - _passwordInput.width(), _userInput.y());
}
int32 buttony = (_tcpProxyRadio.checked() ? (_userInput.y() + _userInput.height()) : (_tcpProxyRadio.y() + _tcpProxyRadio.height())) + st::connectionSkip;
int32 tryipv6y = (_tcpProxyRadio.checked() ? (_userInput.y() + _userInput.height()) : (_tcpProxyRadio.y() + _tcpProxyRadio.height())) + st::connectionSkip + st::lineWidth + st::connectionSkip;
_tryIPv6.move(st::boxPadding.left(), tryipv6y);
_saveButton.move(width() - _saveButton.width(), buttony);
_cancelButton.move(0, buttony);
_saveButton.move(width() - _saveButton.width(), _tryIPv6.y() + _tryIPv6.height() + st::connectionSkip);
_cancelButton.move(0, _saveButton.y());
}
void ConnectionBox::onChange() {
@@ -172,8 +179,17 @@ void ConnectionBox::onSave() {
QNetworkProxyFactory::setUseSystemConfiguration(false);
QNetworkProxyFactory::setUseSystemConfiguration(true);
}
Local::writeSettings();
MTP::restart();
reinitImageLinkManager();
emit closed();
if (cPlatform() == dbipWindows && cTryIPv6() != _tryIPv6.checked()) {
cSetTryIPv6(_tryIPv6.checked());
Local::writeSettings();
cSetRestarting(true);
cSetRestartingToSettings(true);
App::quit();
} else {
cSetTryIPv6(_tryIPv6.checked());
Local::writeSettings();
MTP::restart();
reinitImageLinkManager();
emit closed();
}
}

View File

@@ -47,4 +47,5 @@ private:
PortInput _portInput;
FlatInput _userInput, _passwordInput;
FlatRadiobutton _autoRadio, _httpProxyRadio, _tcpProxyRadio;
FlatCheckbox _tryIPv6;
};

View File

@@ -249,7 +249,7 @@ void ContactsInner::paintDialog(QPainter &p, PeerData *peer, ContactData *data,
} else {
if (data->inchat || data->check) {
p.setPen(st::white->p);
} else if (user && (uname || App::onlineColorUse(user->onlineTill, _time))) {
} else if (user && (uname || App::onlineColorUse(user, _time))) {
p.setPen(st::profileOnlineColor->p);
} else {
p.setPen(st::profileOfflineColor->p);

View File

@@ -264,12 +264,12 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) {
QString appName, appVer = qs(d.vapp_version), systemVer = qs(d.vsystem_version), deviceModel = qs(d.vdevice_model);
if (d.vapi_id.v == 2040 || d.vapi_id.v == 17349) {
appName = (d.vapi_id.v == 2040) ? qsl("Telegram Desktop") : qsl("Telegram Desktop (GitHub)");
// if (systemVer == QLatin1String("windows")) {
appName = (d.vapi_id.v == 2040) ? qstr("Telegram Desktop") : qstr("Telegram Desktop (GitHub)");
// if (systemVer == qstr("windows")) {
// deviceModel = qsl("Windows");
// } else if (systemVer == QLatin1String("os x")) {
// } else if (systemVer == qstr("os x")) {
// deviceModel = qsl("OS X");
// } else if (systemVer == QLatin1String("linux")) {
// } else if (systemVer == qstr("linux")) {
// deviceModel = qsl("Linux");
// }
if (appVer == QString::number(appVer.toInt())) {
@@ -293,7 +293,7 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) {
MTPint active = d.vdate_active.v ? d.vdate_active : d.vdate_created;
data.activeTime = active.v;
data.info = qs(d.vdevice_model) + QLatin1String(", ") + (platform.isEmpty() ? QString() : platform + ' ') + qs(d.vsystem_version);
data.info = qs(d.vdevice_model) + qstr(", ") + (platform.isEmpty() ? QString() : platform + ' ') + qs(d.vsystem_version);
data.ip = qs(d.vip) + (country.isEmpty() ? QString() : QString::fromUtf8(" \xe2\x80\x93 ") + country);
if (!data.hash || (d.vflags.v & 1)) {
data.active = QString();

View File

@@ -27,7 +27,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "localstorage.h"
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) :
_loaded(false), _setId(0), _setAccess(0), _bottom(0),
_loaded(false), _setId(0), _setAccess(0), _setCount(0), _setHash(0), _setFlags(0), _bottom(0),
_input(set), _installRequest(0) {
switch (set.type()) {
case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break;
@@ -46,7 +46,7 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_pack.reserve(v.size());
for (int32 i = 0, l = v.size(); i < l; ++i) {
DocumentData *doc = App::feedDocument(v.at(i));
if (!doc || !doc->sticker) continue;
if (!doc || !doc->sticker()) continue;
_pack.push_back(doc);
}
@@ -57,6 +57,9 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_setShortName = qs(s.vshort_name);
_setId = s.vid.v;
_setAccess = s.vaccess_hash.v;
_setCount = s.vcount.v;
_setHash = s.vhash.v;
_setFlags = s.vflags.v;
}
}
@@ -84,13 +87,25 @@ bool StickerSetInner::failedSet(const RPCError &error) {
void StickerSetInner::installDone(const MTPBool &result) {
StickerSets &sets(cRefStickerSets());
sets.insert(_setId, StickerSet(_setId, _setAccess, _setTitle, _setShortName)).value().stickers = _pack;
int32 index = cStickerSetsOrder().indexOf(_setId);
if (index > 0) {
cRefStickerSetsOrder().removeAt(index);
cRefStickerSetsOrder().push_front(_setId);
} else if (index < 0) {
cRefStickerSetsOrder().push_front(_setId);
sets.insert(_setId, StickerSet(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)).value().stickers = _pack;
int32 insertAtIndex = 0;
StickerSetsOrder &order(cRefStickerSetsOrder());
for (int32 s = order.size(); insertAtIndex < s; ++insertAtIndex) {
StickerSets::const_iterator i = sets.constFind(order.at(insertAtIndex));
if (i == sets.cend() || !(i->flags & MTPDstickerSet_flag_official)) {
break;
}
}
int32 currentIndex = cStickerSetsOrder().indexOf(_setId);
if (currentIndex != insertAtIndex) {
if (currentIndex > 0) {
order.removeAt(currentIndex);
if (currentIndex < insertAtIndex) {
--insertAtIndex;
}
}
order.insert(insertAtIndex, _setId);
}
StickerSets::iterator custom = sets.find(CustomStickerSetId);
@@ -141,11 +156,11 @@ void StickerSetInner::paintEvent(QPaintEvent *e) {
if (!doc->loader && doc->status != FileFailed && !already && !hasdata) {
doc->save(QString());
}
if (doc->sticker->img->isNull() && (already || hasdata)) {
if (doc->sticker()->img->isNull() && (already || hasdata)) {
if (already) {
doc->sticker->img = ImagePtr(doc->already());
doc->sticker()->img = ImagePtr(doc->already());
} else {
doc->sticker->img = ImagePtr(doc->data);
doc->sticker()->img = ImagePtr(doc->data);
}
}
}
@@ -158,8 +173,8 @@ void StickerSetInner::paintEvent(QPaintEvent *e) {
QPoint ppos = pos + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2);
if (goodThumb) {
p.drawPixmapLeft(ppos, width(), doc->thumb->pix(w, h));
} else if (!doc->sticker->img->isNull()) {
p.drawPixmapLeft(ppos, width(), doc->sticker->img->pix(w, h));
} else if (!doc->sticker()->img->isNull()) {
p.drawPixmapLeft(ppos, width(), doc->sticker()->img->pix(w, h));
}
}
}
@@ -193,7 +208,7 @@ QString StickerSetInner::shortName() const {
void StickerSetInner::install() {
if (_installRequest) return;
_installRequest = MTP::send(MTPmessages_InstallStickerSet(_input), rpcDone(&StickerSetInner::installDone), rpcFail(&StickerSetInner::installFailed));
_installRequest = MTP::send(MTPmessages_InstallStickerSet(_input, MTP_bool(false)), rpcDone(&StickerSetInner::installDone), rpcFail(&StickerSetInner::installFailed));
}
StickerSetInner::~StickerSetInner() {
@@ -235,7 +250,6 @@ void StickerSetBox::onAddStickers() {
void StickerSetBox::onShareStickers() {
QString url = qsl("https://telegram.me/addstickers/") + _inner.shortName();
DEBUG_LOG(("Setting text to clipboard from stickerset box: %1").arg(url));
QApplication::clipboard()->setText(url);
App::wnd()->showLayer(new ConfirmBox(lang(lng_stickers_copied), true), true);
}

View File

@@ -57,6 +57,7 @@ private:
bool _loaded;
uint64 _setId, _setAccess;
QString _title, _setTitle, _setShortName;
int32 _setCount, _setHash, _setFlags;
int32 _bottom;
MTPInputStickerSet _input;

View File

@@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#pragma once
static const int32 AppVersion = 8029;
static const wchar_t *AppVersionStr = L"0.8.29";
static const int32 AppVersion = 8039;
static const wchar_t *AppVersionStr = L"0.8.39";
static const bool DevChannel = true;
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
@@ -85,9 +85,10 @@ enum {
MediaOverviewPreloadCount = 4,
AudioVoiceMsgSimultaneously = 4,
AudioSongSimultaneously = 4,
AudioCheckPositionTimeout = 100, // 100ms per check audio pos
AudioCheckPositionDelta = 4800, // update position called each 4800 samples
AudioFadeTimeout = 10, // 10ms
AudioCheckPositionDelta = 2400, // update position called each 2400 samples
AudioFadeTimeout = 7, // 7ms
AudioFadeDuration = 500,
AudioVoiceMsgSkip = 400, // 200ms
AudioVoiceMsgFade = 300, // 300ms
@@ -100,7 +101,7 @@ enum {
AudioVoiceMsgInMemory = 1024 * 1024, // 1 Mb audio is hold in memory and auto loaded
AudioPauseDeviceTimeout = 3000, // pause in 3 secs after playing is over
StickerInMemory = 256 * 1024, // 128 Kb stickers hold in memory, auto loaded and displayed inline
StickerInMemory = 1024 * 1024, // 1024 Kb stickers hold in memory, auto loaded and displayed inline
StickerMaxSize = 2048, // 2048x2048 is a max image size for sticker
MediaViewImageSizeLimit = 100 * 1024 * 1024, // show up to 100mb jpg/png/gif docs in app
@@ -139,6 +140,8 @@ enum {
WrongPasscodeTimeout = 1500,
SessionsShortPollTimeout = 60000,
ChoosePeerByDragTimeout = 1000, // 1 second mouse not moved to choose dialog when dragging a file
};
inline bool isServiceUser(uint64 id) {

View File

@@ -680,6 +680,26 @@ void DialogsListWidget::itemReplaced(HistoryItem *oldItem, HistoryItem *newItem)
}
}
PeerData *DialogsListWidget::updateFromParentDrag(QPoint globalPos) {
lastMousePos = globalPos;
selByMouse = true;
onUpdateSelected(true);
update();
if (_state == DefaultState) {
if (sel) return sel->history->peer;
} else if (_state == FilteredState || _state == SearchedState) {
if (filteredSel >= 0 && filteredSel < filterResults.size()) {
return filterResults[filteredSel]->history->peer;
} else if (peopleSel >= 0 && peopleSel < peopleResults.size()) {
return peopleResults[peopleSel];
} else if (searchedSel >= 0 && searchedSel < searchResults.size()) {
return searchResults[searchedSel]->_item->history()->peer;
}
}
return 0;
}
void DialogsListWidget::itemRemoved(HistoryItem *item) {
int wasCount = searchResults.size();
for (int i = 0; i < searchResults.size();) {
@@ -1356,6 +1376,8 @@ MsgId DialogsListWidget::lastSearchId() const {
DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent)
, _drawShadow(true)
, _dragInScroll(false)
, _dragForward(false)
, dlgOffset(0)
, dlgCount(-1)
, dlgPreloading(0)
@@ -1388,6 +1410,11 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent)
connect(&_newGroup, SIGNAL(clicked()), this, SLOT(onNewGroup()));
connect(&_cancelSearch, SIGNAL(clicked()), this, SLOT(onCancelSearch()));
_chooseByDragTimer.setSingleShot(true);
connect(&_chooseByDragTimer, SIGNAL(timeout()), this, SLOT(onChooseByDrag()));
setAcceptDrops(true);
_searchTimer.setSingleShot(true);
connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchMessages()));
@@ -1604,6 +1631,10 @@ void DialogsWidget::onNeedSearchMessages() {
}
}
void DialogsWidget::onChooseByDrag() {
list.choosePeer();
}
void DialogsWidget::searchMessages(const QString &query) {
if (_filter.text() != query) {
_filter.setText(query);
@@ -1741,6 +1772,78 @@ bool DialogsWidget::addNewContact(int32 uid, bool show) {
return true;
}
void DialogsWidget::dragEnterEvent(QDragEnterEvent *e) {
if (App::main()->selectingPeer()) return;
_dragInScroll = false;
_dragForward = e->mimeData()->hasFormat(qsl("application/x-td-forward-selected"));
if (!_dragForward) _dragForward = e->mimeData()->hasFormat(qsl("application/x-td-forward-pressed-link"));
if (!_dragForward) _dragForward = e->mimeData()->hasFormat(qsl("application/x-td-forward-pressed"));
if (_dragForward && !cWideMode()) _dragForward = false;
if (_dragForward) {
e->setDropAction(Qt::CopyAction);
e->accept();
updateDragInScroll(scroll.geometry().contains(e->pos()));
} else if (App::main() && App::main()->getDragState(e->mimeData()) != DragStateNone) {
e->setDropAction(Qt::CopyAction);
e->accept();
}
_chooseByDragTimer.stop();
}
void DialogsWidget::dragMoveEvent(QDragMoveEvent *e) {
if (scroll.geometry().contains(e->pos())) {
if (_dragForward) {
updateDragInScroll(true);
} else {
_chooseByDragTimer.start(ChoosePeerByDragTimeout);
}
PeerData *p = list.updateFromParentDrag(mapToGlobal(e->pos()));
if (p) {
e->setDropAction(Qt::CopyAction);
} else {
e->setDropAction(Qt::IgnoreAction);
}
} else {
if (_dragForward) updateDragInScroll(false);
list.leaveEvent(0);
e->setDropAction(Qt::IgnoreAction);
}
e->accept();
}
void DialogsWidget::dragLeaveEvent(QDragLeaveEvent *e) {
if (_dragForward) {
updateDragInScroll(false);
} else {
_chooseByDragTimer.stop();
}
list.leaveEvent(0);
e->accept();
}
void DialogsWidget::updateDragInScroll(bool inScroll) {
if (_dragInScroll != inScroll) {
_dragInScroll = inScroll;
if (_dragInScroll) {
App::main()->forwardLayer(1);
} else {
App::main()->dialogsCancelled();
}
}
}
void DialogsWidget::dropEvent(QDropEvent *e) {
_chooseByDragTimer.stop();
if (scroll.geometry().contains(e->pos())) {
PeerData *p = list.updateFromParentDrag(mapToGlobal(e->pos()));
if (p) {
e->acceptProposedAction();
App::main()->onFilesOrForwardDrop(p->id, e->mimeData());
}
}
}
void DialogsWidget::onListScroll() {
// if (!App::self()) return;
@@ -1826,9 +1929,16 @@ void DialogsWidget::resizeEvent(QResizeEvent *e) {
_addContact.move(w - _addContact.width() - st::dlgPaddingHor, _filter.y());
_cancelSearch.move(w - _cancelSearch.width() - st::dlgPaddingHor, _filter.y());
scroll.move(0, _filter.height() + 2 * st::dlgFilterPadding);
int32 addToY = App::main() ? App::main()->contentScrollAddToY() : 0;
int32 newScrollY = scroll.scrollTop() + addToY;
scroll.resize(w, height() - _filter.y() - _filter.height() - st::dlgFilterPadding - st::dlgPaddingVer);
list.resize(w, list.height());
onListScroll();
if (addToY) {
scroll.scrollToY(newScrollY);
} else {
onListScroll();
}
}
void DialogsWidget::keyPressEvent(QKeyEvent *e) {

View File

@@ -98,6 +98,8 @@ public:
void itemRemoved(HistoryItem *item);
void itemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
PeerData *updateFromParentDrag(QPoint globalPos);
~DialogsListWidget();
public slots:
@@ -171,6 +173,12 @@ public:
void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req);
bool addNewContact(int32 uid, bool show = true);
void dragEnterEvent(QDragEnterEvent *e);
void dragMoveEvent(QDragMoveEvent *e);
void dragLeaveEvent(QDragLeaveEvent *e);
void dropEvent(QDropEvent *e);
void updateDragInScroll(bool inScroll);
void resizeEvent(QResizeEvent *e);
void keyPressEvent(QKeyEvent *e);
void paintEvent(QPaintEvent *e);
@@ -228,10 +236,15 @@ public slots:
bool onSearchMessages(bool searchCache = false);
void onNeedSearchMessages();
void onChooseByDrag();
private:
bool _drawShadow;
bool _dragInScroll, _dragForward;
QTimer _chooseByDragTimer;
void unreadCountsReceived(const QVector<MTPDialog> &dialogs);
bool dialogsFailed(const RPCError &error);
bool contactsFailed(const RPCError &error);

View File

@@ -384,7 +384,7 @@ void DragArea::dragLeaveEvent(QDragLeaveEvent *e) {
void DragArea::dropEvent(QDropEvent *e) {
static_cast<HistoryWidget*>(parentWidget())->dropEvent(e);
if (e->isAccepted()) {
emit dropped(e);
emit dropped(e->mimeData());
}
}
@@ -684,10 +684,11 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) {
p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (esize / cIntRetinaFactor())) / 2, width(), App::emojisLarge(), QRect(_variants[variant]->x * esize, _variants[variant]->y * esize, esize, esize));
}
EmojiPanInner::EmojiPanInner(QWidget *parent) : TWidget(parent),
EmojiPanInner::EmojiPanInner(QWidget *parent) : TWidget(parent), _maxHeight(int(st::emojiPanMaxHeight)),
_top(0), _selected(-1), _pressedSel(-1), _pickerSel(-1), _picker(this),
_switcherHover(0), _stickersWidth(st::emojiPanHeaderFont->m.width(lang(lng_switch_stickers))) {
resize(st::emojiPanFullSize.width(), countHeight());
resize(st::emojiPanWidth, countHeight());
setMouseTracking(true);
setFocusPolicy(Qt::NoFocus);
@@ -709,6 +710,11 @@ _switcherHover(0), _stickersWidth(st::emojiPanHeaderFont->m.width(lang(lng_switc
connect(&_picker, SIGNAL(hidden()), this, SLOT(onPickerHidden()));
}
void EmojiPanInner::setMaxHeight(int32 h) {
_maxHeight = h;
resize(st::emojiPanWidth, countHeight());
}
void EmojiPanInner::setScrollTop(int top) {
if (top == _top) return;
@@ -1131,10 +1137,11 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
update();
}
StickerPanInner::StickerPanInner(QWidget *parent) : TWidget(parent),
StickerPanInner::StickerPanInner(QWidget *parent) : TWidget(parent), _maxHeight(st::emojiPanMaxHeight),
_top(0), _selected(-1), _pressedSel(-1),
_switcherHover(0), _emojiWidth(st::emojiPanHeaderFont->m.width(lang(lng_switch_emoji))) {
resize(st::emojiPanFullSize.width(), countHeight());
resize(st::emojiPanWidth, countHeight());
setMouseTracking(true);
setFocusPolicy(Qt::NoFocus);
@@ -1143,6 +1150,11 @@ _switcherHover(0), _emojiWidth(st::emojiPanHeaderFont->m.width(lang(lng_switch_e
refreshStickers();
}
void StickerPanInner::setMaxHeight(int32 h) {
_maxHeight = h;
resize(st::emojiPanWidth, countHeight());
}
void StickerPanInner::setScrollTop(int top) {
if (top == _top) return;
@@ -1154,9 +1166,9 @@ void StickerPanInner::setScrollTop(int top) {
}
int StickerPanInner::countHeight() {
int result = 0, minLastH = st::emojiPanFullSize.height() - st::rbEmoji.height - st::stickerPanPadding;
int result = 0, minLastH = _maxHeight - st::rbEmoji.height - st::stickerPanPadding;
for (int i = 0; i < _sets.size(); ++i) {
int cnt = _sets.at(i).size(), rows = (cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0);
int cnt = _sets.at(i).pack.size(), rows = (cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0);
int h = st::emojiPanHeader + rows * st::stickerPanSize.height();
if (i == _sets.size() - 1 && h < minLastH) h = minLastH;
result += h;
@@ -1174,21 +1186,21 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
int32 y, tilly = 0;
for (int c = 0, l = _sets.size(); c < l; ++c) {
y = tilly;
int32 size = _sets.at(c).size();
int32 size = _sets.at(c).pack.size();
int32 rows = (size / StickerPanPerRow) + ((size % StickerPanPerRow) ? 1 : 0);
tilly = y + st::emojiPanHeader + (rows * st::stickerPanSize.height());
if (r.top() >= tilly) continue;
bool special = (_setIds[c] == DefaultStickerSetId || _setIds[c] == RecentStickerSetId);
bool special = (_sets[c].flags & MTPDstickerSet_flag_official);
y += st::emojiPanHeader;
QString title = _titles[c];
QString title = _sets[c].title;
if (r.bottom() <= y) {
p.setFont(st::emojiPanHeaderFont->f);
p.setPen(st::emojiPanHeaderColor->p);
p.drawTextLeft(st::emojiPanHeaderLeft, qMax(y - int(st::emojiPanHeader), _top) + st::emojiPanHeaderTop, width(), title);
if (!special && y >= _top + 2 * st::emojiPanHeader) {
p.setOpacity(st::stickerPanDeleteOpacity + (1 - st::stickerPanDeleteOpacity) * _hovers[c][size]);
p.setOpacity(st::stickerPanDeleteOpacity + (1 - st::stickerPanDeleteOpacity) * _sets[c].hovers[size]);
p.drawSpriteRight(QPoint(st::emojiPanHeaderLeft, y - (st::emojiPanHeader + st::notifyClose.icon.pxHeight()) / 2), width(), st::notifyClose.icon);
p.setOpacity(1);
}
@@ -1201,10 +1213,10 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
int32 index = i * StickerPanPerRow + j;
if (index >= size) break;
float64 hover = _hovers[c][index];
float64 hover = _sets[c].hovers[index];
DocumentData *sticker = _sets[c][index];
if (!sticker->sticker) continue;
DocumentData *sticker = _sets[c].pack[index];
if (!sticker->sticker()) continue;
QPoint pos(st::stickerPanPadding + j * st::stickerPanSize.width(), y + i * st::stickerPanSize.height());
if (hover > 0) {
@@ -1223,11 +1235,11 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
if (!sticker->loader && sticker->status != FileFailed && !already && !hasdata) {
sticker->save(QString());
}
if (sticker->sticker->img->isNull() && (already || hasdata)) {
if (sticker->sticker()->img->isNull() && (already || hasdata)) {
if (already) {
sticker->sticker->img = ImagePtr(sticker->already());
sticker->sticker()->img = ImagePtr(sticker->already());
} else {
sticker->sticker->img = ImagePtr(sticker->data);
sticker->sticker()->img = ImagePtr(sticker->data);
}
}
}
@@ -1240,12 +1252,12 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
if (goodThumb) {
p.drawPixmapLeft(ppos, width(), sticker->thumb->pix(w, h));
} else if (!sticker->sticker->img->isNull()) {
p.drawPixmapLeft(ppos, width(), sticker->sticker->img->pix(w, h));
} else if (!sticker->sticker()->img->isNull()) {
p.drawPixmapLeft(ppos, width(), sticker->sticker()->img->pix(w, h));
}
if (hover > 0 && _setIds[c] == RecentStickerSetId && _custom.at(index)) {
float64 xHover = _hovers[c][_sets[c].size() + index];
if (hover > 0 && _sets[c].id == RecentStickerSetId && _custom.at(index)) {
float64 xHover = _sets[c].hovers[_sets[c].pack.size() + index];
QPoint xPos = pos + QPoint(st::stickerPanSize.width() - st::stickerPanDelete.pxWidth(), 0);
p.setOpacity(hover * (xHover + (1 - xHover) * st::stickerPanDeleteOpacity));
@@ -1258,7 +1270,7 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
if (y - st::emojiPanHeader < _top) {
p.fillRect(QRect(0, qMin(_top, tilly - int(st::emojiPanHeader)), width(), st::emojiPanHeader), st::emojiPanHeaderBg->b);
} else if (!special && y >= _top + 2 * st::emojiPanHeader) {
p.setOpacity(st::stickerPanDeleteOpacity + (1 - st::stickerPanDeleteOpacity) * _hovers[c][size]);
p.setOpacity(st::stickerPanDeleteOpacity + (1 - st::stickerPanDeleteOpacity) * _sets[c].hovers[size]);
p.drawSpriteRight(QPoint(st::emojiPanHeaderLeft, y - (st::emojiPanHeader + st::notifyClose.icon.pxHeight()) / 2), width(), st::notifyClose.icon);
p.setOpacity(1);
}
@@ -1293,15 +1305,15 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
emit switchToEmoji();
return;
}
if (_selected >= MatrixRowShift * _setIds.size()) {
if (_selected >= MatrixRowShift * _sets.size()) {
return;
}
int tab = (_selected / MatrixRowShift), sel = _selected % MatrixRowShift;
if (_setIds[tab] == RecentStickerSetId && sel >= _sets[tab].size() && sel < _sets[tab].size() * 2 && _custom.at(sel - _sets[tab].size())) {
if (_sets[tab].id == RecentStickerSetId && sel >= _sets[tab].pack.size() && sel < _sets[tab].pack.size() * 2 && _custom.at(sel - _sets[tab].pack.size())) {
clearSelection(true);
bool refresh = false;
DocumentData *sticker = _sets[tab].at(sel - _sets[tab].size());
DocumentData *sticker = _sets[tab].pack.at(sel - _sets[tab].pack.size());
RecentStickerPack &recent(cGetRecentStickers());
for (int32 i = 0, l = recent.size(); i < l; ++i) {
if (recent.at(i).first == sticker) {
@@ -1333,10 +1345,10 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
}
return;
}
if (sel < _sets[tab].size()) {
emit selected(_sets[tab][sel]);
} else if (sel == _sets[tab].size()) {
emit removing(_setIds[tab]);
if (sel < _sets[tab].pack.size()) {
emit selected(_sets[tab].pack[sel]);
} else if (sel == _sets[tab].pack.size()) {
emit removing(_sets[tab].id);
}
}
@@ -1363,7 +1375,7 @@ void StickerPanInner::clearSelection(bool fast) {
if (fast) {
for (Animations::const_iterator i = _animations.cbegin(); i != _animations.cend(); ++i) {
int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
(index == SwitcherSelected ? _switcherHover : _hovers[tab][sel]) = 0;
(index == SwitcherSelected ? _switcherHover : _sets[tab].hovers[sel]) = 0;
}
_animations.clear();
_selected = _pressedSel = -1;
@@ -1377,14 +1389,9 @@ void StickerPanInner::refreshStickers() {
clearSelection(true);
const StickerSets &sets(cStickerSets());
_setIds.clear(); _setIds.reserve(sets.size() + 1);
_sets.clear(); _sets.reserve(sets.size() + 1);
_hovers.clear(); _hovers.reserve(sets.size() + 1);
_titles.clear(); _titles.reserve(sets.size() + 1);
refreshRecent(false);
appendSet(DefaultStickerSetId);
for (StickerSetsOrder::const_iterator i = cStickerSetsOrder().cbegin(), e = cStickerSetsOrder().cend(); i != e; ++i) {
appendSet(*i);
}
@@ -1400,11 +1407,11 @@ void StickerPanInner::refreshStickers() {
void StickerPanInner::preloadImages() {
uint64 ms = getms();
for (int32 i = 0, l = _sets.size(), k = 0; i < l; ++i) {
for (int32 j = 0, n = _sets.at(i).size(); j < n; ++j) {
for (int32 j = 0, n = _sets.at(i).pack.size(); j < n; ++j) {
if (++k > StickerPanPerRow * (StickerPanPerRow + 1)) break;
DocumentData *sticker = _sets.at(i).at(j);
if (!sticker || !sticker->sticker) continue;
DocumentData *sticker = _sets.at(i).pack.at(j);
if (!sticker || !sticker->sticker()) continue;
bool goodThumb = !sticker->thumb->isNull() && ((sticker->thumb->width() >= 128) || (sticker->thumb->height() >= 128));
if (goodThumb) {
@@ -1430,14 +1437,14 @@ void StickerPanInner::preloadImages() {
uint64 StickerPanInner::currentSet(int yOffset) const {
int y, ytill = 0;
for (int i = 0, l = _sets.size(); i < l; ++i) {
int cnt = _sets.at(i).size();
int cnt = _sets.at(i).pack.size();
y = ytill;
ytill = y + st::emojiPanHeader + ((cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0)) * st::stickerPanSize.height();
if (yOffset < ytill) {
return _setIds.at(i);
return _sets.at(i).id;
}
}
return _setIds.isEmpty() ? RecentStickerSetId : _setIds.back();
return _sets.isEmpty() ? RecentStickerSetId : _sets.back().id;
}
void StickerPanInner::appendSet(uint64 setId) {
@@ -1450,11 +1457,9 @@ void StickerPanInner::appendSet(uint64 setId) {
for (int32 i = 0, l = it->stickers.size(); i < l; ++i) {
pack.push_back(it->stickers.at(i));
}
_setIds.push_back(it->id);
_sets.push_back(pack);
_hovers.push_back(QVector<float64>(it->stickers.size() + 1, 0));
int32 availw = width() - st::emojiPanHeaderLeft - st::emojiSwitchSkip - _emojiWidth - (st::emojiSwitchSkip - st::emojiSwitchImgSkip);
_titles.push_back(st::emojiPanHeaderFont->m.elidedText(it->title, Qt::ElideRight, availw));
QString title = st::emojiPanHeaderFont->m.elidedText(it->title, Qt::ElideRight, availw);
_sets.push_back(DisplayedSet(it->id, it->flags, title, pack.size() + 1, pack));
}
void StickerPanInner::refreshRecent(bool performResize) {
@@ -1462,11 +1467,8 @@ void StickerPanInner::refreshRecent(bool performResize) {
clearSelection(true);
StickerSets::const_iterator customIt = cStickerSets().constFind(CustomStickerSetId);
if (cGetRecentStickers().isEmpty() && (customIt == cStickerSets().cend() || customIt->stickers.isEmpty())) {
if (!_setIds.isEmpty() && _setIds.at(0) == RecentStickerSetId) {
_setIds.pop_front();
if (!_sets.isEmpty() && _sets.at(0).id == RecentStickerSetId) {
_sets.pop_front();
_hovers.pop_front();
_titles.pop_front();
}
} else {
StickerPack recent;
@@ -1489,14 +1491,11 @@ void StickerPanInner::refreshRecent(bool performResize) {
_custom.push_back(true);
}
}
if (_setIds.isEmpty() || _setIds.at(0) != RecentStickerSetId) {
_setIds.push_front(RecentStickerSetId);
_hovers.push_back(QVector<float64>(recent.size() * 2, 0));
_sets.push_back(recent);
_titles.push_back(lang(lng_emoji_category0));
if (_sets.isEmpty() || _sets.at(0).id != RecentStickerSetId) {
_sets.push_back(DisplayedSet(RecentStickerSetId, MTPDstickerSet_flag_official, lang(lng_emoji_category0), recent.size() * 2, recent));
} else {
_sets[0] = recent;
_hovers[0].resize(recent.size() * 2);
_sets[0].pack = recent;
_sets[0].hovers.resize(recent.size() * 2);
}
}
@@ -1510,14 +1509,14 @@ void StickerPanInner::refreshRecent(bool performResize) {
void StickerPanInner::fillIcons(QVector<StickerIcon> &icons) {
icons.clear();
if (_setIds.isEmpty()) return;
if (_sets.isEmpty()) return;
icons.reserve(_sets.size());
int32 i = 0;
if (_setIds.at(0) == RecentStickerSetId) ++i;
if (_sets.at(0).id == RecentStickerSetId) ++i;
if (i > 0) icons.push_back(StickerIcon());
for (int32 l = _sets.size(); i < l; ++i) {
DocumentData *s = _sets.at(i).at(0);
DocumentData *s = _sets.at(i).pack.at(0);
int32 availw = st::rbEmoji.width - 2 * st::stickerIconPadding, availh = st::rbEmoji.height - 2 * st::stickerIconPadding;
int32 thumbw = s->thumb->width(), thumbh = s->thumb->height(), pixw = 1, pixh = 1;
if (availw * thumbh > availh * thumbw) {
@@ -1529,7 +1528,7 @@ void StickerPanInner::fillIcons(QVector<StickerIcon> &icons) {
}
if (pixw < 1) pixw = 1;
if (pixh < 1) pixh = 1;
icons.push_back(StickerIcon(_setIds.at(i), s, pixw, pixh));
icons.push_back(StickerIcon(_sets.at(i).id, s, pixw, pixh));
}
}
@@ -1547,25 +1546,27 @@ void StickerPanInner::updateSelected() {
}
} else {
int y, ytill = 0, sx = (rtl() ? width() - p.x() : p.x()) - st::stickerPanPadding;
for (int c = 0, l = _setIds.size(); c < l; ++c) {
int cnt = _sets[c].size();
bool special = _setIds[c] == DefaultStickerSetId || _setIds[c] == RecentStickerSetId;
for (int c = 0, l = _sets.size(); c < l; ++c) {
const DisplayedSet &set(_sets.at(c));
int cnt = set.pack.size();
bool special = (set.flags & MTPDstickerSet_flag_official);
y = ytill;
ytill = y + st::emojiPanHeader + ((cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0)) * st::stickerPanSize.height();
if (p.y() >= y && p.y() < ytill) {
if (!special && p.y() >= y && p.y() < y + st::emojiPanHeader && sx + st::stickerPanPadding >= width() - st::emojiPanHeaderLeft - st::notifyClose.icon.pxWidth() && sx + st::stickerPanPadding < width() - st::emojiPanHeaderLeft) {
selIndex = c * MatrixRowShift + _sets[c].size();
selIndex = c * MatrixRowShift + set.pack.size();
} else {
y += st::emojiPanHeader;
if (p.y() >= y && sx >= 0 && sx < StickerPanPerRow * st::stickerPanSize.width()) {
selIndex = qFloor((p.y() - y) / st::stickerPanSize.height()) * StickerPanPerRow + qFloor(sx / st::stickerPanSize.width());
if (selIndex >= _sets[c].size()) {
if (selIndex >= set.pack.size()) {
selIndex = -1;
} else {
if (_setIds[c] == RecentStickerSetId && _custom[selIndex]) {
if (set.id == RecentStickerSetId && _custom[selIndex]) {
int32 inx = sx - (selIndex % StickerPanPerRow) * st::stickerPanSize.width(), iny = p.y() - y - ((selIndex / StickerPanPerRow) * st::stickerPanSize.height());
if (inx >= st::stickerPanSize.width() - st::stickerPanDelete.pxWidth() && iny < st::stickerPanDelete.pxHeight()) {
selIndex += _sets[c].size();
selIndex += set.pack.size();
}
}
selIndex += c * MatrixRowShift;
@@ -1579,13 +1580,13 @@ void StickerPanInner::updateSelected() {
bool startanim = false;
int oldSel = _selected, oldSelTab = oldSel / MatrixRowShift, xOldSel = -1, newSel = selIndex, newSelTab = newSel / MatrixRowShift, xNewSel = -1;
if (oldSel >= 0 && oldSelTab < _setIds.size() && _setIds[oldSelTab] == RecentStickerSetId && oldSel >= oldSelTab * MatrixRowShift + _sets[oldSelTab].size()) {
if (oldSel >= 0 && oldSelTab < _sets.size() && _sets[oldSelTab].id == RecentStickerSetId && oldSel >= oldSelTab * MatrixRowShift + _sets[oldSelTab].pack.size()) {
xOldSel = oldSel;
oldSel -= _sets[oldSelTab].size();
oldSel -= _sets[oldSelTab].pack.size();
}
if (newSel >= 0 && newSelTab < _setIds.size() && _setIds[newSelTab] == RecentStickerSetId && newSel >= newSelTab * MatrixRowShift + _sets[newSelTab].size()) {
if (newSel >= 0 && newSelTab < _sets.size() && _sets[newSelTab].id == RecentStickerSetId && newSel >= newSelTab * MatrixRowShift + _sets[newSelTab].pack.size()) {
xNewSel = newSel;
newSel -= _sets[newSelTab].size();
newSel -= _sets[newSelTab].pack.size();
}
if (newSel != oldSel) {
if (oldSel >= 0) {
@@ -1630,10 +1631,10 @@ bool StickerPanInner::animStep(float64 ms) {
int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
float64 dt = float64(now - i.value()) / st::emojiPanDuration;
if (dt >= 1) {
(index == SwitcherSelected ? _switcherHover : _hovers[tab][sel]) = (i.key() > 0) ? 1 : 0;
(index == SwitcherSelected ? _switcherHover : _sets[tab].hovers[sel]) = (i.key() > 0) ? 1 : 0;
i = _animations.erase(i);
} else {
(index == SwitcherSelected ? _switcherHover : _hovers[tab][sel]) = (i.key() > 0) ? dt : (1 - dt);
(index == SwitcherSelected ? _switcherHover : _sets[tab].hovers[sel]) = (i.key() > 0) ? dt : (1 - dt);
++i;
}
}
@@ -1645,9 +1646,9 @@ void StickerPanInner::showStickerSet(uint64 setId) {
clearSelection(true);
int32 y = 0;
for (int c = 0; c < _setIds.size(); ++c) {
if (_setIds.at(c) == setId) break;
int rows = (_sets[c].size() / StickerPanPerRow) + ((_sets[c].size() % StickerPanPerRow) ? 1 : 0);
for (int c = 0; c < _sets.size(); ++c) {
if (_sets.at(c).id == setId) break;
int rows = (_sets[c].pack.size() / StickerPanPerRow) + ((_sets[c].pack.size() % StickerPanPerRow) ? 1 : 0);
y += st::emojiPanHeader + rows * st::stickerPanSize.height();
}
@@ -1658,7 +1659,7 @@ void StickerPanInner::showStickerSet(uint64 setId) {
update();
}
EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent),
EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent), _maxHeight(st::emojiPanMaxHeight),
_horizontal(false), _noTabUpdate(false), _hiding(false), a_opacity(0), _shadow(st::dropdownDef.shadow),
_recent(this , qsl("emoji_group"), dbietRecent , QString(), true , st::rbEmojiRecent),
_people(this , qsl("emoji_group"), dbietPeople , QString(), false, st::rbEmojiPeople),
@@ -1679,12 +1680,12 @@ e_scroll(this, st::emojiScroll), e_inner(), s_scroll(this, st::emojiScroll), s_i
s_scroll.setFocusPolicy(Qt::NoFocus);
s_scroll.viewport()->setFocusPolicy(Qt::NoFocus);
_width = st::dropdownDef.padding.left() + st::emojiPanFullSize.width() + st::dropdownDef.padding.right();
_height = st::dropdownDef.padding.top() + st::emojiPanFullSize.height() + st::dropdownDef.padding.bottom();
_width = st::dropdownDef.padding.left() + st::emojiPanWidth + st::dropdownDef.padding.right();
_height = st::dropdownDef.padding.top() + _maxHeight + st::dropdownDef.padding.bottom();
resize(_width, _height);
e_scroll.resize(st::emojiPanFullSize.width(), st::emojiPanFullSize.height() - st::rbEmoji.height);
s_scroll.resize(st::emojiPanFullSize.width(), st::emojiPanFullSize.height() - st::rbEmoji.height);
e_scroll.resize(st::emojiPanWidth, _maxHeight - st::rbEmoji.height);
s_scroll.resize(st::emojiPanWidth, _maxHeight - st::rbEmoji.height);
e_scroll.move(st::dropdownDef.padding.left(), st::dropdownDef.padding.top());
e_scroll.setWidget(&e_inner);
@@ -1696,8 +1697,8 @@ e_scroll(this, st::emojiScroll), e_inner(), s_scroll(this, st::emojiScroll), s_i
s_inner.setAttribute(Qt::WA_OpaquePaintEvent);
s_scroll.setAutoFillBackground(true);
int32 left = _iconsLeft = st::dropdownDef.padding.left() + (st::emojiPanFullSize.width() - 8 * st::rbEmoji.width) / 2;
int32 top = _iconsTop = st::dropdownDef.padding.top() + st::emojiPanFullSize.height() - st::rbEmoji.height;
int32 left = _iconsLeft = st::dropdownDef.padding.left() + (st::emojiPanWidth - 8 * st::rbEmoji.width) / 2;
int32 top = _iconsTop = st::dropdownDef.padding.top() + _maxHeight - st::rbEmoji.height;
prepareTab(left, top, _width, _recent);
prepareTab(left, top, _width, _people);
prepareTab(left, top, _width, _nature);
@@ -1735,6 +1736,41 @@ e_scroll(this, st::emojiScroll), e_inner(), s_scroll(this, st::emojiScroll), s_i
// setAttribute(Qt::WA_AcceptTouchEvents);
}
void EmojiPan::setMaxHeight(int32 h) {
h = qMin(int(st::emojiPanMaxHeight), h);
if (h == _maxHeight) return;
int32 was = _maxHeight;
_maxHeight = h;
_height = st::dropdownDef.padding.top() + _maxHeight + st::dropdownDef.padding.bottom();
resize(_width, _height);
if (was > _maxHeight) {
e_scroll.resize(st::emojiPanWidth, _maxHeight - st::rbEmoji.height);
s_scroll.resize(st::emojiPanWidth, _maxHeight - st::rbEmoji.height);
s_inner.setMaxHeight(_maxHeight);
e_inner.setMaxHeight(_maxHeight);
} else {
s_inner.setMaxHeight(_maxHeight);
e_inner.setMaxHeight(_maxHeight);
e_scroll.resize(st::emojiPanWidth, _maxHeight - st::rbEmoji.height);
s_scroll.resize(st::emojiPanWidth, _maxHeight - st::rbEmoji.height);
}
_iconsTop = st::dropdownDef.padding.top() + _maxHeight - st::rbEmoji.height;
_recent.move(_recent.x(), _iconsTop);
_people.move(_people.x(), _iconsTop);
_nature.move(_nature.x(), _iconsTop);
_food.move(_food.x(), _iconsTop);
_celebration.move(_celebration.x(), _iconsTop);
_activity.move(_activity.x(), _iconsTop);
_travel.move(_travel.x(), _iconsTop);
_objects.move(_objects.x(), _iconsTop);
update();
}
void EmojiPan::prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab) {
tab.moveToLeft(left, top, _width);
left += tab.width();
@@ -2362,9 +2398,9 @@ void EmojiPan::onSwitch() {
hideAll();
_moveStart = getms();
a_toCoord = (_stickersShown != rtl()) ? anim::ivalue(st::emojiPanFullSize.width(), 0) : anim::ivalue(-st::emojiPanFullSize.width(), 0);
a_toCoord = (_stickersShown != rtl()) ? anim::ivalue(st::emojiPanWidth, 0) : anim::ivalue(-st::emojiPanWidth, 0);
a_toAlpha = anim::fvalue(0, 1);
a_fromCoord = (_stickersShown != rtl()) ? anim::ivalue(0, -st::emojiPanFullSize.width()) : anim::ivalue(0, st::emojiPanFullSize.width());
a_fromCoord = (_stickersShown != rtl()) ? anim::ivalue(0, -st::emojiPanWidth) : anim::ivalue(0, st::emojiPanWidth);
a_fromAlpha = anim::fvalue(1, 0);
if (!animating()) anim::start(this);
@@ -2373,7 +2409,7 @@ void EmojiPan::onSwitch() {
void EmojiPan::onRemoveSet(uint64 setId) {
StickerSets::const_iterator it = cStickerSets().constFind(setId);
if (it != cStickerSets().cend() && setId != DefaultStickerSetId && setId != RecentStickerSetId) {
if (it != cStickerSets().cend() && !(it->flags & MTPDstickerSet_flag_official)) {
_removingSetId = it->id;
ConfirmBox *box = new ConfirmBox(lng_stickers_remove_pack(lt_sticker_pack, it->title));
connect(box, SIGNAL(confirmed()), this, SLOT(onRemoveSetSure()));
@@ -2385,7 +2421,7 @@ void EmojiPan::onRemoveSet(uint64 setId) {
void EmojiPan::onRemoveSetSure() {
App::wnd()->hideLayer();
StickerSets::iterator it = cRefStickerSets().find(_removingSetId);
if (it != cRefStickerSets().cend() && _removingSetId != DefaultStickerSetId && _removingSetId != RecentStickerSetId) {
if (it != cRefStickerSets().cend() && !(it->flags & MTPDstickerSet_flag_official)) {
if (it->id && it->access) {
MTP::send(MTPmessages_UninstallStickerSet(MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access))));
} else if (!it->shortName.isEmpty()) {
@@ -2425,7 +2461,8 @@ void MentionsInner::paintEvent(QPaintEvent *e) {
QPainter p(this);
int32 atwidth = st::mentionFont->m.width('@'), hashwidth = st::mentionFont->m.width('#');
int32 availwidth = width() - 2 * st::mentionPadding.left() - st::mentionPhotoSize - 2 * st::mentionPadding.right();
int32 mentionleft = 2 * st::mentionPadding.left() + st::mentionPhotoSize;
int32 mentionwidth = width() - mentionleft - 2 * st::mentionPadding.right();
int32 htagleft = st::btnAttachPhoto.width + st::taMsgField.textMrg.left() - st::dlgShadow, htagwidth = width() - st::mentionPadding.right() - htagleft - st::mentionScroll.width;
int32 from = qFloor(e->rect().top() / st::mentionHeight), to = qFloor(e->rect().bottom() / st::mentionHeight) + 1;
@@ -2445,9 +2482,9 @@ void MentionsInner::paintEvent(QPaintEvent *e) {
UserData *user = _rows->at(i);
QString first = (_parent->filter().size() < 2) ? QString() : ('@' + user->username.mid(0, _parent->filter().size() - 1)), second = (_parent->filter().size() < 2) ? ('@' + user->username) : user->username.mid(_parent->filter().size() - 1);
int32 firstwidth = st::mentionFont->m.width(first), secondwidth = st::mentionFont->m.width(second), unamewidth = firstwidth + secondwidth, namewidth = user->nameText.maxWidth();
if (availwidth < unamewidth + namewidth) {
namewidth = (availwidth * namewidth) / (namewidth + unamewidth);
unamewidth = availwidth - namewidth;
if (mentionwidth < unamewidth + namewidth) {
namewidth = (mentionwidth * namewidth) / (namewidth + unamewidth);
unamewidth = mentionwidth - namewidth;
if (firstwidth < unamewidth + st::mentionFont->elidew) {
if (firstwidth < unamewidth) {
first = st::mentionFont->m.elidedText(first, Qt::ElideRight, unamewidth);
@@ -2465,10 +2502,10 @@ void MentionsInner::paintEvent(QPaintEvent *e) {
p.setFont(st::mentionFont->f);
p.setPen((selected ? st::mentionFgOverActive : st::mentionFgActive)->p);
p.drawText(2 * st::mentionPadding.left() + st::mentionPhotoSize + namewidth + st::mentionPadding.right(), i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, first);
p.drawText(mentionleft + namewidth + st::mentionPadding.right(), i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, first);
if (!second.isEmpty()) {
p.setPen((selected ? st::mentionFgOver : st::mentionFg)->p);
p.drawText(2 * st::mentionPadding.left() + st::mentionPhotoSize + namewidth + st::mentionPadding.right() + firstwidth, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, second);
p.drawText(mentionleft + namewidth + st::mentionPadding.right() + firstwidth, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, second);
}
} else if (!_hrows->isEmpty()) {
QString hrow = _hrows->at(i);
@@ -2495,50 +2532,42 @@ void MentionsInner::paintEvent(QPaintEvent *e) {
} else {
UserData *user = _crows->at(i).first;
const BotCommand &command = _crows->at(i).second;
QString toHighlight = command.command;
const BotCommand *command = _crows->at(i).second;
QString toHighlight = command->command;
int32 botStatus = _parent->chat() ? _parent->chat()->botStatus : -1;
if (hasUsername || botStatus == 0 || botStatus == 2) {
toHighlight += '@' + user->username;
}
if (_parent->chat() || botStatus == 0 || botStatus == 2) {
if (true || _parent->chat() || botStatus == 0 || botStatus == 2) {
user->photo->load();
p.drawPixmap(st::mentionPadding.left(), i * st::mentionHeight + st::mentionPadding.top(), user->photo->pixRounded(st::mentionPhotoSize));
}
int32 addleft = 0, widthleft = htagwidth;
int32 addleft = 0, widthleft = mentionwidth;
QString first = (_parent->filter().size() < 2) ? QString() : ('/' + toHighlight.mid(0, _parent->filter().size() - 1)), second = (_parent->filter().size() < 2) ? ('/' + toHighlight) : toHighlight.mid(_parent->filter().size() - 1);
int32 firstwidth = st::mentionFont->m.width(first), secondwidth = st::mentionFont->m.width(second);
if (htagwidth < firstwidth + secondwidth) {
if (htagwidth < firstwidth + st::mentionFont->elidew) {
first = st::mentionFont->m.elidedText(first + second, Qt::ElideRight, htagwidth);
if (widthleft < firstwidth + secondwidth) {
if (widthleft < firstwidth + st::mentionFont->elidew) {
first = st::mentionFont->m.elidedText(first + second, Qt::ElideRight, widthleft);
second = QString();
} else {
second = st::mentionFont->m.elidedText(second, Qt::ElideRight, htagwidth - firstwidth);
second = st::mentionFont->m.elidedText(second, Qt::ElideRight, widthleft - firstwidth);
}
}
p.setFont(st::mentionFont->f);
if (!first.isEmpty()) {
p.setPen((selected ? st::mentionFgOverActive : st::mentionFgActive)->p);
p.drawText(htagleft, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, first);
p.drawText(mentionleft, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, first);
}
if (!second.isEmpty()) {
p.setPen((selected ? st::mentionFgOver : st::mentionFg)->p);
p.drawText(htagleft + firstwidth, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, second);
p.drawText(mentionleft + firstwidth, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, second);
}
addleft += firstwidth + secondwidth + st::mentionPadding.left();
widthleft -= firstwidth + secondwidth + st::mentionPadding.left();
QString description = command.description;
if (widthleft > st::mentionFont->elidew && !description.isEmpty()) {
p.setFont(st::mentionFont->f);
int32 descwidth = st::mentionFont->m.width(description);
if (widthleft < descwidth) {
description = st::mentionFont->m.elidedText(description, Qt::ElideRight, widthleft);
descwidth = st::mentionFont->m.width(description);
}
if (widthleft > st::mentionFont->elidew && !command->descriptionText().isEmpty()) {
p.setPen((selected ? st::mentionFgOver : st::mentionFg)->p);
p.drawText(htagleft + addleft + (widthleft - descwidth), i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, description);
command->descriptionText().drawElided(p, mentionleft + addleft, i * st::mentionHeight + st::mentionTop, widthleft, 1, style::al_right);
}
}
}
@@ -2574,6 +2603,15 @@ bool MentionsInner::moveSel(int direction) {
}
bool MentionsInner::select() {
QString sel = getSelected();
if (!sel.isEmpty()) {
emit chosen(sel);
return true;
}
return false;
}
QString MentionsInner::getSelected() const {
int32 maxSel = (_rows->isEmpty() ? (_hrows->isEmpty() ? _crows->size() : _hrows->size()) : _rows->size());
if (_sel >= 0 && _sel < maxSel) {
QString result;
@@ -2583,18 +2621,17 @@ bool MentionsInner::select() {
result = '#' + _hrows->at(_sel);
} else {
UserData *user = _crows->at(_sel).first;
const BotCommand &command(_crows->at(_sel).second);
const BotCommand *command(_crows->at(_sel).second);
int32 botStatus = _parent->chat() ? _parent->chat()->botStatus : -1;
if (botStatus == 0 || botStatus == 2 || _parent->filter().indexOf('@') > 1) {
result = '/' + command.command + '@' + user->username;
result = '/' + command->command + '@' + user->username;
} else {
result = '/' + command.command;
result = '/' + command->command;
}
}
emit chosen(result);
return true;
return result;
}
return false;
return QString();
}
void MentionsInner::mousePressEvent(QMouseEvent *e) {
@@ -2720,6 +2757,12 @@ void MentionsDropdown::showFiltered(PeerData *peer, QString start) {
updateFiltered(toDown);
}
bool MentionsDropdown::clearFilteredCommands() {
if (_crows.isEmpty()) return false;
_crows.clear();
return true;
}
void MentionsDropdown::updateFiltered(bool toDown) {
int32 now = unixtime();
MentionRows rows;
@@ -2783,6 +2826,7 @@ void MentionsDropdown::updateFiltered(bool toDown) {
}
}
} else if (_user->botInfo) {
if (!_user->botInfo->inited) App::api()->requestFullPeer(_user);
cnt = _user->botInfo->commands.size();
bots.insert(_user, true);
}
@@ -2793,17 +2837,16 @@ void MentionsDropdown::updateFiltered(bool toDown) {
for (MentionRows::const_iterator i = _chat->lastAuthors.cbegin(), e = _chat->lastAuthors.cend(); i != e; ++i) {
UserData *user = *i;
if (!user->botInfo) continue;
if (!bots.contains(user)) continue;
if (!user->botInfo->inited) App::api()->requestFullPeer(user);
if (user->botInfo->commands.isEmpty()) continue;
bots.remove(user);
for (int32 j = 0, l = user->botInfo->commands.size(); j < l; ++j) {
if (_filter.size() > 1) {
QString toFilter = (hasUsername || botStatus == 0 || botStatus == 2) ? user->botInfo->commands.at(j).command + '@' + user->username : user->botInfo->commands.at(j).command;
if (!toFilter.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || toFilter.size() + 1 == _filter.size()) continue;
if (!toFilter.startsWith(_filter.midRef(1), Qt::CaseInsensitive)/* || toFilter.size() + 1 == _filter.size()*/) continue;
}
crows.push_back(qMakePair(user, user->botInfo->commands.at(j)));
}
if (!bots.isEmpty()) {
bots.remove(user);
crows.push_back(qMakePair(user, &user->botInfo->commands.at(j)));
}
}
}
@@ -2813,9 +2856,9 @@ void MentionsDropdown::updateFiltered(bool toDown) {
for (int32 j = 0, l = user->botInfo->commands.size(); j < l; ++j) {
if (_filter.size() > 1) {
QString toFilter = (hasUsername || botStatus == 0 || botStatus == 2) ? user->botInfo->commands.at(j).command + '@' + user->username : user->botInfo->commands.at(j).command;
if (!toFilter.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || toFilter.size() + 1 == _filter.size()) continue;
if (!toFilter.startsWith(_filter.midRef(1), Qt::CaseInsensitive)/* || toFilter.size() + 1 == _filter.size()*/) continue;
}
crows.push_back(qMakePair(user, user->botInfo->commands.at(j)));
crows.push_back(qMakePair(user, &user->botInfo->commands.at(j)));
}
}
}
@@ -2824,10 +2867,10 @@ void MentionsDropdown::updateFiltered(bool toDown) {
if (rows.isEmpty() && hrows.isEmpty() && crows.isEmpty()) {
if (!isHidden()) {
hideStart();
_rows.clear();
_hrows.clear();
_crows.clear();
}
_rows.clear();
_hrows.clear();
_crows.clear();
} else {
_rows = rows;
_hrows = hrows;
@@ -2857,13 +2900,13 @@ void MentionsDropdown::recount(bool toDown) {
int32 h = (_rows.isEmpty() ? (_hrows.isEmpty() ? _crows.size() : _hrows.size()) : _rows.size()) * st::mentionHeight, oldst = _scroll.scrollTop(), st = oldst;
if (_inner.height() != h) {
st += h - _inner.height();
// st += h - _inner.height();
_inner.resize(width(), h);
}
if (h > _boundings.height()) h = _boundings.height();
if (h > 4.5 * st::mentionHeight) h = 4.5 * st::mentionHeight;
if (height() != h) {
st += _scroll.height() - h;
// st += _scroll.height() - h;
setGeometry(0, _boundings.height() - h, width(), h);
_scroll.resize(width(), h);
} else if (y() != _boundings.height() - h) {
@@ -2954,6 +2997,10 @@ int32 MentionsDropdown::innerBottom() {
return _scroll.scrollTop() + _scroll.height();
}
QString MentionsDropdown::getSelected() const {
return _inner.getSelected();
}
bool MentionsDropdown::eventFilter(QObject *obj, QEvent *e) {
if (isHidden()) return QWidget::eventFilter(obj, e);
if (e->type() == QEvent::KeyPress) {

View File

@@ -110,7 +110,7 @@ public:
signals:
void dropped(QDropEvent *e);
void dropped(const QMimeData *data);
public slots:
@@ -202,6 +202,7 @@ public:
EmojiPanInner(QWidget *parent = 0);
void setMaxHeight(int32 h);
void paintEvent(QPaintEvent *e);
void mousePressEvent(QMouseEvent *e);
@@ -244,6 +245,8 @@ signals:
private:
int32 _maxHeight;
int32 countHeight();
void selectEmoji(EmojiPtr emoji);
@@ -286,6 +289,7 @@ public:
StickerPanInner(QWidget *parent = 0);
void setMaxHeight(int32 h);
void paintEvent(QPaintEvent *e);
void mousePressEvent(QMouseEvent *e);
@@ -329,6 +333,8 @@ signals:
private:
int32 _maxHeight;
void appendSet(uint64 setId);
int32 countHeight();
@@ -339,10 +345,16 @@ private:
int32 _top;
QList<QString> _titles;
QList<uint64> _setIds;
QList<StickerPack> _sets;
QList<QVector<float64> > _hovers;
struct DisplayedSet {
DisplayedSet(uint64 id, int32 flags, const QString &title, int32 hoversSize, const StickerPack &pack = StickerPack()) : id(id), flags(flags), title(title), hovers(hoversSize, 0), pack(pack) {
}
uint64 id;
int32 flags;
QString title;
QVector<float64> hovers;
StickerPack pack;
};
QList<DisplayedSet> _sets;
QList<bool> _custom;
int32 _selected, _pressedSel;
@@ -359,6 +371,7 @@ public:
EmojiPan(QWidget *parent);
void setMaxHeight(int32 h);
void paintEvent(QPaintEvent *e);
void enterEvent(QEvent *e);
@@ -412,6 +425,7 @@ signals:
private:
int32 _maxHeight;
bool _horizontal;
void leaveToChildEvent(QEvent *e);
@@ -467,7 +481,7 @@ private:
typedef QList<UserData*> MentionRows;
typedef QList<QString> HashtagRows;
typedef QList<QPair<UserData*, BotCommand> > BotCommandRows;
typedef QList<QPair<UserData*, const BotCommand*> > BotCommandRows;
class MentionsDropdown;
class MentionsInner : public QWidget {
@@ -489,6 +503,8 @@ public:
bool moveSel(int direction);
bool select();
QString getSelected() const;
signals:
void chosen(QString mentionOrHashtag);
@@ -525,6 +541,7 @@ public:
void fastHide();
bool clearFilteredCommands();
void showFiltered(PeerData *peer, QString start);
void updateFiltered(bool toDown = false);
void setBoundings(QRect boundings);
@@ -538,6 +555,7 @@ public:
int32 innerBottom();
bool eventFilter(QObject *obj, QEvent *e);
QString getSelected() const;
~MentionsDropdown();

View File

@@ -25,9 +25,9 @@ void filedialogInit() {
if (cDialogLastPath().isEmpty()) {
#ifdef Q_OS_WIN
// hack to restore previous dir without hurting performance
QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
settings.beginGroup(QLatin1String("Qt"));
QByteArray sd = settings.value(QLatin1String("filedialog")).toByteArray();
QSettings settings(QSettings::UserScope, qstr("QtProject"));
settings.beginGroup(qstr("Qt"));
QByteArray sd = settings.value(qstr("filedialog")).toByteArray();
QDataStream stream(&sd, QIODevice::ReadOnly);
if (!stream.atEnd()) {
int version = 3, _QFileDialogMagic = 190;

View File

@@ -128,7 +128,8 @@ int32 FlatTextarea::fakeMargin() const {
void FlatTextarea::paintEvent(QPaintEvent *e) {
QPainter p(viewport());
p.fillRect(rect(), _st.bgColor->b);
QRect r(rect().intersected(e->rect()));
p.fillRect(r, _st.bgColor->b);
bool phDraw = _phVisible;
if (animating()) {
p.setOpacity(a_phAlpha.current());
@@ -136,7 +137,7 @@ void FlatTextarea::paintEvent(QPaintEvent *e) {
}
if (phDraw) {
p.save();
p.setClipRect(rect());
p.setClipRect(r);
QRect phRect(_st.textMrg.left() - _fakeMargin + _st.phPos.x() + a_phLeft.current(), _st.textMrg.top() - _fakeMargin + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom());
p.setFont(_st.font->f);
p.setPen(a_phColor.current());
@@ -174,7 +175,10 @@ EmojiPtr FlatTextarea::getSingleEmoji() const {
if (!text.isEmpty()) {
QTextCharFormat format = fragment.charFormat();
return emojiFromUrl(static_cast<const QTextImageFormat*>(&format)->name());
QString imageName = static_cast<QTextImageFormat*>(&format)->name();
if (imageName.startsWith(qstr("emoji://e."))) {
return emojiFromUrl(imageName);
}
}
return 0;
}
@@ -303,7 +307,7 @@ void FlatTextarea::getSingleEmojiFragment(QString &text, QTextFragment &fragment
}
if (f.isImageFormat() && !t.isEmpty() && t.at(0).unicode() == QChar::ObjectReplacementCharacter) {
QString imageName = static_cast<QTextImageFormat*>(&f)->name();
if (imageName.startsWith(QLatin1String("emoji://e."))) {
if (imageName.startsWith(qstr("emoji://e."))) {
fragment = fr;
text = t;
return;
@@ -387,7 +391,7 @@ QString FlatTextarea::getText(int32 start, int32 end) const {
case QChar::ObjectReplacementCharacter:
if (emojiText.isEmpty() && f.isImageFormat()) {
QString imageName = static_cast<QTextImageFormat*>(&f)->name();
if (imageName.startsWith(QLatin1String("emoji://e."))) {
if (imageName.startsWith(qstr("emoji://e."))) {
if (EmojiPtr emoji = emojiFromUrl(imageName)) {
emojiText = emojiString(emoji);
}
@@ -530,17 +534,25 @@ void FlatTextarea::insertFromMimeData(const QMimeData *source) {
}
void FlatTextarea::insertEmoji(EmojiPtr emoji, QTextCursor c) {
c.removeSelectedText();
QPixmap img(App::emojiSingle(emoji, _st.font->height));
QString url = qsl("emoji://e.") + QString::number(emojiKey(emoji), 16);
document()->addResource(QTextDocument::ImageResource, QUrl(url), QVariant(img));
QTextImageFormat imageFormat;
imageFormat.setWidth(img.width() / cIntRetinaFactor());
imageFormat.setHeight(img.height() / cIntRetinaFactor());
imageFormat.setName(url);
int32 ew = ESize + st::emojiPadding * cIntRetinaFactor() * 2, eh = _st.font->height * cIntRetinaFactor();
imageFormat.setWidth(ew / cIntRetinaFactor());
imageFormat.setHeight(eh / cIntRetinaFactor());
imageFormat.setName(qsl("emoji://e.") + QString::number(emojiKey(emoji), 16));
imageFormat.setVerticalAlignment(QTextCharFormat::AlignBaseline);
c.insertImage(imageFormat);
static QString objectReplacement(QChar::ObjectReplacementCharacter);
c.insertText(objectReplacement, imageFormat);
}
QVariant FlatTextarea::loadResource(int type, const QUrl &name) {
QString imageName = name.toDisplayString();
if (imageName.startsWith(qstr("emoji://e."))) {
if (EmojiPtr emoji = emojiFromUrl(imageName)) {
return QVariant(App::emojiSingle(emoji, _st.font->height));
}
}
return QVariant();
}
void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
@@ -579,6 +591,10 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
if (emoji) break;
}
if (emoji) {
if (!document()->pageSize().isNull()) {
document()->setPageSize(QSizeF(0, 0));
}
QTextCursor c(doc->docHandle(), emojiPosition);
c.setPosition(emojiPosition + emojiLen, QTextCursor::KeepAnchor);
int32 removedUpto = c.position();
@@ -608,6 +624,8 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
}
void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int charsAdded) {
if (_replacingEmojis) return;
if (!_links.isEmpty()) {
bool changed = false;
for (LinkRanges::iterator i = _links.begin(); i != _links.end();) {
@@ -624,7 +642,7 @@ void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int
if (changed) emit linksChanged();
}
if (_replacingEmojis || document()->availableRedoSteps() > 0) return;
if (document()->availableRedoSteps() > 0) return;
const int takeBack = 3;
@@ -636,7 +654,14 @@ void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int
}
if (charsAdded <= 0) return;
_insertions.push_back(Insertion(position, charsAdded));
// _insertions.push_back(Insertion(position, charsAdded));
_replacingEmojis = true;
QSizeF s = document()->pageSize();
processDocumentContentsChange(position, charsAdded);
if (document()->pageSize() != s) {
document()->setPageSize(s);
}
_replacingEmojis = false;
}
void FlatTextarea::onDocumentContentsChanged() {
@@ -647,6 +672,8 @@ void FlatTextarea::onDocumentContentsChanged() {
_insertions.clear();
} else {
_replacingEmojis = true;
QSizeF s = document()->pageSize();
do {
Insertion i = _insertions.front();
_insertions.pop_front();
@@ -654,6 +681,10 @@ void FlatTextarea::onDocumentContentsChanged() {
processDocumentContentsChange(i.first, i.second);
}
} while (!_insertions.isEmpty());
if (document()->pageSize() != s) {
document()->setPageSize(s);
}
_replacingEmojis = false;
}
}

View File

@@ -103,6 +103,8 @@ protected:
return QTextEdit::leaveEvent(e);
}
QVariant loadResource(int type, const QUrl &name);
private:
void getSingleEmojiFragment(QString &text, QTextFragment &fragment) const;

View File

@@ -26,8 +26,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include <QtGui/QCursor>
#include <QtGui/QFont>
inline QPoint rtlpoint(int x, int y, int outerw) {
return QPoint(rtl() ? (outerw - x) : x, y);
}
inline QPoint rtlpoint(const QPoint &p, int outerw) {
return rtl() ? QPoint(outerw - p.x(), p.y()) : p;
}
inline QRect rtlrect(int x, int y, int w, int h, int outerw) {
return rtl() ? QRect(outerw - x - w, y, w, h) : QRect(x, y, w, h);
return QRect(rtl() ? (outerw - x - w) : x, y, w, h);
}
inline QRect rtlrect(const QRect &r, int outerw) {
return rtl() ? QRect(outerw - r.x() - r.width(), r.y(), r.width(), r.height()) : r;
}
inline QRect centerrect(const QRect &inRect, const QRect &rect) {
return QRect(inRect.x() + (inRect.width() - rect.width()) / 2, inRect.y() + (inRect.height() - rect.height()) / 2, rect.width(), rect.height());

View File

@@ -24,7 +24,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
namespace {
const QRegularExpression _reDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)?((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){1,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
const QRegularExpression _reDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)?((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){1,10}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
const QRegularExpression _reExplicitDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){0,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
const QRegularExpression _reMailName(qsl("[a-zA-Z\\-_\\.0-9]{1,256}$"));
const QRegularExpression _reMailStart(qsl("^[a-zA-Z\\-_\\.0-9]{1,256}\\@"));
@@ -863,7 +863,7 @@ public:
}
void draw(int32 left, int32 top, int32 w, style::align align, int32 yFrom, int32 yTo, uint16 selectedFrom = 0, uint16 selectedTo = 0) {
if (_t->_blocks.isEmpty()) return;
if (_t->isEmpty()) return;
_blocksSize = _t->_blocks.size();
if (!_textStyle) _initDefault();
@@ -1043,7 +1043,7 @@ public:
}
void drawElided(int32 left, int32 top, int32 w, style::align align, int32 lines, int32 yFrom, int32 yTo, int32 removeFromEnd) {
if (lines <= 0) return;
if (lines <= 0 || _t->isNull()) return;
if (yTo < 0 || (lines - 1) * _t->_font->height < yTo) {
yTo = lines * _t->_font->height;
@@ -1057,7 +1057,7 @@ public:
_lnkX = x;
_lnkY = y;
_lnkResult = &_zeroLnk;
if (_lnkX >= 0 && _lnkX < w && _lnkY >= 0) {
if (!_t->isNull() && _lnkX >= 0 && _lnkX < w && _lnkY >= 0) {
draw(0, 0, w, align, _lnkY, _lnkY + 1);
}
return *_lnkResult;
@@ -1067,7 +1067,7 @@ public:
lnk = TextLinkPtr();
inText = false;
if (x >= 0 && x < w && y >= 0) {
if (!_t->isNull() && x >= 0 && x < w && y >= 0) {
_lnkX = x;
_lnkY = y;
_lnkResult = &lnk;
@@ -1081,8 +1081,7 @@ public:
symbol = 0;
after = false;
upon = false;
if (y >= 0) {
if (!_t->isNull() && y >= 0) {
_lnkX = x;
_lnkY = y;
_getSymbol = &symbol;
@@ -1615,25 +1614,36 @@ public:
}
}
style::font applyFlags(int32 flags, const style::font &f) {
style::font result = f;
if (flags & TextBlockBold) result = result->bold();
if (flags & TextBlockItalic) result = result->italic();
if (flags & TextBlockUnderline) result = result->underline();
return result;
}
void eSetFont(ITextBlock *block) {
style::font newFont = _t->_font;
int flags = block->flags();
if (!flags && block->lnkIndex()) {
if (flags) {
newFont = applyFlags(flags, _t->_font);
}
if (block->lnkIndex()) {
const TextLinkPtr &l(_t->_links.at(block->lnkIndex() - 1));
if (l == _overLnk) {
if (l == _downLnk || !_downLnk) {
flags = _textStyle->lnkOverFlags->flags();
if (_t->_font != _textStyle->lnkOverFlags) newFont = _textStyle->lnkOverFlags;
} else {
flags = _textStyle->lnkFlags->flags();
if (_t->_font != _textStyle->lnkFlags) newFont = _textStyle->lnkFlags;
}
} else {
flags = _textStyle->lnkFlags->flags();
if (_t->_font != _textStyle->lnkFlags) newFont = _textStyle->lnkFlags;
}
}
if (flags & TextBlockBold) newFont = newFont->bold();
if (flags & TextBlockItalic) newFont = newFont->italic();
if (flags & TextBlockUnderline) newFont = newFont->underline();
if (newFont != _f) {
if (newFont->family() == _t->_font->family()) {
newFont = applyFlags(flags | newFont->flags(), _t->_font);
}
_f = newFont;
_e->fnt = _f->f;
_e->resetFontEngineCache();

View File

@@ -259,13 +259,23 @@ public:
virtual QString encoded() const {
return QString();
}
virtual const QLatin1String &type() const = 0;
virtual ~ITextLink() {
}
};
#define TEXT_LINK_CLASS(ClassName) public: \
const QLatin1String &type() const { \
static const QLatin1String _type(qstr(#ClassName)); \
return _type; \
}
typedef QSharedPointer<ITextLink> TextLinkPtr;
class TextLink : public ITextLink {
TEXT_LINK_CLASS(TextLink)
public:
TextLink(const QString &url, bool fullDisplayed = true) : _url(url), _fullDisplayed(fullDisplayed) {
@@ -289,7 +299,7 @@ public:
QString encoded() const {
QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString());
QString result(good.isValid() ? good.toEncoded() : _url);
QString result(good.isValid() ? QString::fromUtf8(good.toEncoded()) : _url);
if (!QRegularExpression(qsl("^[a-zA-Z]+://")).match(result).hasMatch()) { // no protocol
return qsl("http://") + result;
@@ -305,6 +315,8 @@ private:
};
class EmailLink : public ITextLink {
TEXT_LINK_CLASS(EmailLink)
public:
EmailLink(const QString &email) : _email(email) {
@@ -335,6 +347,8 @@ private:
};
class MentionLink : public ITextLink {
TEXT_LINK_CLASS(MentionLink)
public:
MentionLink(const QString &tag) : _tag(tag) {
@@ -361,6 +375,8 @@ private:
};
class HashtagLink : public ITextLink {
TEXT_LINK_CLASS(HashtagLink)
public:
HashtagLink(const QString &tag) : _tag(tag) {
@@ -387,6 +403,8 @@ private:
};
class BotCommandLink : public ITextLink {
TEXT_LINK_CLASS(BotCommandLink)
public:
BotCommandLink(const QString &cmd) : _cmd(cmd) {
@@ -485,6 +503,9 @@ public:
bool isEmpty() const {
return _text.isEmpty();
}
bool isNull() const {
return !_font;
}
QString original(uint16 selectedFrom = 0, uint16 selectedTo = 0xFFFF, bool expandLinks = true) const;
bool lastDots(int32 dots, int32 maxdots = 3) { // hack for typing animation

View File

@@ -17,20 +17,6 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#pragma once
class Widget : public QWidget {
public:
Widget(QWidget *parent = 0) : QWidget(parent) {
}
void moveToLeft(int x, int y, int outerw) {
move(rtl() ? (outerw - x - width()) : x, y);
}
void moveToRight(int x, int y, int outerw) {
move(rtl() ? x : (outerw - x - width()), y);
}
};
namespace App {
const QPixmap &sprite();
}
@@ -119,14 +105,20 @@ public:
void drawSpriteCenter(const QRect &in, const style::sprite &sprite) {
return drawPixmap(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), App::sprite(), sprite);
}
void drawSpriteCenterLeft(const QRect &in, int outerw, const style::sprite &sprite) {
return drawPixmapLeft(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), outerw, App::sprite(), sprite);
}
void drawSpriteCenterRight(const QRect &in, int outerw, const style::sprite &sprite) {
return drawPixmapRight(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), outerw, App::sprite(), sprite);
}
};
class TWidget : public Widget {
class TWidget : public QWidget {
Q_OBJECT
public:
TWidget(QWidget *parent = 0) : Widget(parent) {
TWidget(QWidget *parent = 0) : QWidget(parent) {
}
TWidget *tparent() {
return qobject_cast<TWidget*>(parentWidget());
@@ -140,6 +132,27 @@ public:
virtual void enterFromChildEvent(QEvent *e) { // e -- from leaveEvent() of child TWidget
}
void moveToLeft(int x, int y, int outerw) {
move(rtl() ? (outerw - x - width()) : x, y);
}
void moveToRight(int x, int y, int outerw) {
move(rtl() ? x : (outerw - x - width()), y);
}
QPoint myrtlpoint(int x, int y) const {
return rtlpoint(x, y, width());
}
QPoint myrtlpoint(const QPoint p) const {
return rtlpoint(p, width());
}
QRect myrtlrect(int x, int y, int w, int h) const {
return rtlrect(x, y, w, h, width());
}
QRect myrtlrect(const QRect &r) {
return rtlrect(r, width());
}
void rtlupdate(const QRect &r) {
update(myrtlrect(r));
}
bool event(QEvent *e) {
return QWidget::event(e);
}
@@ -149,12 +162,12 @@ protected:
void enterEvent(QEvent *e) {
TWidget *p(tparent());
if (p) p->leaveToChildEvent(e);
return Widget::enterEvent(e);
return QWidget::enterEvent(e);
}
void leaveEvent(QEvent *e) {
TWidget *p(tparent());
if (p) p->enterFromChildEvent(e);
return Widget::leaveEvent(e);
return QWidget::leaveEvent(e);
}
private:

File diff suppressed because it is too large Load Diff

View File

@@ -106,6 +106,7 @@ enum MediaOverviewType {
OverviewVideos,
OverviewDocuments,
OverviewAudios,
OverviewAudioDocuments,
OverviewCount
};
@@ -127,6 +128,7 @@ inline MTPMessagesFilter typeToMediaFilter(MediaOverviewType &type) {
case OverviewVideos: return MTP_inputMessagesFilterVideo();
case OverviewDocuments: return MTP_inputMessagesFilterDocument();
case OverviewAudios: return MTP_inputMessagesFilterAudio();
case OverviewAudioDocuments: return MTP_inputMessagesFilterAudioDocuments();
default: type = OverviewCount; break;
}
return MTPMessagesFilter();
@@ -254,6 +256,7 @@ struct History : public QList<HistoryBlock*> {
bool lastKeyboardInited, lastKeyboardUsed;
MsgId lastKeyboardId;
PeerId lastKeyboardFrom;
void clearLastKeyboard();
mtpRequestId sendRequestId;
@@ -285,6 +288,8 @@ struct History : public QList<HistoryBlock*> {
MediaOverviewIds _overviewIds[OverviewCount];
int32 _overviewCount[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
void eraseFromOverview(MediaOverviewType type, MsgId msgId);
static const int32 ScrollMax = INT_MAX;
};
@@ -635,6 +640,12 @@ class HistoryReply; // dynamic_cast optimize
class HistoryMessage; // dynamic_cast optimize
class HistoryForwarded; // dynamic_cast optimize
enum HistoryCursorState {
HistoryDefaultCursorState,
HistoryInTextCursorState,
HistoryInDateCursorState
};
class HistoryMedia;
class HistoryItem : public HistoryElem {
public:
@@ -697,9 +708,9 @@ public:
virtual bool hasPoint(int32 x, int32 y) const {
return false;
}
virtual void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const {
virtual void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const {
lnk = TextLinkPtr();
inText = false;
state = HistoryDefaultCursorState;
}
virtual void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { // from text
upon = hasPoint(x, y);
@@ -717,8 +728,6 @@ public:
}
virtual void updateMedia(const MTPMessageMedia &media) {
}
virtual void updateStickerEmoji() {
}
virtual QString selectedText(uint32 selection) const {
return qsl("[-]");
@@ -787,6 +796,8 @@ protected:
};
class MessageLink : public ITextLink {
TEXT_LINK_CLASS(MessageLink)
public:
MessageLink(PeerId peer, MsgId msgid) : _peer(peer), _msgid(msgid) {
}
@@ -827,7 +838,7 @@ public:
w = qMin(width, _maxw);
return _height;
}
virtual void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const = 0;
virtual void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const = 0;
virtual void draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width = -1) const = 0;
virtual bool uploading() const {
return false;
@@ -847,10 +858,6 @@ public:
return false;
}
virtual bool updateStickerEmoji() {
return false;
}
virtual bool animating() const {
return false;
}
@@ -890,7 +897,7 @@ public:
const QString inHistoryText() const;
const Text &captionForClone() const;
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
HistoryMedia *clone() const;
PhotoData *photo() const {
@@ -922,6 +929,7 @@ private:
};
QString formatSizeText(qint64 size);
QString formatDownloadText(qint64 ready, qint64 total);
QString formatDurationText(qint64 duration);
class HistoryVideo : public HistoryMedia {
@@ -938,7 +946,8 @@ public:
const QString inDialogsText() const;
const QString inHistoryText() const;
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
int32 countHeight(const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
bool uploading() const {
return (data->status == FileUploading);
}
@@ -978,7 +987,7 @@ public:
const QString inDialogsText() const;
const QString inHistoryText() const;
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
bool uploading() const {
return (data->status == FileUploading);
}
@@ -1021,7 +1030,7 @@ public:
bool uploading() const {
return (data->status == FileUploading);
}
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
HistoryMedia *clone() const;
DocumentData *document() {
@@ -1038,6 +1047,9 @@ public:
}
ImagePtr replyPreview();
void drawInPlaylist(QPainter &p, const HistoryItem *parent, bool selected, bool over, int32 width) const;
TextLinkPtr linkInPlaylist();
private:
DocumentData *data;
@@ -1066,7 +1078,7 @@ public:
const QString inHistoryText() const;
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
int32 countHeight(const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
HistoryMedia *clone() const;
DocumentData *document() {
@@ -1077,7 +1089,6 @@ public:
void unregItem(HistoryItem *item);
void updateFrom(const MTPMessageMedia &media);
bool updateStickerEmoji();
private:
@@ -1101,7 +1112,7 @@ public:
const QString inDialogsText() const;
const QString inHistoryText() const;
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width) const;
HistoryMedia *clone() const;
void updateFrom(const MTPMessageMedia &media);
@@ -1131,7 +1142,7 @@ public:
const QString inDialogsText() const;
const QString inHistoryText() const;
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
HistoryMedia *clone() const;
void regItem(HistoryItem *item);
@@ -1224,7 +1235,7 @@ public:
const QString inDialogsText() const;
const QString inHistoryText() const;
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
HistoryMedia *clone() const;
bool isImageLink() const {
@@ -1266,8 +1277,8 @@ public:
int32 resize(int32 width, bool dontRecountText = false, const HistoryItem *parent = 0);
bool hasPoint(int32 x, int32 y) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const;
virtual void getStateFromMessageText(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const QRect &r) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const;
virtual void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const;
uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const {
@@ -1283,7 +1294,6 @@ public:
_media->updateFrom(media);
}
}
void updateStickerEmoji();
QString selectedText(uint32 selection) const;
QString inDialogsText() const;
@@ -1342,9 +1352,9 @@ public:
void drawMessageText(QPainter &p, const QRect &trect, uint32 selection) const;
int32 resize(int32 width, bool dontRecountText = false, const HistoryItem *parent = 0);
bool hasPoint(int32 x, int32 y) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const;
void getStateFromMessageText(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const QRect &r) const;
void getForwardedState(TextLinkPtr &lnk, bool &inText, int32 x, int32 w) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const;
void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const;
void getForwardedState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 w) const;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const;
QDateTime dateForwarded() const {
@@ -1395,8 +1405,8 @@ public:
void drawMessageText(QPainter &p, const QRect &trect, uint32 selection) const;
int32 resize(int32 width, bool dontRecountText = false, const HistoryItem *parent = 0);
bool hasPoint(int32 x, int32 y) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const;
void getStateFromMessageText(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const QRect &r) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const;
void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const;
UserData *replyTo() const {
@@ -1436,7 +1446,7 @@ public:
void draw(QPainter &p, uint32 selection) const;
int32 resize(int32 width, bool dontRecountText = false, const HistoryItem *parent = 0);
bool hasPoint(int32 x, int32 y) const;
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const;
uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const {
return _text.adjustSelection(from, to, type);
@@ -1477,9 +1487,9 @@ class HistoryDateMsg : public HistoryServiceMsg {
public:
HistoryDateMsg(History *history, HistoryBlock *block, const QDate &date);
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const {
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const {
lnk = TextLinkPtr();
inText = false;
state = HistoryDefaultCursorState;
}
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const {
symbol = 0xFFFF;

File diff suppressed because it is too large Load Diff

View File

@@ -81,6 +81,8 @@ public:
void updateBotInfo(bool recount = true);
bool wasSelectedText() const;
~HistoryList();
public slots:
@@ -104,6 +106,7 @@ public slots:
void onMenuDestroy(QObject *obj);
void onTouchSelect();
void onTouchScrollTimer();
void onDragExec();
private:
@@ -115,7 +118,6 @@ private:
HistoryItem *prevItem(HistoryItem *item);
HistoryItem *nextItem(HistoryItem *item);
void updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting, bool force = false);
void applyDragSelection();
History *hist;
@@ -133,6 +135,9 @@ private:
Qt::CursorShape _cursor;
typedef QMap<HistoryItem*, uint32> SelectedItems;
SelectedItems _selected;
void applyDragSelection();
void applyDragSelection(SelectedItems *toItems) const;
enum DragAction {
NoDrag = 0x00,
PrepareDrag = 0x01,
@@ -144,6 +149,7 @@ private:
TextSelectType _dragSelType;
QPoint _dragStartPos, _dragPos;
HistoryItem *_dragItem;
HistoryCursorState _dragCursorState;
uint16 _dragSymbol;
bool _dragWasInactive;
@@ -154,6 +160,7 @@ private:
HistoryItem *_dragSelFrom, *_dragSelTo;
bool _dragSelecting;
bool _wasSelectedText; // was some text selected in current drag action
bool _touchScroll, _touchSelect, _touchInProgress;
QPoint _touchStart, _touchPrevPos, _touchPos;
@@ -409,6 +416,7 @@ public:
void animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false);
bool showStep(float64 ms);
void animStop();
void doneShow();
QPoint clampMousePosition(QPoint point);
@@ -460,6 +468,8 @@ public:
bool eventFilter(QObject *obj, QEvent *e);
void updateBotKeyboard();
DragState getDragState(const QMimeData *d);
~HistoryWidget();
signals:
@@ -502,10 +512,12 @@ public slots:
void onPhotoSelect();
void onDocumentSelect();
void onPhotoDrop(QDropEvent *e);
void onDocumentDrop(QDropEvent *e);
void onPhotoDrop(const QMimeData *data);
void onDocumentDrop(const QMimeData *data);
void onFilesDrop(const QMimeData *data);
void onKbToggle(bool manual = true);
void onCmdStart();
void onPhotoReady();
void onSendConfirmed();
@@ -514,8 +526,10 @@ public slots:
void showPeer(const PeerId &peer, MsgId msgId = 0, bool force = false, bool leaveActive = false);
void clearLoadingAround();
void activate();
void onMentionHashtagOrBotCommandInsert(QString str);
void onTextChange();
void onFieldTabbed();
void onStickerSend(DocumentData *sticker);
void onVisibleChanged();
@@ -541,6 +555,7 @@ public slots:
void onDraftSave(bool delayed = false);
void updateStickers();
void botCommandsChanged(UserData *user);
void onRecordError();
void onRecordDone(QByteArray result, qint32 samples);
@@ -591,7 +606,6 @@ private:
void setFieldText(const QString &text);
QStringList getMediasFromMime(const QMimeData *d);
DragState getDragState(const QMimeData *d);
void updateDragAreas();
@@ -616,9 +630,11 @@ private:
MentionsDropdown _attachMention;
bool isBotStart() const;
bool updateCmdStartShown();
FlatButton _send, _botStart;
IconedButton _attachDocument, _attachPhoto, _attachEmoji, _kbShow, _kbHide;
IconedButton _attachDocument, _attachPhoto, _attachEmoji, _kbShow, _kbHide, _cmdStart;
bool _cmdStartShown;
MessageField _field;
Animation _recordAnim, _recordingAnim;
bool _recording, _inRecord, _inField, _inReply;

View File

@@ -26,6 +26,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
namespace {
class SignUpLink : public ITextLink {
TEXT_LINK_CLASS(SignUpLink)
public:
SignUpLink(IntroPhone *widget) : _widget(widget) {

View File

@@ -71,28 +71,28 @@ void LangLoader::foundKeyValue(LangKey key) {
}
QString Translator::translate(const char *context, const char *sourceText, const char *disambiguation, int n) const {
if (QLatin1String("QMenuBar") == context) {
if (QLatin1String("Services") == sourceText) return lang(lng_mac_menu_services);
if (QLatin1String("Hide %1") == sourceText) return lng_mac_menu_hide_telegram(lt_telegram, qsl("%1"));
if (QLatin1String("Hide Others") == sourceText) return lang(lng_mac_menu_hide_others);
if (QLatin1String("Show All") == sourceText) return lang(lng_mac_menu_show_all);
if (QLatin1String("Preferences...") == sourceText) return lang(lng_mac_menu_preferences);
if (QLatin1String("Quit %1") == sourceText) return lng_mac_menu_quit_telegram(lt_telegram, qsl("%1"));
if (QLatin1String("About %1") == sourceText) return lng_mac_menu_about_telegram(lt_telegram, qsl("%1"));
if (qstr("QMenuBar") == context) {
if (qstr("Services") == sourceText) return lang(lng_mac_menu_services);
if (qstr("Hide %1") == sourceText) return lng_mac_menu_hide_telegram(lt_telegram, qsl("%1"));
if (qstr("Hide Others") == sourceText) return lang(lng_mac_menu_hide_others);
if (qstr("Show All") == sourceText) return lang(lng_mac_menu_show_all);
if (qstr("Preferences...") == sourceText) return lang(lng_mac_menu_preferences);
if (qstr("Quit %1") == sourceText) return lng_mac_menu_quit_telegram(lt_telegram, qsl("%1"));
if (qstr("About %1") == sourceText) return lng_mac_menu_about_telegram(lt_telegram, qsl("%1"));
return QString();
}
if (QLatin1String("QWidgetTextControl") == context || QLatin1String("QLineEdit") == context) {
if (QLatin1String("&Undo") == sourceText) return lang((cPlatform() == dbipWindows) ? lng_wnd_menu_undo : ((cPlatform() == dbipMac) ? lng_mac_menu_undo : lng_linux_menu_undo));
if (QLatin1String("&Redo") == sourceText) return lang((cPlatform() == dbipWindows) ? lng_wnd_menu_redo : ((cPlatform() == dbipMac) ? lng_mac_menu_redo : lng_linux_menu_redo));
if (QLatin1String("Cu&t") == sourceText) return lang(lng_mac_menu_cut);
if (QLatin1String("&Copy") == sourceText) return lang(lng_mac_menu_copy);
if (QLatin1String("&Paste") == sourceText) return lang(lng_mac_menu_paste);
if (QLatin1String("Delete") == sourceText) return lang(lng_mac_menu_delete);
if (QLatin1String("Select All") == sourceText) return lang(lng_mac_menu_select_all);
if (qstr("QWidgetTextControl") == context || qstr("QLineEdit") == context) {
if (qstr("&Undo") == sourceText) return lang((cPlatform() == dbipWindows) ? lng_wnd_menu_undo : ((cPlatform() == dbipMac) ? lng_mac_menu_undo : lng_linux_menu_undo));
if (qstr("&Redo") == sourceText) return lang((cPlatform() == dbipWindows) ? lng_wnd_menu_redo : ((cPlatform() == dbipMac) ? lng_mac_menu_redo : lng_linux_menu_redo));
if (qstr("Cu&t") == sourceText) return lang(lng_mac_menu_cut);
if (qstr("&Copy") == sourceText) return lang(lng_mac_menu_copy);
if (qstr("&Paste") == sourceText) return lang(lng_mac_menu_paste);
if (qstr("Delete") == sourceText) return lang(lng_mac_menu_delete);
if (qstr("Select All") == sourceText) return lang(lng_mac_menu_select_all);
return QString();
}
if (QLatin1String("QUnicodeControlCharacterMenu") == context) {
if (QLatin1String("Insert Unicode control character") == sourceText) return lang(lng_menu_insert_unicode);
if (qstr("QUnicodeControlCharacterMenu") == context) {
if (qstr("Insert Unicode control character") == sourceText) return lang(lng_menu_insert_unicode);
return QString();
}
return QString();

View File

@@ -166,11 +166,11 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_username_title" = "Benutzernamen ändern";
"lng_username_about" = "Wähle einen (optionalen) öffentlichen \nBenutzernamen, wenn du von anderen \ngefunden werden willst, ohne, dass sie \ndeine Nummer kennen müssen.\n\nErlaubt sind a-z, 0-9 und Unterstriche. \nDie Mindestlänge beträgt 5 Zeichen.";
"lng_username_invalid" = "Der Benutzername ist fehlerhaft.";
"lng_username_occupied" = "Der Benutzername ist bereits belegt.";
"lng_username_too_short" = "Der Benutzername ist zu kurz.";
"lng_username_bad_symbols" = "Nur a-z, 0-9 und Unterstriche sind erlaubt.";
"lng_username_available" = "Der Benutzername ist noch verfügbar.";
"lng_username_invalid" = "Benutzername ungültig.";
"lng_username_occupied" = "Benutzername ist bereits belegt.";
"lng_username_too_short" = "Benutzername ist zu kurz.";
"lng_username_bad_symbols" = "Ungültige Zeichen im Benutzernamen.";
"lng_username_available" = "Benutzername ist verfügbar.";
"lng_username_not_found" = "Kontakt @{user} konnte nicht gefunden werden.";
"lng_settings_section_contact_info" = "Kontaktprofil";
@@ -301,13 +301,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_connection_type" = "Verbindungsart:";
"lng_connection_auto_connecting" = "Standard (verbinden..)";
"lng_connection_auto" = "Standard ({type} verwendet)";
"lng_connection_http_proxy" = "HTTP mit Proxy";
"lng_connection_tcp_proxy" = "TCP mit Proxy";
"lng_connection_auto" = "Standard ({transport} verwendet)";
"lng_connection_proxy_connecting" = "Verbinde über Proxy...";
"lng_connection_proxy" = "{transport} mit Proxy";
"lng_connection_header" = "Verbindungsart";
"lng_connection_auto_rb" = "Auto (TCP wenn verfügbar oder HTTP)";
"lng_connection_http_proxy_rb" = "HTTP mit benutzerdef. http-Proxy";
"lng_connection_tcp_proxy_rb" = "TCP mit benutzerdef. socks5-Proxy";
"lng_connection_try_ipv6" = "Über IPv6 verbinden";
"lng_connection_host_ph" = "Hostname";
"lng_connection_port_ph" = "Port";
"lng_connection_user_ph" = "Benutzername";
@@ -367,6 +368,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_files_header" = "Dateiübersicht";
"lng_profile_audios" = "{count:_not_used_|# Sprachnachricht|# Sprachnachrichten} »";
"lng_profile_audios_header" = "Übersicht Sprachnachrichten";
"lng_profile_audio_files_header" = "Wiedergabeliste";
"lng_profile_show_all_types" = "Alle Filter anzeigen";
"lng_profile_copy_phone" = "Telefonnummer kopieren";
@@ -572,7 +574,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_selected_delete_confirm" = "Löschen";
"lng_about_version" = "Version {version}";
"lng_about_text" = "Telegram Desktop basiert auf [a href=\"https://core.telegram.org/mtproto\"]MTProto[/a] und\ndem [a href=\"https://core.telegram.org/api\"]Telegram API[/a], um Geschwindigkeit \nund Sicherheit zu gewährleisten.\n\nSoftware steht unter der [a href=\"https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\"]GNU GPL[/a] Version 3,\nQuelltext ist bei [a href=\"https://github.com/telegramdesktop/tdesktop\"]GitHub[/a] verfügbar.";
"lng_about_text" = "Telegram Desktop basiert auf [a href=\"https://core.telegram.org/mtproto\"]MTProto[/a] und\nder [a href=\"https://core.telegram.org/api\"]Telegram API[/a], um Geschwindigkeit \nund Sicherheit zu gewährleisten.\n\nSoftware steht unter der [a href=\"https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\"]GNU GPL[/a] Version 3,\nQuelltext ist bei [a href=\"https://github.com/telegramdesktop/tdesktop\"]GitHub[/a] verfügbar.";
"lng_about_done" = "Fertig";
"lng_search_found_results" = "{count:Keine Nachrichten|# Nachricht|# Nachrichten}";
@@ -601,7 +603,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_new_version_wrap" = "Telegram Desktop wurde aktualisiert auf Version {version}\n\n{changes}\n\nGesamter Versionsverlauf:\n{link}";
"lng_new_version_minor" = "— Fehlerbehebungen und Softwareoptimierungen";
"lng_new_version_text" = "Diese neue Version enthält Unterstützung für die neue Bot API, welche für alle kostenlos verfügbar ist. Kannst du programmieren? Erstelle deine eigenen Bots für Spiele, Dienste oder Integrationen.\n\nMehr dazu unter {blog_link}";
"lng_new_version_text" = "— In-App Medienwiedergabe optimiert\n— Fehlerbehebungen und kleinere Verbesserungen";
"lng_menu_insert_unicode" = "Unicode-Steuerzeichen einfügen";

View File

@@ -301,13 +301,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_connection_type" = "Tipo de conexión:";
"lng_connection_auto_connecting" = "Por defecto (conectando...)";
"lng_connection_auto" = "Por defecto ({type} en uso)";
"lng_connection_http_proxy" = "HTTP con proxy";
"lng_connection_tcp_proxy" = "TCP con proxy";
"lng_connection_auto" = "Por defecto ({transport} en uso)";
"lng_connection_proxy_connecting" = "Conectando a través de un proxy...";
"lng_connection_proxy" = "{transport} con un proxy";
"lng_connection_header" = "Tipo de conexión";
"lng_connection_auto_rb" = "Automático (TCP si está disponible o HTTP)";
"lng_connection_http_proxy_rb" = "HTTP con http-proxy personalizado";
"lng_connection_tcp_proxy_rb" = "TCP con socks5-proxy personalizado";
"lng_connection_try_ipv6" = "Intentar conectar a través de IPv6";
"lng_connection_host_ph" = "Nombre del host";
"lng_connection_port_ph" = "Puerto";
"lng_connection_user_ph" = "Alias";
@@ -362,11 +363,12 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_photos" = "{count:_not_used_|# foto|# fotos} »";
"lng_profile_photos_header" = "Todas las fotos";
"lng_profile_videos" = "{count:_not_used_|# vídeo|# vídeos} »";
"lng_profile_videos_header" = "Todos los vídeos";
"lng_profile_videos_header" = "Vídeos";
"lng_profile_files" = "{count:_not_used_|# archivo|# archivos} »";
"lng_profile_files_header" = "Todos los archivos";
"lng_profile_files_header" = "Archivos";
"lng_profile_audios" = "{count:_not_used_|# mensaje de voz|# mensajes de voz} »";
"lng_profile_audios_header" = "Todos los mensajes de voz";
"lng_profile_audios_header" = "Mensajes de voz";
"lng_profile_audio_files_header" = "Lista de reproducción";
"lng_profile_show_all_types" = "Mostrar todos los tipos";
"lng_profile_copy_phone" = "Copiar número";
@@ -464,7 +466,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_from_you" = "Tú";
"lng_bot_description" = "¿Qué puede hacer este bot?";
"lng_bot_start" = "Empezar";
"lng_bot_start" = "Iniciar";
"lng_bot_choose_group" = "Elegir grupo";
"lng_bot_no_groups" = "No tienes grupos";
"lng_bot_groups_not_found" = "No se encontraron grupos";
@@ -601,7 +603,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_new_version_wrap" = "Telegram Desktop fue actualizada a la versión {version}\n\n{changes}\n\nEl historial completo está disponible aquí:\n{link}";
"lng_new_version_minor" = "— Corrección de errores y otras mejoras menores";
"lng_new_version_text" = "Esta nueva versión incluye el soporte para bots, usando la nueva API para bots, gratis para todos. Si eres un ingeniero, crea tus propios bots para juegos, servicios o integraciones .\n\nConoce más en {blog_link}";
"lng_new_version_text" = "— Reproducción de la multimedia dentro de la aplicación mejorada\n— Corrección de errores y otras mejoras menores";
"lng_menu_insert_unicode" = "Insertar caracteres de control Unicode";

View File

@@ -166,11 +166,11 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_username_title" = "Cambia username";
"lng_username_about" = "Puoi scegliere un username su Telegram.\nSe lo fai, le altre persone potranno trovarti\ntramite questo nome utente e contattarti \nsenza conoscere il tuo numero di telefono.\n\nPuoi usare a-z, 0-9 e underscore.\nLa lunghezza minima è di 5 caratteri.";
"lng_username_invalid" = "Il nome non è valido.";
"lng_username_occupied" = "Il nome è già occupato.";
"lng_username_too_short" = "Il nome è troppo corto.";
"lng_username_bad_symbols" = "Questo nome ha simboli errati.";
"lng_username_available" = "Il nome è disponibile.";
"lng_username_invalid" = "L'username non è valido.";
"lng_username_occupied" = "L'username è già occupato.";
"lng_username_too_short" = "L'username è troppo corto.";
"lng_username_bad_symbols" = "Questo username ha simboli errati.";
"lng_username_available" = "L'username è disponibile.";
"lng_username_not_found" = "Utente @{user} non trovato.";
"lng_settings_section_contact_info" = "Informazioni di contatto";
@@ -301,13 +301,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_connection_type" = "Tipo di connessione:";
"lng_connection_auto_connecting" = "Default (connessione..)";
"lng_connection_auto" = "Default ({type} in uso)";
"lng_connection_http_proxy" = "HTTP con proxy";
"lng_connection_tcp_proxy" = "TCP con proxy";
"lng_connection_auto" = "Predefinito ({transport} in uso)";
"lng_connection_proxy_connecting" = "Connessione tramite proxy..";
"lng_connection_proxy" = "{transport} con proxy";
"lng_connection_header" = "Tipo di connessione";
"lng_connection_auto_rb" = "Auto (TCP se disponibile o HTTP)";
"lng_connection_http_proxy_rb" = "HTTP con proxy-http personalizzato";
"lng_connection_tcp_proxy_rb" = "TCP con proxy-socks5 personalizzato";
"lng_connection_try_ipv6" = "Prova a connettere tramite IPv6";
"lng_connection_host_ph" = "Hostname";
"lng_connection_port_ph" = "Porta";
"lng_connection_user_ph" = "Username";
@@ -367,6 +368,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_files_header" = "Panoramica file";
"lng_profile_audios" = "{count:_not_used_|# nota vocale|# note vocali} »";
"lng_profile_audios_header" = "Panoramica note vocali";
"lng_profile_audio_files_header" = "Playlist";
"lng_profile_show_all_types" = "Mostra tutti i tipi";
"lng_profile_copy_phone" = "Copia numero di telefono";
@@ -601,7 +603,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_new_version_wrap" = "Telegram Desktop si è aggiornato alla versione {version}\n\n{changes}\n\nLa cronologia degli update è disponibile qui:\n{link}";
"lng_new_version_minor" = "— Bug fix e altri miglioramenti minori";
"lng_new_version_text" = "Questa nuova versione include il support per i bot usando la nuova API per i bot. Se sei un ingegnere, crea i tuoi bot per giochi, servizi o integrazioni. Scopri di più su {blog_link}";
"lng_new_version_text" = "— Riproduzione dei media migliorata\n— Risoluzione di bug e miglioramenti minori";
"lng_menu_insert_unicode" = "Inserisci carattere di controllo Unicode";

View File

@@ -169,7 +169,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_username_invalid" = "올바르지 않은 아이디입니다.";
"lng_username_occupied" = "사용중인 아이디입니다.";
"lng_username_too_short" = "아이디가 너무 짧습니다.";
"lng_username_bad_symbols" = "올바르지 않은 아이디입니다.";
"lng_username_bad_symbols" = "아이디에 올바르지 않은 문자가 있습니다.";
"lng_username_available" = "사용 가능한 아이디입니다.";
"lng_username_not_found" = "아이디 @{user}를 찾을 수 없습니다.";
@@ -301,13 +301,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_connection_type" = "연결 유형:";
"lng_connection_auto_connecting" = "기본값 (연결중..)";
"lng_connection_auto" = "기본값 ({type} 사용)";
"lng_connection_http_proxy" = "HTTP 프록시";
"lng_connection_tcp_proxy" = "TCP 프록시";
"lng_connection_auto" = "기본값 ({transport} 사용)";
"lng_connection_proxy_connecting" = "프록시 연결 중...";
"lng_connection_proxy" = "{transport} 프록시 연결";
"lng_connection_header" = "연결 유형";
"lng_connection_auto_rb" = "자동 (사용 가능하다면 TCP 아니면 HTTP 사용)";
"lng_connection_http_proxy_rb" = "HTTP (커스텀 HTTP 프록시)";
"lng_connection_tcp_proxy_rb" = "TCP (커스텀 socks5-proxy)";
"lng_connection_try_ipv6" = "IPv6로 연결 시도 중";
"lng_connection_host_ph" = "호스트네임";
"lng_connection_port_ph" = "포트";
"lng_connection_user_ph" = "아이디";
@@ -367,6 +368,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_files_header" = "파일 내역";
"lng_profile_audios" = "{count:_not_used_|#개의 음성 메시지|#개의 음성 메시지} »";
"lng_profile_audios_header" = "음성 메시지 내역";
"lng_profile_audio_files_header" = "재생목록";
"lng_profile_show_all_types" = "모든 유형 보기";
"lng_profile_copy_phone" = "전화번호 복사";
@@ -601,7 +603,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_new_version_wrap" = "텔레그램 데스크탑은 {version} 버전으로 업데이트 되었습니다.\n\n{changes}\n\n전체 버전 히스토리는 아래에서 확인 가능합니다:\n{link}";
"lng_new_version_minor" = "— 버그 수정 및 일부 기능 향상";
"lng_new_version_text" = "새로운 버전에서는 신규 봇 API를 무료로 공개합니다. 개발자라면 누구나 게임, 서비스나 통합 봇등 개발이 가능합니다. \n\n{blog_link}에서 자세한 사항을 알아보세요.";
"lng_new_version_text" = "— 앱내 미디어 재생 기능 향상\n— 버그 수정 및 마이나 기능 향상";
"lng_menu_insert_unicode" = "유니코드 문자를 입력하세요.";

View File

@@ -166,11 +166,11 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_username_title" = "Gebruikersnaam wijzigen";
"lng_username_about" = "Je kunt hier je gebruikersnaam kiezen. \nHiermee kunnen anderen je vinden \nen contact met je opnemen zonder \nje telefoonnummer te weten.\n\na-z, 0-9 en underscore is toegestaan. \nDe minimale lengte is 5 tekens.";
"lng_username_invalid" = "Deze naam is ongeldig.";
"lng_username_occupied" = "Sorry, deze gebruikersnaam is al bezet.";
"lng_username_too_short" = "Deze naam is te kort.";
"lng_username_bad_symbols" = "Sorry, deze naam bevat ongeldige tekens.";
"lng_username_available" = "Deze naam is beschikbaar.";
"lng_username_invalid" = "Deze gebruikersnaam is ongeldig.";
"lng_username_occupied" = "Deze gebruikersnaam is al bezet";
"lng_username_too_short" = "Deze gebruikersnaam is te kort.";
"lng_username_bad_symbols" = "Deze gebruikersnaam bevat ongeldige tekens.";
"lng_username_available" = "Deze gebruikersnaam is beschikbaar.";
"lng_username_not_found" = "Gebruiker @{user} niet gevonden.";
"lng_settings_section_contact_info" = "Contactgegevens";
@@ -301,13 +301,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_connection_type" = "Verbindingstype:";
"lng_connection_auto_connecting" = "Standaard (verbinden)";
"lng_connection_auto" = "Standaard ({type} wordt gebruikt)";
"lng_connection_http_proxy" = "HTTP met proxy";
"lng_connection_tcp_proxy" = "TCP met proxy";
"lng_connection_auto" = "Standaard ({transport} wordt gebruikt)";
"lng_connection_proxy_connecting" = "Verbinden via proxy..";
"lng_connection_proxy" = "{transport} met proxy";
"lng_connection_header" = "Verbindingstype";
"lng_connection_auto_rb" = "Auto (TCP indien beschikbaar of HTTP)";
"lng_connection_http_proxy_rb" = "HTTP met aangepaste http-proxy";
"lng_connection_tcp_proxy_rb" = "TCP met aangepaste socks5-proxy";
"lng_connection_try_ipv6" = "Verbinden via IPV6";
"lng_connection_host_ph" = "Hostnaam";
"lng_connection_port_ph" = "Poort";
"lng_connection_user_ph" = "Gebruikersnaam";
@@ -367,6 +368,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_files_header" = "Bestandsoverzicht";
"lng_profile_audios" = "{count:_not_used_|# spraakbericht|# spraakberichten} »";
"lng_profile_audios_header" = "Overzicht van spraakberichten";
"lng_profile_audio_files_header" = "Afspeellijst";
"lng_profile_show_all_types" = "Alles weergeven";
"lng_profile_copy_phone" = "Telefoonnummer kopiëren";
@@ -601,7 +603,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_new_version_wrap" = "Telegram is bijgewerkt naar versie {version}\n\n{changes} \n\nVolledige versiegeschiedenis is hier te vinden:\n{link}";
"lng_new_version_minor" = "— Probleemoplossing en andere kleine verbeteringen";
"lng_new_version_text" = "Deze versie heeft ondersteuning voor de nieuwe bot-API, gratis voor iedereen. Handig met programmeren? Maak dan je eigen bots voor spelletjes, diensten en integraties. \n\nMeer weten? kijk op: {blog_link}";
"lng_new_version_text" = "— Media afspelen binnen de app verbeterd\n— Probleemoplossing en kleine verbeteringen";
"lng_menu_insert_unicode" = "Unicode-besturingsteken invoegen";

View File

@@ -166,11 +166,11 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_username_title" = "Alterar nome de usuário";
"lng_username_about" = "Você pode escolher um nome de usuário no Telegram.\nAssim, outras pessoas poderão te encontrar\npelo nome de usuário e entrar em contato\nsem precisar saber seu telefone.\n\nVocê pode usar a-z, 0-9 e underline.\nO tamanho mínimo é 5 caracteres.";
"lng_username_invalid" = "Esse nome é inválido.";
"lng_username_occupied" = "Esse nome já está ocupado.";
"lng_username_too_short" = "Esse nome é muito curto.";
"lng_username_bad_symbols" = "Esse nome contém símbolos incompatíveis.";
"lng_username_available" = "Esse nome está disponível.";
"lng_username_invalid" = "Nome de usuário inválido.";
"lng_username_occupied" = "Nome de usuário ocupado.";
"lng_username_too_short" = "Nome de usuário muito curto.";
"lng_username_bad_symbols" = "Nome de usuário com símbolos incompatíveis.";
"lng_username_available" = "Nome de usuário disponível.";
"lng_username_not_found" = "Usuário @{user} não encontrado.";
"lng_settings_section_contact_info" = "Informação de contato";
@@ -301,13 +301,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_connection_type" = "Tipo de conexão:";
"lng_connection_auto_connecting" = "Padrão (conectando..)";
"lng_connection_auto" = "Padrão ({type} usado)";
"lng_connection_http_proxy" = "HTTP com proxy";
"lng_connection_tcp_proxy" = "TCP com proxy";
"lng_connection_auto" = "Padrão ({transport} usado)";
"lng_connection_proxy_connecting" = "Conectando via proxy...";
"lng_connection_proxy" = "{transport} com proxy";
"lng_connection_header" = "Tipo de conexão";
"lng_connection_auto_rb" = "Auto (TCP se disponível ou HTTP)";
"lng_connection_http_proxy_rb" = "HTTP com http-proxy customizado";
"lng_connection_tcp_proxy_rb" = "TCP com socks5-proxy customizado";
"lng_connection_try_ipv6" = "Tentando conexão via IPv6";
"lng_connection_host_ph" = "Nome do host";
"lng_connection_port_ph" = "Porta";
"lng_connection_user_ph" = "Nome de usuário";
@@ -360,13 +361,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_shared_media" = "Mídia compartilhada";
"lng_profile_no_media" = "Nenhuma mídia nessa conversa.";
"lng_profile_photos" = "{count:_not_used_|# foto|# fotos} »";
"lng_profile_photos_header" = "Visualização de fotos";
"lng_profile_photos_header" = "Fotos";
"lng_profile_videos" = "{count:_not_used_|# arquivo de vídeo|# arquivo de vídeos} »";
"lng_profile_videos_header" = "Visualização de vídeos";
"lng_profile_videos_header" = "Vídeos";
"lng_profile_files" = "{count:_not_used_|# arquivo|# arquivos} »";
"lng_profile_files_header" = "Visualização de arquivos";
"lng_profile_files_header" = "Arquivos";
"lng_profile_audios" = "{count:_not_used_|# mensagem de voz|# mensagens de voz} »";
"lng_profile_audios_header" = "Visualização de mensagens de voz";
"lng_profile_audios_header" = "Mensagens de voz";
"lng_profile_audio_files_header" = "Reprodução";
"lng_profile_show_all_types" = "Mostrar todos os tipos";
"lng_profile_copy_phone" = "Copiar número de telefone";
@@ -601,7 +603,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_new_version_wrap" = "Telegram Desktop foi atualizado para a versão {version}\n\n{changes}\n\nHistórico completo de mudanças disponível aqui:\n{link}";
"lng_new_version_minor" = "— Resolução de bugs e outras menores melhorias";
"lng_new_version_text" = "Essa nova versão inclui suporte para bots usando a nova API de bots. Se você for um engenheiro, crie seus próprios bots para jogos, serviços ou integrações.\n\nLeia mais em {blog_link}";
"lng_new_version_text" = "— Reprodução de mídia no app melhorada\n— Resolução de bugs e menores melhorias";
"lng_menu_insert_unicode" = "Inserir caractere de controle Unicode";

View File

@@ -18,6 +18,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "stdafx.h"
#include "localimageloader.h"
#include "gui/filedialog.h"
#include "audio.h"
#include <libexif/exif-data.h>
LocalImageLoaderPrivate::LocalImageLoaderPrivate(int32 currentUser, LocalImageLoader *loader, QThread *thread) : QObject(0)
@@ -164,7 +165,40 @@ void LocalImageLoaderPrivate::prepareImages() {
MTPDocument document(MTP_documentEmpty(MTP_long(0)));
MTPAudio audio(MTP_audioEmpty(MTP_long(0)));
bool isSong = false;
QByteArray jpeg;
if (type == ToPrepareDocument) {
if (mime == qstr("audio/mp3") || mime == qstr("audio/m4a") || mime == qstr("audio/aac") || mime == qstr("audio/ogg") ||
filename.endsWith(qstr(".mp3"), Qt::CaseInsensitive) || filename.endsWith(qstr(".m4a"), Qt::CaseInsensitive) ||
filename.endsWith(qstr(".aac"), Qt::CaseInsensitive) || filename.endsWith(qstr(".ogg"), Qt::CaseInsensitive)) {
QImage cover;
QByteArray coverBytes, coverFormat;
MTPDocumentAttribute audioAttribute = audioReadSongAttributes(file, data, cover, coverBytes, coverFormat);
if (audioAttribute.type() == mtpc_documentAttributeAudio) {
attributes.push_back(audioAttribute);
isSong = true;
if (!cover.isNull()) { // cover to thumb
int32 cw = cover.width(), ch = cover.height();
if (cw < 20 * ch && ch < 20 * cw) {
QPixmap full = (cw > 90 || ch > 90) ? QPixmap::fromImage(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(cover, Qt::ColorOnly);
{
QByteArray thumbFormat = "JPG";
int32 thumbQuality = 87;
QBuffer jpegBuffer(&jpeg);
full.save(&jpegBuffer, thumbFormat, thumbQuality);
}
photoThumbs.insert('0', full);
thumb = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));
thumbId = MTP::nonce<uint64>();
}
}
}
}
}
if (type == ToPreparePhoto) {
int32 w = img.width(), h = img.height();
@@ -189,7 +223,7 @@ void LocalImageLoaderPrivate::prepareImages() {
photo = MTP_photo(MTP_long(id), MTP_long(0), MTP_int(user), MTP_int(unixtime()), MTP_geoPointEmpty(), MTP_vector<MTPPhotoSize>(photoSizes));
thumbId = id;
} else if ((type == ToPrepareVideo || type == ToPrepareDocument) && !img.isNull()) {
} else if ((type == ToPrepareVideo || type == ToPrepareDocument) && !img.isNull() && !isSong) {
int32 w = img.width(), h = img.height();
QByteArray thumbFormat = "JPG";
int32 thumbQuality = 87;

View File

@@ -517,6 +517,8 @@ namespace {
typedef QPair<MediaKey, FileLocation> FileLocationPair;
typedef QMap<QString, FileLocationPair> FileLocationPairs;
FileLocationPairs _fileLocationPairs;
typedef QMap<MediaKey, MediaKey> FileLocationAliases;
FileLocationAliases _fileLocationAliases;
FileKey _locationsKey = 0;
FileKey _recentStickersKeyOld = 0, _stickersKey = 0;
@@ -566,14 +568,28 @@ namespace {
_writeMap(WriteMapFast);
}
quint32 size = 0;
for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
for (FileLocations::const_iterator i = _fileLocations.cbegin(), e = _fileLocations.cend(); i != e; ++i) {
// location + type + namelen + name + date + size
size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(i.value().name) + _dateTimeSize() + sizeof(quint32);
}
//end mark
size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(QString()) + _dateTimeSize() + sizeof(quint32);
size += sizeof(quint32); // aliases count
for (FileLocationAliases::const_iterator i = _fileLocationAliases.cbegin(), e = _fileLocationAliases.cend(); i != e; ++i) {
// alias + location
size += sizeof(quint64) * 2 + sizeof(quint64) * 2;
}
EncryptedDescriptor data(size);
for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
data.stream << quint64(i.key().first) << quint64(i.key().second) << quint32(i.value().type) << i.value().name << i.value().modified << quint32(i.value().size);
}
data.stream << quint64(0) << quint64(0) << quint32(0) << QString() << QDateTime::currentDateTime() << quint32(0);
data.stream << quint32(_fileLocationAliases.size());
for (FileLocationAliases::const_iterator i = _fileLocationAliases.cbegin(), e = _fileLocationAliases.cend(); i != e; ++i) {
data.stream << quint64(i.key().first) << quint64(i.key().second) << quint64(i.value().first) << quint64(i.value().second);
}
FileWriteDescriptor file(_locationsKey);
file.writeEncrypted(data);
}
@@ -588,12 +604,18 @@ namespace {
return;
}
bool endMarkFound = false;
while (!locations.stream.atEnd()) {
quint64 first, second;
FileLocation loc;
quint32 type;
locations.stream >> first >> second >> type >> loc.name >> loc.modified >> loc.size;
if (!first && !second && !type && loc.name.isEmpty() && !loc.size) { // end mark
endMarkFound = true;
break;
}
MediaKey key(first, second);
loc.type = StorageFileType(type);
@@ -604,6 +626,16 @@ namespace {
_writeLocations();
}
}
if (endMarkFound) {
quint32 cnt;
locations.stream >> cnt;
for (quint32 i = 0; i < cnt; ++i) {
quint64 kfirst, ksecond, vfirst, vsecond;
locations.stream >> kfirst >> ksecond >> vfirst >> vsecond;
_fileLocationAliases.insert(MediaKey(kfirst, ksecond), MediaKey(vfirst, vsecond));
}
}
}
mtpDcOptions *_dcOpts = 0;
@@ -736,6 +768,14 @@ namespace {
};
} break;
case dbiTryIPv6: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
cSetTryIPv6(v == 1);
} break;
case dbiSeenTrayTooltip: {
qint32 v;
stream >> v;
@@ -996,6 +1036,14 @@ namespace {
cSetDialogLastPath(path);
} break;
case dbiSongVolume: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
cSetSongVolume(snap(v / 1e6, 0., 1.));
} break;
default:
LOG(("App Error: unknown blockId in _readSetting: %1").arg(blockId));
return false;
@@ -1217,7 +1265,7 @@ namespace {
_writeMap(WriteMapFast);
}
uint32 size = 11 * (sizeof(quint32) + sizeof(qint32));
uint32 size = 12 * (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));
@@ -1238,6 +1286,7 @@ namespace {
data.stream << quint32(dbiCompressPastedImage) << qint32(cCompressPastedImage());
data.stream << quint32(dbiEmojiTab) << qint32(cEmojiTab());
data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
data.stream << quint32(dbiSongVolume) << qint32(qRound(cSongVolume() * 1e6));
{
RecentEmojisPreload v(cRecentEmojisPreload());
@@ -1789,7 +1838,7 @@ namespace Local {
cSetDcOptions(dcOpts);
}
quint32 size = 10 * (sizeof(quint32) + sizeof(qint32));
quint32 size = 11 * (sizeof(quint32) + sizeof(qint32));
for (mtpDcOptions::const_iterator i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
size += sizeof(quint32) + sizeof(quint32) + sizeof(quint32);
size += sizeof(quint32) + _stringSize(QString::fromUtf8(i->ip.data(), i->ip.size()));
@@ -1827,6 +1876,7 @@ namespace Local {
const ConnectionProxy &proxy(cConnectionProxy());
data.stream << proxy.host << qint32(proxy.port) << proxy.user << proxy.password;
}
data.stream << quint32(dbiTryIPv6) << qint32(cTryIPv6());
TWindowPos pos(cWindowPos());
data.stream << quint32(dbiWindowPosition) << qint32(pos.x) << qint32(pos.y) << qint32(pos.w) << qint32(pos.h) << qint32(pos.moncrc) << qint32(pos.maximized);
@@ -1989,12 +2039,21 @@ namespace Local {
return (_draftsPositionsMap.constFind(peer) != _draftsPositionsMap.cend());
}
void writeFileLocation(const MediaKey &location, const FileLocation &local) {
void writeFileLocation(MediaKey location, const FileLocation &local) {
if (local.name.isEmpty()) return;
FileLocationAliases::const_iterator aliasIt = _fileLocationAliases.constFind(location);
if (aliasIt != _fileLocationAliases.cend()) {
location = aliasIt.value();
}
FileLocationPairs::iterator i = _fileLocationPairs.find(local.name);
if (i != _fileLocationPairs.cend()) {
if (i.value().second == local) {
if (i.value().first != location) {
_fileLocationAliases.insert(location, i.value().first);
_writeLocations(WriteMapFast);
}
return;
}
if (i.value().first != location) {
@@ -2012,7 +2071,12 @@ namespace Local {
_writeLocations(WriteMapFast);
}
FileLocation readFileLocation(const MediaKey &location, bool check) {
FileLocation readFileLocation(MediaKey location, bool check) {
FileLocationAliases::const_iterator aliasIt = _fileLocationAliases.constFind(location);
if (aliasIt != _fileLocationAliases.cend()) {
location = aliasIt.value();
}
FileLocations::iterator i = _fileLocations.find(location);
for (FileLocations::iterator i = _fileLocations.find(location); (i != _fileLocations.end()) && (i.key() == location);) {
if (check) {
@@ -2231,13 +2295,21 @@ namespace Local {
void _writeStickerSet(QDataStream &stream, uint64 setId) {
StickerSets::const_iterator it = cStickerSets().constFind(setId);
if (it == cStickerSets().cend() || it->stickers.isEmpty()) return;
if (it == cStickerSets().cend()) return;
stream << quint64(it->id) << quint64(it->access) << it->title << it->shortName << quint32(it->stickers.size());
bool notLoaded = (it->flags & MTPDstickerSet_flag_NOT_LOADED);
if (notLoaded) {
stream << quint64(it->id) << quint64(it->access) << it->title << it->shortName << qint32(-it->count) << qint32(it->hash) << qint32(it->flags);
return;
} else {
if (it->stickers.isEmpty()) return;
}
stream << quint64(it->id) << quint64(it->access) << it->title << it->shortName << qint32(it->stickers.size()) << qint32(it->hash) << qint32(it->flags);
for (StickerPack::const_iterator j = it->stickers.cbegin(), e = it->stickers.cend(); j != e; ++j) {
DocumentData *doc = *j;
stream << quint64(doc->id) << quint64(doc->access) << qint32(doc->date) << doc->name << doc->mime << qint32(doc->dc) << qint32(doc->size) << qint32(doc->dimensions.width()) << qint32(doc->dimensions.height()) << qint32(doc->type) << doc->sticker->alt;
switch (doc->sticker->set.type()) {
stream << quint64(doc->id) << quint64(doc->access) << qint32(doc->date) << doc->name << doc->mime << qint32(doc->dc) << qint32(doc->size) << qint32(doc->dimensions.width()) << qint32(doc->dimensions.height()) << qint32(doc->type) << doc->sticker()->alt;
switch (doc->sticker()->set.type()) {
case mtpc_inputStickerSetID: {
stream << qint32(StickerSetTypeID);
} break;
@@ -2249,7 +2321,7 @@ namespace Local {
stream << qint32(StickerSetTypeEmpty);
} break;
}
const StorageImageLocation &loc(doc->sticker->loc);
const StorageImageLocation &loc(doc->sticker()->loc);
stream << qint32(loc.width) << qint32(loc.height) << qint32(loc.dc) << quint64(loc.volume) << qint32(loc.local) << quint64(loc.secret);
}
}
@@ -2266,30 +2338,39 @@ namespace Local {
}
_writeMap();
} else {
int32 setsCount = 0;
quint32 size = sizeof(quint32) + _bytearraySize(cStickersHash());
for (StickerSets::const_iterator i = sets.cbegin(); i != sets.cend(); ++i) {
bool notLoaded = (i->flags & MTPDstickerSet_flag_NOT_LOADED);
if (notLoaded) {
if (!(i->flags & MTPDstickerSet_flag_disabled)) { // waiting to receive
return;
}
} else {
if (i->stickers.isEmpty()) continue;
}
// id + access + title + shortName + stickersCount + hash + flags
size += sizeof(quint64) * 2 + _stringSize(i->title) + _stringSize(i->shortName) + sizeof(quint32) + sizeof(qint32) * 2;
for (StickerPack::const_iterator j = i->stickers.cbegin(), e = i->stickers.cend(); j != e; ++j) {
DocumentData *doc = *j;
// id + access + date + namelen + name + mimelen + mime + dc + size + width + height + type + alt + type-of-set
size += sizeof(quint64) + sizeof(quint64) + sizeof(qint32) + _stringSize(doc->name) + _stringSize(doc->mime) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + _stringSize(doc->sticker()->alt) + sizeof(qint32);
// thumb-width + thumb-height + thumb-dc + thumb-volume + thumb-local + thumb-secret
size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(quint64) + sizeof(qint32) + sizeof(quint64);
}
++setsCount;
}
if (!_stickersKey) {
_stickersKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
}
quint32 size = sizeof(quint32) + _bytearraySize(cStickersHash());
for (StickerSets::const_iterator i = sets.cbegin(); i != sets.cend(); ++i) {
if (i->stickers.isEmpty()) continue;
// id + access + title + shortName + stickersCount
size += sizeof(quint64) * 2 + _stringSize(i->title) + _stringSize(i->shortName) + sizeof(quint32);
for (StickerPack::const_iterator j = i->stickers.cbegin(), e = i->stickers.cend(); j != e; ++j) {
DocumentData *doc = *j;
// id + access + date + namelen + name + mimelen + mime + dc + size + width + height + type + alt + type-of-set
size += sizeof(quint64) + sizeof(quint64) + sizeof(qint32) + _stringSize(doc->name) + _stringSize(doc->mime) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + _stringSize(doc->sticker->alt) + sizeof(qint32);
// thumb-width + thumb-height + thumb-dc + thumb-volume + thumb-local + thumb-secret
size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(quint64) + sizeof(qint32) + sizeof(quint64);
}
}
EncryptedDescriptor data(size);
data.stream << quint32(cStickerSets().size()) << cStickersHash();
_writeStickerSet(data.stream, DefaultStickerSetId);
data.stream << quint32(setsCount) << cStickersHash();
_writeStickerSet(data.stream, CustomStickerSetId);
for (StickerSetsOrder::const_iterator i = cStickerSetsOrder().cbegin(), e = cStickerSetsOrder().cend(); i != e; ++i) {
_writeStickerSet(data.stream, *i);
@@ -2312,15 +2393,17 @@ namespace Local {
StickerSets &sets(cRefStickerSets());
sets.clear();
cSetStickerSetsOrder(StickerSetsOrder());
StickerSetsOrder &order(cRefStickerSetsOrder());
order.clear();
RecentStickerPack &recent(cRefRecentStickers());
recent.clear();
cSetStickersHash(QByteArray());
StickerSet &def(sets.insert(DefaultStickerSetId, StickerSet(DefaultStickerSetId, 0, lang(lng_stickers_default_set), QString())).value());
StickerSet &custom(sets.insert(CustomStickerSetId, StickerSet(CustomStickerSetId, 0, lang(lng_custom_stickers), QString())).value());
StickerSet &def(sets.insert(DefaultStickerSetId, StickerSet(DefaultStickerSetId, 0, lang(lng_stickers_default_set), QString(), 0, 0, MTPDstickerSet_flag_official)).value());
StickerSet &custom(sets.insert(CustomStickerSetId, StickerSet(CustomStickerSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, 0)).value());
QMap<uint64, bool> read;
while (!stickers.stream.atEnd()) {
@@ -2347,16 +2430,22 @@ namespace Local {
}
DocumentData *doc = App::documentSet(id, 0, access, date, attributes, mime, ImagePtr(), dc, size, StorageImageLocation());
if (!doc->sticker) continue;
if (!doc->sticker()) continue;
if (value > 0) {
def.stickers.push_back(doc);
++def.count;
} else {
custom.stickers.push_back(doc);
++custom.count;
}
if (recent.size() < StickerPanPerRow * StickerPanRowsPerPage && qAbs(value) > 1) recent.push_back(qMakePair(doc, qAbs(value)));
}
if (def.stickers.isEmpty()) sets.remove(DefaultStickerSetId);
if (def.stickers.isEmpty()) {
sets.remove(DefaultStickerSetId);
} else {
order.push_front(DefaultStickerSetId);
}
if (custom.stickers.isEmpty()) sets.remove(CustomStickerSetId);
writeStickers();
@@ -2396,11 +2485,18 @@ namespace Local {
for (uint32 i = 0; i < cnt; ++i) {
quint64 setId = 0, setAccess = 0;
QString setTitle, setShortName;
quint32 scnt = 0;
qint32 scnt = 0;
stickers.stream >> setId >> setAccess >> setTitle >> setShortName >> scnt;
qint32 setHash = 0, setFlags = 0;
if (stickers.version > 8033) {
stickers.stream >> setHash >> setFlags;
}
if (setId == DefaultStickerSetId) {
setTitle = lang(lng_stickers_default_set);
setFlags |= MTPDstickerSet_flag_official;
order.push_front(setId);
} else if (setId == CustomStickerSetId) {
setTitle = lang(lng_custom_stickers);
} else if (setId) {
@@ -2408,11 +2504,16 @@ namespace Local {
} else {
continue;
}
StickerSet &set(sets.insert(setId, StickerSet(setId, setAccess, setTitle, setShortName)).value());
StickerSet &set(sets.insert(setId, StickerSet(setId, setAccess, setTitle, setShortName, 0, setHash, setFlags)).value());
if (scnt < 0) { // disabled not loaded set
set.count = -scnt;
continue;
}
set.stickers.reserve(scnt);
QMap<uint64, bool> read;
for (uint32 j = 0; j < scnt; ++j) {
for (int32 j = 0; j < scnt; ++j) {
quint64 id, access;
QString name, mime, alt;
qint32 date, dc, size, width, height, type, typeOfSet;
@@ -2453,9 +2554,10 @@ namespace Local {
StorageImageLocation thumb(thumbWidth, thumbHeight, thumbDc, thumbVolume, thumbLocal, thumbSecret);
DocumentData *doc = App::documentSet(id, 0, access, date, attributes, mime, thumb.dc ? ImagePtr(thumb) : ImagePtr(), dc, size, thumb);
if (!doc->sticker) continue;
if (!doc->sticker()) continue;
set.stickers.push_back(doc);
++set.count;
}
}
@@ -2771,7 +2873,7 @@ namespace Local {
if (!QDir(di.filePath()).removeRecursively()) result = false;
} else {
QString path = di.filePath();
if (!path.endsWith(QLatin1String("map0")) && !path.endsWith(QLatin1String("map1"))) {
if (!path.endsWith(qstr("map0")) && !path.endsWith(qstr("map1"))) {
if (!QFile::remove(di.filePath())) result = false;
}
}

View File

@@ -113,8 +113,8 @@ namespace Local {
MessageCursor readDraftPositions(const PeerId &peer);
bool hasDraftPositions(const PeerId &peer);
void writeFileLocation(const StorageKey &location, const FileLocation &local);
FileLocation readFileLocation(const StorageKey &location, bool check = true);
void writeFileLocation(MediaKey location, const FileLocation &local);
FileLocation readFileLocation(MediaKey location, bool check = true);
void writeImage(const StorageKey &location, const ImagePtr &img);
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);

View File

@@ -277,7 +277,7 @@ void TopBarWidget::showAll() {
resizeEvent(0);
return;
}
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
PeerData *p = App::main() ? App::main()->profilePeer() : 0, *o = App::main() ? App::main()->overviewPeer() : 0;
if (p && (p->chat || p->asUser()->contact >= 0)) {
if (p->chat) {
if (p->asChat()->forbidden) {
@@ -324,7 +324,7 @@ void TopBarWidget::showAll() {
_mediaType.hide();
}
}
if (App::main() && App::main()->historyPeer() && !p && _clearSelection.isHidden() && !cWideMode()) {
if (App::main() && App::main()->historyPeer() && !o && !p && _clearSelection.isHidden() && !cWideMode()) {
_info.show();
} else {
_info.hide();
@@ -350,9 +350,12 @@ MainWidget *TopBarWidget::main() {
return static_cast<MainWidget*>(parentWidget());
}
MainWidget::MainWidget(Window *window) : QWidget(window), _started(0), failedObjId(0), _toForwardNameVersion(0), _dialogsWidth(st::dlgMinWidth),
dialogs(this), history(this), profile(0), overview(0), _topBar(this), _forwardConfirm(0), hider(0), _mediaType(this), _mediaTypeMask(0),
updGoodPts(0), updLastPts(0), updPtsCount(0), updDate(0), updQts(-1), updSeq(0), updInited(false), updSkipPtsUpdateLevel(0), _onlineRequest(0), _lastWasOnline(false), _lastSetOnline(0), _isIdle(false),
MainWidget::MainWidget(Window *window) : QWidget(window),
_started(0), failedObjId(0), _toForwardNameVersion(0), _dialogsWidth(st::dlgMinWidth),
dialogs(this), history(this), profile(0), overview(0), _player(this), _topBar(this),
_forwardConfirm(0), hider(0), _playerHeight(0), _contentScrollAddToY(0), _mediaType(this), _mediaTypeMask(0),
updGoodPts(0), updLastPts(0), updPtsCount(0), updDate(0), updQts(-1), updSeq(0), updInited(false), updSkipPtsUpdateLevel(0),
_onlineRequest(0), _lastWasOnline(false), _lastSetOnline(0), _isIdle(false),
_failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _background(0), _api(new ApiWrap(this)) {
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
@@ -369,14 +372,17 @@ _failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _backgr
connect(&_bySeqTimer, SIGNAL(timeout()), this, SLOT(getDifference()));
connect(&_byPtsTimer, SIGNAL(timeout()), this, SLOT(getDifference()));
connect(&_failDifferenceTimer, SIGNAL(timeout()), this, SLOT(getDifferenceForce()));
connect(_api, SIGNAL(fullPeerUpdated(PeerData*)), this, SIGNAL(peerUpdated(PeerData*)));
connect(this, SIGNAL(peerUpdated(PeerData*)), &history, SLOT(peerUpdated(PeerData*)));
connect(&_topBar, SIGNAL(clicked()), this, SLOT(onTopBarClick()));
connect(&history, SIGNAL(peerShown(PeerData*)), this, SLOT(onPeerShown(PeerData*)));
connect(&updateNotifySettingTimer, SIGNAL(timeout()), this, SLOT(onUpdateNotifySettings()));
connect(this, SIGNAL(showPeerAsync(quint64,qint32,bool,bool)), this, SLOT(showPeer(quint64,qint32,bool,bool)), Qt::QueuedConnection);
if (audioPlayer()) {
connect(audioPlayer(), SIGNAL(updated(AudioData*)), this, SLOT(audioPlayProgress(AudioData*)));
connect(audioPlayer(), SIGNAL(stopped(AudioData*)), this, SLOT(audioPlayProgress(AudioData*)));
connect(audioPlayer(), SIGNAL(updated(const AudioMsgId&)), this, SLOT(audioPlayProgress(const AudioMsgId&)));
connect(audioPlayer(), SIGNAL(stopped(const AudioMsgId&)), this, SLOT(audioPlayProgress(const AudioMsgId&)));
connect(audioPlayer(), SIGNAL(updated(const SongMsgId&)), this, SLOT(documentPlayProgress(const SongMsgId&)));
connect(audioPlayer(), SIGNAL(stopped(const SongMsgId&)), this, SLOT(documentPlayProgress(const SongMsgId&)));
}
connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted()));
@@ -394,7 +400,10 @@ _failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _backgr
App::wnd()->getTitle()->updateBackButton();
_topBar.hide();
_player.hide();
_topBar.raise();
_player.raise();
dialogs.raise();
_mediaType.raise();
@@ -409,17 +418,27 @@ _failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _backgr
_api->init();
}
void MainWidget::onForward(const PeerId &peer, bool forwardSelected) {
void MainWidget::onForward(const PeerId &peer, ForwardWhatMessages what) {
history.cancelReply();
_toForward.clear();
if (forwardSelected) {
if (what == ForwardSelectedMessages) {
if (overview) {
overview->fillSelectedItems(_toForward, false);
} else {
history.fillSelectedItems(_toForward, false);
}
} else if (App::contextItem() && dynamic_cast<HistoryMessage*>(App::contextItem()) && App::contextItem()->id > 0) {
_toForward.insert(App::contextItem()->id, App::contextItem());
} else {
HistoryItem *item = 0;
if (what == ForwardContextMessage) {
item = App::contextItem();
} else if (what == ForwardPressedMessage) {
item = App::pressedItem();
} else if (what == ForwardPressedLinkMessage) {
item = App::pressedLinkItem();
}
if (dynamic_cast<HistoryMessage*>(item) && item->id > 0) {
_toForward.insert(item->id, item);
}
}
updateForwardingTexts();
showPeer(peer, 0, false, true);
@@ -559,6 +578,10 @@ void MainWidget::updateStickers() {
history.updateStickers();
}
void MainWidget::botCommandsChanged(UserData *bot) {
history.botCommandsChanged(bot);
}
void MainWidget::onUpdateMuted() {
App::updateMuted();
}
@@ -571,6 +594,19 @@ void MainWidget::onSendPaths(const PeerId &peer) {
history.onSendPaths(peer);
}
void MainWidget::onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data) {
if (data->hasFormat(qsl("application/x-td-forward-selected"))) {
onForward(peer, ForwardSelectedMessages);
} else if (data->hasFormat(qsl("application/x-td-forward-pressed-link"))) {
onForward(peer, ForwardPressedLinkMessage);
} else if (data->hasFormat(qsl("application/x-td-forward-pressed"))) {
onForward(peer, ForwardPressedMessage);
} else {
showPeer(peer, 0, false, true);
history.onFilesDrop(data);
}
}
void MainWidget::noHider(HistoryHider *destroyed) {
if (hider == destroyed) {
hider = 0;
@@ -587,7 +623,7 @@ void MainWidget::noHider(HistoryHider *destroyed) {
onPeerShown(history.peer());
if (profile || overview || (history.peer() && history.peer()->id)) {
dialogs.enableShadow(false);
QPixmap animCache = myGrab(this, QRect(0, st::topBarHeight, _dialogsWidth, height() - st::topBarHeight)),
QPixmap animCache = myGrab(this, QRect(0, _playerHeight + st::topBarHeight, _dialogsWidth, height() - _playerHeight - st::topBarHeight)),
animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
dialogs.enableShadow();
_topBar.enableShadow();
@@ -616,15 +652,16 @@ void MainWidget::hiderLayer(HistoryHider *h) {
hider = h;
connect(hider, SIGNAL(forwarded()), &dialogs, SLOT(onCancelSearch()));
dialogsToUp();
if (cWideMode()) {
hider->show();
resizeEvent(0);
dialogs.activate();
} else {
dialogsToUp();
hider->hide();
dialogs.enableShadow(false);
QPixmap animCache = myGrab(this, QRect(0, 0, _dialogsWidth, height()));
QPixmap animCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
dialogs.enableShadow();
_topBar.enableShadow();
@@ -694,6 +731,10 @@ void MainWidget::dialogsActivate() {
dialogs.activate();
}
DragState MainWidget::getDragState(const QMimeData *mime) {
return history.getDragState(mime);
}
bool MainWidget::leaveChatFailed(PeerData *peer, const RPCError &error) {
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
@@ -735,14 +776,16 @@ void MainWidget::deleteMessages(const QVector<MTPint> &ids) {
void MainWidget::deletedContact(UserData *user, const MTPcontacts_Link &result) {
const MTPDcontacts_link &d(result.c_contacts_link());
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser));
App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link);
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser), false);
App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link, false);
App::emitPeerUpdated();
}
void MainWidget::deleteHistoryAndContact(UserData *user, const MTPcontacts_Link &result) {
const MTPDcontacts_link &d(result.c_contacts_link());
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser));
App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link);
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser), false);
App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link, false);
App::emitPeerUpdated();
if ((profile && profile->peer() == user) || (overview && overview->peer() == user) || _stack.contains(user) || history.peer() == user) {
showPeer(0);
@@ -806,13 +849,13 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
const QVector<MTPMessage> *v = 0;
if (result.type() == mtpc_messages_messages) {
const MTPDmessages_messages &d(result.c_messages_messages());
App::feedChats(d.vchats);
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
v = &d.vmessages.c_vector().v;
} else if (result.type() == mtpc_messages_messagesSlice) {
const MTPDmessages_messagesSlice &d(result.c_messages_messagesSlice());
App::feedChats(d.vchats);
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
v = &d.vmessages.c_vector().v;
}
if (!v) return;
@@ -1105,13 +1148,14 @@ void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &r
}
}
mediaOverviewUpdated(peer);
mediaOverviewUpdated(peer, type);
}
void MainWidget::mediaOverviewUpdated(PeerData *peer) {
if (profile) profile->mediaOverviewUpdated(peer);
void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
if (profile) profile->mediaOverviewUpdated(peer, type);
if (!_player.isHidden()) _player.mediaOverviewUpdated(peer, type);
if (overview && overview->peer() == peer) {
overview->mediaOverviewUpdated(peer);
overview->mediaOverviewUpdated(peer, type);
int32 mask = 0;
History *h = peer ? App::historyLoaded(peer->id) : 0;
@@ -1303,7 +1347,7 @@ void MainWidget::photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpR
h->_overview[type].push_front(item->id);
}
}
if (App::wnd()) App::wnd()->mediaOverviewUpdated(h->peer);
if (App::wnd()) App::wnd()->mediaOverviewUpdated(h->peer, type);
}
void MainWidget::partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result) {
@@ -1378,16 +1422,16 @@ void MainWidget::audioLoadProgress(mtpFileLoader *loader) {
if (audio->loader->done()) {
audio->finish();
QString already = audio->already();
bool play = audio->openOnSave > 0 && audioPlayer();
bool play = audio->openOnSave > 0 && audio->openOnSaveMsgId && audioPlayer();
if ((!already.isEmpty() && audio->openOnSave) || (!audio->data.isEmpty() && play)) {
if (play) {
AudioData *playing = 0;
AudioMsgId playing;
AudioPlayerState state = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &state);
if (playing == audio && state != AudioPlayerStopped) {
audioPlayer()->pauseresume();
if (playing.msgId == audio->openOnSaveMsgId && !(state & AudioPlayerStoppedMask) && state != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewAudios);
} else {
audioPlayer()->play(audio);
audioPlayer()->play(AudioMsgId(audio, audio->openOnSaveMsgId));
if (App::main()) App::main()->audioMarkRead(audio);
}
} else {
@@ -1411,15 +1455,17 @@ void MainWidget::audioLoadProgress(mtpFileLoader *loader) {
}
}
void MainWidget::audioPlayProgress(AudioData *audio) {
AudioData *playing = 0;
void MainWidget::audioPlayProgress(const AudioMsgId &audioId) {
AudioMsgId playing;
AudioPlayerState state = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &state);
if (playing == audio && state == AudioPlayerStoppedAtStart) {
audioPlayer()->clearStoppedAtStart(audio);
if (playing == audioId && state == AudioPlayerStoppedAtStart) {
audioPlayer()->clearStoppedAtStart(audioId);
AudioData *audio = audioId.audio;
QString already = audio->already(true);
if (already.isEmpty() && !audio->data.isEmpty()) {
bool mp3 = (audio->mime == QLatin1String("audio/mp3"));
bool mp3 = (audio->mime == qstr("audio/mp3"));
QString filename = saveFileName(lang(lng_save_audio), mp3 ? qsl("MP3 Audio (*.mp3);;All files (*.*)") : qsl("OGG Opus Audio (*.ogg);;All files (*.*)"), qsl("audio"), mp3 ? qsl(".mp3") : qsl(".ogg"), false);
if (!filename.isEmpty()) {
QFile f(filename);
@@ -1438,12 +1484,78 @@ void MainWidget::audioPlayProgress(AudioData *audio) {
}
}
const AudioItems &items(App::audioItems());
AudioItems::const_iterator i = items.constFind(audio);
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
msgUpdated(j.key()->history()->peer->id, j.key());
if (HistoryItem *item = App::histItemById(audioId.msgId)) {
msgUpdated(item->history()->peer->id, item);
}
}
void MainWidget::documentPlayProgress(const SongMsgId &songId) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0;
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing == songId && playingState == AudioPlayerStoppedAtStart) {
playingState = AudioPlayerStopped;
audioPlayer()->clearStoppedAtStart(songId);
DocumentData *document = songId.song;
QString already = document->already(true);
if (already.isEmpty() && !document->data.isEmpty()) {
QString name = document->name, filter;
MimeType mimeType = mimeTypeForName(document->mime);
QStringList p = mimeType.globPatterns();
QString pattern = p.isEmpty() ? QString() : p.front();
if (name.isEmpty()) {
name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString());
}
if (pattern.isEmpty()) {
filter = qsl("All files (*.*)");
} else {
filter = mimeType.filterString() + qsl(";;All files (*.*)");
}
QString filename = saveFileName(lang(lng_save_file), filter, qsl("doc"), name, false);
if (!filename.isEmpty()) {
QFile f(filename);
if (f.open(QIODevice::WriteOnly)) {
if (f.write(document->data) == document->data.size()) {
f.close();
already = filename;
document->location = FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename);
Local::writeFileLocation(mediaKey(mtpToLocationType(mtpc_inputDocumentFileLocation), document->dc, document->id), FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename));
}
}
}
}
if (!already.isEmpty()) {
psOpenFile(already);
}
}
if (playing == songId) {
_player.updateState(playing, playingState, playingPosition, playingDuration, playingFrequency);
if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
if (_player.isHidden()) {
_player.clearSelection();
_player.show();
_playerHeight = _contentScrollAddToY = _player.height();
resizeEvent(0);
}
}
}
if (HistoryItem *item = App::histItemById(songId.msgId)) {
msgUpdated(item->history()->peer->id, item);
}
}
void MainWidget::hidePlayer() {
if (!_player.isHidden()) {
_player.hide();
_contentScrollAddToY = -_player.height();
_playerHeight = 0;
resizeEvent(0);
}
}
@@ -1463,16 +1575,32 @@ void MainWidget::audioLoadRetry() {
}
void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
bool songPlayActivated = false;
DocumentData *document = App::document(loader->objId());
if (document->loader) {
if (document->loader->done()) {
document->finish();
QString already = document->already();
if (!already.isEmpty() && document->openOnSave) {
if (document->openOnSave > 0 && document->size < MediaViewImageSizeLimit) {
HistoryItem *item = (document->openOnSave && document->openOnSaveMsgId) ? App::histItemById(document->openOnSaveMsgId) : 0;
bool play = document->song() && audioPlayer() && document->openOnSave && item;
if ((!already.isEmpty() || (!document->data.isEmpty() && play)) && document->openOnSave) {
if (play) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing.msgId == item->id && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewDocuments);
} else {
SongMsgId song(document, item->id);
audioPlayer()->play(song);
if (App::main()) App::main()->documentPlayProgress(song);
}
songPlayActivated = true;
} else if(document->openOnSave > 0 && document->size < MediaViewImageSizeLimit) {
QImageReader reader(already);
if (reader.canRead()) {
HistoryItem *item = App::histItemById(document->openOnSaveMsgId);
if (reader.supportsAnimation() && reader.imageCount() > 1 && item) {
startGif(item, already);
} else if (item) {
@@ -1502,6 +1630,21 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
}
}
App::wnd()->documentUpdated(document);
if (!songPlayActivated && audioPlayer()) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0;
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing.song == document && !_player.isHidden()) {
if (document->loader) {
_player.updateState(playing, playingState, playingPosition, playingDuration, playingFrequency);
} else {
audioPlayer()->play(playing);
}
}
}
}
void MainWidget::documentLoadFailed(mtpFileLoader *loader, bool started) {
@@ -1761,19 +1904,19 @@ void MainWidget::showPeer(quint64 peerId, qint32 msgId, bool back, bool force) {
hider = 0;
}
if (force || !selectingPeer()) {
if (!animating() && ((history.isHidden() && (profile || overview)) || (!cWideMode() && (history.isHidden() || !peerId)))) {
if (!animating() && ((history.isHidden() && history.activePeer() && (profile || overview)) || (!cWideMode() && (history.isHidden() || !peerId)))) {
dialogs.enableShadow(false);
if (peerId) {
_topBar.enableShadow(false);
if (cWideMode()) {
animCache = myGrab(this, QRect(_dialogsWidth, st::topBarHeight, width() - _dialogsWidth, height() - st::topBarHeight));
animCache = myGrab(this, QRect(_dialogsWidth, _playerHeight + st::topBarHeight, width() - _dialogsWidth, height() - _playerHeight - st::topBarHeight));
} else {
animCache = myGrab(this, QRect(0, st::topBarHeight, _dialogsWidth, height() - st::topBarHeight));
animCache = myGrab(this, QRect(0, _playerHeight + st::topBarHeight, _dialogsWidth, height() - _playerHeight - st::topBarHeight));
}
} else if (cWideMode()) {
animCache = myGrab(this, QRect(_dialogsWidth, 0, width() - _dialogsWidth, height()));
animCache = myGrab(this, QRect(_dialogsWidth, _playerHeight, width() - _dialogsWidth, height() - _playerHeight));
} else {
animCache = myGrab(this, QRect(0, 0, _dialogsWidth, height()));
animCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
}
if (peerId || cWideMode()) {
animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
@@ -1822,6 +1965,8 @@ void MainWidget::showPeer(quint64 peerId, qint32 msgId, bool back, bool force) {
history.show();
if (!animCache.isNull()) {
history.animShow(animCache, animTopBarCache, back);
} else {
QTimer::singleShot(0, this, SLOT(setInnerFocus()));
}
}
}
@@ -1871,8 +2016,12 @@ PeerData *MainWidget::profilePeer() {
return profile ? profile->peer() : 0;
}
PeerData *MainWidget::overviewPeer() {
return overview ? overview->peer() : 0;
}
bool MainWidget::mediaTypeSwitch() {
if (!overview) return false;
if (!overview || (overview->type() == OverviewAudioDocuments)) return false;
for (int32 i = 0; i < OverviewCount; ++i) {
if (!(_mediaTypeMask & ~(1 << i))) {
@@ -1887,13 +2036,21 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
if (overview && overview->peer() == peer) {
if (overview->type() != type) {
overview->switchType(type);
} else if (type == OverviewAudioDocuments) { // hack for player
showBackFromStack();
}
return;
}
dialogs.enableShadow(false);
_topBar.enableShadow(false);
QPixmap animCache = myGrab(this, history.geometry()), animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
QRect topBarRect = QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight);
QRect historyRect = QRect(history.x(), topBarRect.y() + topBarRect.height(), history.width(), history.y() + history.height() - topBarRect.y() - topBarRect.height());
QPixmap animCache, animTopBarCache;
if (!animating() && (!cWideMode() || profile || overview || history.peer())) {
animCache = myGrab(this, historyRect);
animTopBarCache = myGrab(this, topBarRect);
}
dialogs.enableShadow();
_topBar.enableShadow();
if (!back) {
@@ -1901,7 +2058,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
_stack.push_back(new StackItemOverview(overview->peer(), overview->type(), overview->lastWidth(), overview->lastScrollTop()));
} else if (profile) {
_stack.push_back(new StackItemProfile(profile->peer(), profile->lastScrollTop(), profile->allMediaShown()));
} else {
} else if (history.peer()) {
_stack.push_back(new StackItemHistory(history.peer(), history.lastWidth(), history.lastScrollTop(), history.replyReturns(), history.kbWasHidden()));
}
}
@@ -1920,14 +2077,20 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
}
overview = new OverviewWidget(this, peer, type);
_mediaTypeMask = 0;
mediaOverviewUpdated(peer);
_topBar.show();
resizeEvent(0);
overview->animShow(animCache, animTopBarCache, back, lastScrollTop);
mediaOverviewUpdated(peer, type);
if (!animCache.isNull()) {
overview->animShow(animCache, animTopBarCache, back, lastScrollTop);
} else {
overview->fastShow();
}
history.animStop();
history.showPeer(0, 0, false, true);
history.hide();
if (!cWideMode()) dialogs.hide();
_topBar.raise();
_player.raise();
dialogs.raise();
_mediaType.raise();
if (hider) hider->raise();
@@ -1973,6 +2136,7 @@ void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop,
history.showPeer(0, 0, false, true);
history.hide();
_topBar.raise();
_player.raise();
dialogs.raise();
_mediaType.raise();
if (hider) hider->raise();
@@ -1980,7 +2144,16 @@ void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop,
}
void MainWidget::showBackFromStack() {
if (_stack.isEmpty() || selectingPeer()) return;
if (selectingPeer()) return;
if (_stack.isEmpty()) {
if (cWideMode()) {
showPeer(0, 0, false, true);
QTimer::singleShot(0, this, SLOT(setInnerFocus()));
} else {
onShowDialogs();
}
return;
}
StackItem *item = _stack.back();
_stack.pop_back();
if (item->type() == HistoryStackItem) {
@@ -2062,6 +2235,7 @@ void MainWidget::sentDataReceived(uint64 randomId, const MTPmessages_SentMessage
void MainWidget::sentUpdatesReceived(const MTPUpdates &result) {
handleUpdates(result);
App::emitPeerUpdated();
}
void MainWidget::msgUpdated(PeerId peer, const HistoryItem *msg) {
@@ -2225,19 +2399,26 @@ void MainWidget::resizeEvent(QResizeEvent *e) {
if (cWideMode()) {
_dialogsWidth = snap<int>((width() * 5) / 14, st::dlgMinWidth, st::dlgMaxWidth);
dialogs.setGeometry(0, 0, _dialogsWidth + st::dlgShadow, height());
_topBar.setGeometry(_dialogsWidth, 0, width() - _dialogsWidth, st::topBarHeight + st::titleShadow);
history.setGeometry(_dialogsWidth, tbh, width() - _dialogsWidth, height() - tbh);
_player.setGeometry(_dialogsWidth, 0, width() - _dialogsWidth, _player.height());
_topBar.setGeometry(_dialogsWidth, _playerHeight, width() - _dialogsWidth, st::topBarHeight + st::titleShadow);
history.setGeometry(_dialogsWidth, _playerHeight + tbh, width() - _dialogsWidth, height() - _playerHeight - tbh);
if (hider) hider->setGeometry(QRect(_dialogsWidth, 0, width() - _dialogsWidth, height()));
} else {
_dialogsWidth = width();
dialogs.setGeometry(0, 0, _dialogsWidth + st::dlgShadow, height());
_topBar.setGeometry(0, 0, _dialogsWidth, st::topBarHeight + st::titleShadow);
history.setGeometry(0, tbh, _dialogsWidth, height() - tbh);
_player.setGeometry(0, 0, _dialogsWidth, _player.height());
dialogs.setGeometry(0, _playerHeight, _dialogsWidth + st::dlgShadow, height() - _playerHeight);
_topBar.setGeometry(0, _playerHeight, _dialogsWidth, st::topBarHeight + st::titleShadow);
history.setGeometry(0, _playerHeight + tbh, _dialogsWidth, height() - _playerHeight - tbh);
if (hider) hider->setGeometry(QRect(0, 0, _dialogsWidth, height()));
}
_mediaType.move(width() - _mediaType.width(), st::topBarHeight);
_mediaType.move(width() - _mediaType.width(), _playerHeight + st::topBarHeight);
if (profile) profile->setGeometry(history.geometry());
if (overview) overview->setGeometry(history.geometry());
_contentScrollAddToY = 0;
}
int32 MainWidget::contentScrollAddToY() const {
return _contentScrollAddToY;
}
void MainWidget::keyPressEvent(QKeyEvent *e) {
@@ -2267,8 +2448,14 @@ void MainWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) {
}
void MainWidget::topBarShadowParams(int32 &x, float64 &o) {
if (!profile && !overview && dialogs.isHidden()) {
history.topBarShadowParams(x, o);
if (!cWideMode() && dialogs.isHidden()) {
if (profile) {
if (!history.activePeer()) profile->topBarShadowParams(x, o);
} else if (overview) {
if (!history.activePeer()) overview->topBarShadowParams(x, o);
} else {
history.topBarShadowParams(x, o);
}
}
}
@@ -2296,6 +2483,10 @@ TopBarWidget *MainWidget::topBar() {
return &_topBar;
}
PlayerWidget *MainWidget::player() {
return &_player;
}
void MainWidget::onTopBarClick() {
if (profile) {
profile->topBarClick();
@@ -2389,6 +2580,8 @@ void MainWidget::gotState(const MTPupdates_State &state) {
dialogs.loadDialogs();
updateOnline();
App::emitPeerUpdated();
}
void MainWidget::gotDifference(const MTPupdates_Difference &diff) {
@@ -2404,6 +2597,8 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) {
noUpdatesTimer.start(NoUpdatesTimeout);
updInited = true;
App::emitPeerUpdated();
} break;
case mtpc_updates_differenceSlice: {
const MTPDupdates_differenceSlice &d(diff.c_updates_differenceSlice());
@@ -2416,6 +2611,8 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) {
MTP_LOG(0, ("getDifference { good - after a slice of difference was received }%1").arg(cTestMode() ? " TESTMODE" : ""));
getDifference();
App::emitPeerUpdated();
} break;
case mtpc_updates_difference: {
const MTPDupdates_difference &d(diff.c_updates_difference());
@@ -2443,6 +2640,7 @@ void MainWidget::applySkippedPtsUpdates() {
}
--updSkipPtsUpdateLevel;
clearSkippedPtsUpdates();
App::emitPeerUpdated();
}
void MainWidget::clearSkippedPtsUpdates() {
@@ -2472,8 +2670,8 @@ bool MainWidget::updPtsUpdated(int pts, int ptsCount) { // return false if need
void MainWidget::feedDifference(const MTPVector<MTPUser> &users, const MTPVector<MTPChat> &chats, const MTPVector<MTPMessage> &msgs, const MTPVector<MTPUpdate> &other) {
App::wnd()->checkAutoLock();
App::feedUsers(users);
App::feedChats(chats);
App::feedUsers(users, false);
App::feedChats(chats, false);
feedMessageIds(other);
App::feedMsgs(msgs, 1);
feedUpdates(other, true);
@@ -2550,18 +2748,18 @@ bool MainWidget::started() {
void MainWidget::openLocalUrl(const QString &url) {
QString u(url.trimmed());
if (u.startsWith(QLatin1String("tg://resolve"), Qt::CaseInsensitive)) {
if (u.startsWith(qstr("tg://resolve"), Qt::CaseInsensitive)) {
QRegularExpressionMatch m = QRegularExpression(qsl("^tg://resolve/?\\?domain=([a-zA-Z0-9\\.\\_]+)(&(start|startgroup)=([a-zA-Z0-9\\.\\_\\-]+))?(&|$)"), QRegularExpression::CaseInsensitiveOption).match(u);
if (m.hasMatch()) {
QString start = m.captured(3), startToken = m.captured(4);
openUserByName(m.captured(1), (start == qsl("startgroup")), startToken);
}
} else if (u.startsWith(QLatin1String("tg://join"), Qt::CaseInsensitive)) {
} else if (u.startsWith(qstr("tg://join"), Qt::CaseInsensitive)) {
QRegularExpressionMatch m = QRegularExpression(qsl("^tg://join/?\\?invite=([a-zA-Z0-9\\.\\_\\-]+)(&|$)"), QRegularExpression::CaseInsensitiveOption).match(u);
if (m.hasMatch()) {
joinGroupByHash(m.captured(1));
}
} else if (u.startsWith(QLatin1String("tg://addstickers"), Qt::CaseInsensitive)) {
} else if (u.startsWith(qstr("tg://addstickers"), Qt::CaseInsensitive)) {
QRegularExpressionMatch m = QRegularExpression(qsl("^tg://addstickers/?\\?set=([a-zA-Z0-9\\.\\_]+)(&|$)"), QRegularExpression::CaseInsensitiveOption).match(u);
if (m.hasMatch()) {
stickersBox(MTP_inputStickerSetShortName(MTP_string(m.captured(1))));
@@ -2845,7 +3043,7 @@ void MainWidget::updateNotifySetting(PeerData *peer, bool enabled) {
}
void MainWidget::incrementSticker(DocumentData *sticker) {
if (!sticker || !sticker->sticker) return;
if (!sticker || !sticker->sticker()) return;
RecentStickerPack &recent(cGetRecentStickers());
RecentStickerPack::iterator i = recent.begin(), e = recent.end();
@@ -2886,13 +3084,13 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
bool found = false;
uint64 setId = 0;
QString setName;
switch (sticker->sticker->set.type()) {
case mtpc_inputStickerSetID: setId = sticker->sticker->set.c_inputStickerSetID().vid.v; break;
case mtpc_inputStickerSetShortName: setName = qs(sticker->sticker->set.c_inputStickerSetShortName().vshort_name).toLower().trimmed(); break;
switch (sticker->sticker()->set.type()) {
case mtpc_inputStickerSetID: setId = sticker->sticker()->set.c_inputStickerSetID().vid.v; break;
case mtpc_inputStickerSetShortName: setName = qs(sticker->sticker()->set.c_inputStickerSetShortName().vshort_name).toLower().trimmed(); break;
}
StickerSets &sets(cRefStickerSets());
for (StickerSets::const_iterator i = sets.cbegin(); i != sets.cend(); ++i) {
if (i->id == CustomStickerSetId || (setId && i->id == setId) || (!setName.isEmpty() && i->shortName.toLower().trimmed() == setName) || (!setId && setName.isEmpty() && i->id == DefaultStickerSetId)) {
if (i->id == CustomStickerSetId || i->id == DefaultStickerSetId || (setId && i->id == setId) || (!setName.isEmpty() && i->shortName.toLower().trimmed() == setName)) {
for (int32 j = 0, l = i->stickers.size(); j < l; ++j) {
if (i->stickers.at(j) == sticker) {
found = true;
@@ -2905,9 +3103,10 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
if (!found) {
StickerSets::iterator it = sets.find(CustomStickerSetId);
if (it == sets.cend()) {
it = sets.insert(CustomStickerSetId, StickerSet(CustomStickerSetId, 0, lang(lng_custom_stickers), QString()));
it = sets.insert(CustomStickerSetId, StickerSet(CustomStickerSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, 0));
}
it->stickers.push_back(sticker);
++it->count;
Local::writeStickers();
}
history.updateRecentStickers();
@@ -3050,7 +3249,8 @@ void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
noUpdatesTimer.start(NoUpdatesTimeout);
handleUpdates(updates);
} catch(mtpErrorUnexpected &e) { // just some other type
App::emitPeerUpdated();
} catch (mtpErrorUnexpected &e) { // just some other type
}
}
update();
@@ -3068,8 +3268,8 @@ void MainWidget::handleUpdates(const MTPUpdates &updates) {
}
}
App::feedChats(d.vchats);
App::feedUsers(d.vusers);
App::feedUsers(d.vusers, false);
App::feedChats(d.vchats, false);
feedUpdates(d.vupdates);
updSetState(0, d.vdate.v, updQts, d.vseq.v);
@@ -3085,8 +3285,8 @@ void MainWidget::handleUpdates(const MTPUpdates &updates) {
}
}
App::feedChats(d.vchats);
App::feedUsers(d.vusers);
App::feedUsers(d.vusers, false);
App::feedChats(d.vchats, false);
feedUpdates(d.vupdates);
updSetState(0, d.vdate.v, updQts, d.vseq.v);
@@ -3210,6 +3410,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
if (item->isMediaUnread()) {
item->markMediaRead();
msgUpdated(item->history()->peer->id, item);
if (item->out() && !item->history()->peer->chat) {
item->history()->peer->asUser()->madeAction();
}
}
}
}
@@ -3276,17 +3479,17 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateChatParticipants: {
const MTPDupdateChatParticipants &d(update.c_updateChatParticipants());
App::feedParticipants(d.vparticipants, true);
App::feedParticipants(d.vparticipants, true, false);
} break;
case mtpc_updateChatParticipantAdd: {
const MTPDupdateChatParticipantAdd &d(update.c_updateChatParticipantAdd());
App::feedParticipantAdd(d);
App::feedParticipantAdd(d, false);
} break;
case mtpc_updateChatParticipantDelete: {
const MTPDupdateChatParticipantDelete &d(update.c_updateChatParticipantDelete());
App::feedParticipantDelete(d);
App::feedParticipantDelete(d, false);
} break;
case mtpc_updateUserStatus: {
@@ -3305,7 +3508,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_userStatusOffline: user->onlineTill = d.vstatus.c_userStatusOffline().vwas_online.v; break;
case mtpc_userStatusOnline: user->onlineTill = d.vstatus.c_userStatusOnline().vexpires.v; break;
}
if (App::main()) App::main()->peerUpdated(user);
App::markPeerUpdated(user);
}
if (d.vuser_id.v == MTP::authedId()) {
if (d.vstatus.type() == mtpc_userStatusOffline || d.vstatus.type() == mtpc_userStatusEmpty) {
@@ -3328,7 +3531,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} else {
user->setName(textOneLine(user->firstName), textOneLine(user->lastName), user->nameOrPhone, textOneLine(qs(d.vusername)));
}
if (App::main()) App::main()->peerUpdated(user);
App::markPeerUpdated(user);
}
} break;
@@ -3342,7 +3545,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
user->photosCount = -1;
user->photos.clear();
} else {
if (user->photoId) {
if (user->photoId && user->photoId != UnknownPeerPhotoId) {
if (user->photosCount > 0) ++user->photosCount;
user->photos.push_front(App::photo(user->photoId));
} else {
@@ -3350,8 +3553,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
user->photos.clear();
}
}
if (App::main()) App::main()->peerUpdated(user);
if (App::wnd()) App::wnd()->mediaOverviewUpdated(user);
App::markPeerUpdated(user);
if (App::wnd()) App::wnd()->mediaOverviewUpdated(user, OverviewCount);
}
} break;
@@ -3367,7 +3570,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateContactLink: {
const MTPDupdateContactLink &d(update.c_updateContactLink());
App::feedUserLink(d.vuser_id, d.vmy_link, d.vforeign_link);
App::feedUserLink(d.vuser_id, d.vmy_link, d.vforeign_link, false);
} break;
case mtpc_updateNotifySettings: {
@@ -3386,7 +3589,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
if (user) {
user->setPhone(qs(d.vphone));
user->setName(user->firstName, user->lastName, (user->contact || isServiceUser(user->id) || user->phone.isEmpty()) ? QString() : App::formatPhone(user->phone), user->username);
if (App::main()) App::main()->peerUpdated(user);
App::markPeerUpdated(user);
}
} break;

View File

@@ -21,6 +21,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "historywidget.h"
#include "profilewidget.h"
#include "overviewwidget.h"
#include "playerwidget.h"
#include "apiwrap.h"
class Window;
@@ -163,6 +164,13 @@ public:
}
};
enum ForwardWhatMessages {
ForwardSelectedMessages,
ForwardContextMessage,
ForwardPressedMessage,
ForwardPressedLinkMessage
};
class MainWidget : public QWidget, public Animated, public RPCSender {
Q_OBJECT
@@ -182,6 +190,9 @@ public:
void topBarShadowParams(int32 &x, float64 &o);
TopBarWidget *topBar();
PlayerWidget *player();
int32 contentScrollAddToY() const;
void animShow(const QPixmap &bgAnimCache, bool back = false);
bool animStep(float64 ms);
@@ -226,6 +237,7 @@ public:
PeerData *activePeer();
MsgId activeMsgId();
PeerData *profilePeer();
PeerData *overviewPeer();
bool mediaTypeSwitch();
void showPeerProfile(PeerData *peer, bool back = false, int32 lastScrollTop = -1, bool allMediaShown = false);
void showMediaOverview(PeerData *peer, MediaOverviewType type, bool back = false, int32 lastScrollTop = -1);
@@ -254,14 +266,17 @@ public:
void shareContactLayer(UserData *contact);
void hiderLayer(HistoryHider *h);
void noHider(HistoryHider *destroyed);
void onForward(const PeerId &peer, bool forwardSelected);
void onForward(const PeerId &peer, ForwardWhatMessages what);
void onShareContact(const PeerId &peer, UserData *contact);
void onSendPaths(const PeerId &peer);
void onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data);
bool selectingPeer(bool withConfirm = false);
void offerPeer(PeerId peer);
void focusPeerSelect();
void dialogsActivate();
DragState getDragState(const QMimeData *mime);
bool leaveChatFailed(PeerData *peer, const RPCError &e);
void deleteHistory(PeerData *peer, const MTPUpdates &updates);
void deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHistory &result);
@@ -303,7 +318,7 @@ public:
void searchMessages(const QString &query);
void preloadOverviews(PeerData *peer);
void mediaOverviewUpdated(PeerData *peer);
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
void changingMsgId(HistoryItem *row, MsgId newId);
void itemRemoved(HistoryItem *item);
void itemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
@@ -352,6 +367,7 @@ public:
void updateMutedIn(int32 seconds);
void updateStickers();
void botCommandsChanged(UserData *bot);
~MainWidget();
@@ -376,10 +392,12 @@ public slots:
void audioLoadProgress(mtpFileLoader *loader);
void audioLoadFailed(mtpFileLoader *loader, bool started);
void audioLoadRetry();
void audioPlayProgress(AudioData *audio);
void audioPlayProgress(const AudioMsgId &audioId);
void documentLoadProgress(mtpFileLoader *loader);
void documentLoadFailed(mtpFileLoader *loader, bool started);
void documentLoadRetry();
void documentPlayProgress(const SongMsgId &songId);
void hidePlayer();
void setInnerFocus();
void dialogsCancelled();
@@ -479,12 +497,16 @@ private:
HistoryWidget history;
ProfileWidget *profile;
OverviewWidget *overview;
PlayerWidget _player;
TopBarWidget _topBar;
ConfirmBox *_forwardConfirm; // for narrow mode
HistoryHider *hider;
StackItems _stack;
QPixmap profileAnimCache;
int32 _playerHeight;
int32 _contentScrollAddToY;
Dropdown _mediaType;
int32 _mediaTypeMask;

View File

@@ -26,6 +26,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
namespace {
class SaveMsgLink : public ITextLink {
TEXT_LINK_CLASS(SaveMsgLink)
public:
SaveMsgLink(MediaView *view) : _view(view) {
@@ -134,19 +136,19 @@ void MediaView::moveToScreen() {
}
int32 navSkip = 2 * st::mvControlMargin + st::mvControlSize;
_closeNav = rtlrect(width() - st::mvControlMargin - st::mvControlSize, st::mvControlMargin, st::mvControlSize, st::mvControlSize, width());
_closeNav = myrtlrect(width() - st::mvControlMargin - st::mvControlSize, st::mvControlMargin, st::mvControlSize, st::mvControlSize);
_closeNavIcon = centersprite(_closeNav, st::mvClose);
_leftNav = rtlrect(st::mvControlMargin, navSkip, st::mvControlSize, height() - 2 * navSkip, width());
_leftNav = myrtlrect(st::mvControlMargin, navSkip, st::mvControlSize, height() - 2 * navSkip);
_leftNavIcon = centersprite(_leftNav, st::mvLeft);
_rightNav = rtlrect(width() - st::mvControlMargin - st::mvControlSize, navSkip, st::mvControlSize, height() - 2 * navSkip, width());
_rightNav = myrtlrect(width() - st::mvControlMargin - st::mvControlSize, navSkip, st::mvControlSize, height() - 2 * navSkip);
_rightNavIcon = centersprite(_rightNav, st::mvRight);
_saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2);
}
void MediaView::mediaOverviewUpdated(PeerData *peer) {
void MediaView::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
if (!_photo && !_doc) return;
if (_history && _history->peer == peer) {
if (_history && _history->peer == peer && type == _overview) {
_index = -1;
for (int i = 0, l = _history->_overview[_overview].size(); i < l; ++i) {
if (_history->_overview[_overview].at(i) == _msgid) {
@@ -156,7 +158,7 @@ void MediaView::mediaOverviewUpdated(PeerData *peer) {
}
updateControls();
preloadData(0);
} else if (_user == peer) {
} else if (_user == peer && type == OverviewCount) {
if (!_photo) return;
_index = -1;
@@ -190,7 +192,7 @@ void MediaView::changingMsgId(HistoryItem *row, MsgId newId) {
if (row->id == _msgid) {
_msgid = newId;
}
mediaOverviewUpdated(row->history()->peer);
mediaOverviewUpdated(row->history()->peer, _overview);
}
void MediaView::updateDocSize() {
@@ -256,9 +258,9 @@ void MediaView::updateControls() {
}
_saveVisible = ((_photo && _photo->full->loaded()) || (_doc && (!_doc->already(true).isEmpty() || (_current.isNull() && _currentGif.isNull()))));
_saveNav = rtlrect(width() - st::mvIconSize.width() * 2, height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height(), width());
_saveNav = myrtlrect(width() - st::mvIconSize.width() * 2, height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height());
_saveNavIcon = centersprite(_saveNav, st::mvSave);
_moreNav = rtlrect(width() - st::mvIconSize.width(), height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height(), width());
_moreNav = myrtlrect(width() - st::mvIconSize.width(), height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height());
_moreNavIcon = centersprite(_moreNav, st::mvMore);
QDateTime d(date(_photo ? _photo->date : _doc->date)), dNow(date(unixtime()));
@@ -271,11 +273,11 @@ void MediaView::updateControls() {
}
if (_from) {
_fromName.setText(st::mvFont, _from->name);
_nameNav = rtlrect(st::mvTextLeft, height() - st::mvTextTop, qMin(_fromName.maxWidth(), width() / 3), st::mvFont->height, width());
_dateNav = rtlrect(st::mvTextLeft + _nameNav.width() + st::mvTextSkip, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height, width());
_nameNav = myrtlrect(st::mvTextLeft, height() - st::mvTextTop, qMin(_fromName.maxWidth(), width() / 3), st::mvFont->height);
_dateNav = myrtlrect(st::mvTextLeft + _nameNav.width() + st::mvTextSkip, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height);
} else {
_nameNav = QRect();
_dateNav = rtlrect(st::mvTextLeft, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height, width());
_dateNav = myrtlrect(st::mvTextLeft, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height);
}
updateHeader();
if (_photo) {
@@ -347,7 +349,6 @@ bool MediaView::animStep(float64 msp) {
a_cOpacity.finish();
_controlsState = (_controlsState == ControlsShowing ? ControlsShown : ControlsHidden);
setCursor(_controlsState == ControlsHidden ? Qt::BlankCursor : (_over == OverNone ? style::cur_default : style::cur_pointer));
LOG(("Finished with controls!"));
} else {
a_cOpacity.update(dt, anim::linear);
}
@@ -408,7 +409,6 @@ void MediaView::close() {
void MediaView::activateControls() {
_controlsHideTimer.start(int(st::mvWaitHide));
if (_controlsState == ControlsHiding || _controlsState == ControlsHidden) {
LOG(("Showing controls.."));
_controlsState = ControlsShowing;
_controlsAnimStarted = getms();
a_cOpacity.start(1);
@@ -419,7 +419,6 @@ void MediaView::activateControls() {
void MediaView::onHideControls(bool force) {
if (!force && !_dropdown.isHidden()) return;
if (_controlsState == ControlsHiding || _controlsState == ControlsHidden) return;
LOG(("Hiding controls.."));
_controlsState = ControlsHiding;
_controlsAnimStarted = getms();
a_cOpacity.start(0);
@@ -680,7 +679,7 @@ void MediaView::showPhoto(PhotoData *photo, PeerData *context) {
_photo = photo;
_overview = OverviewCount;
if (_user) {
if (_user->photos.isEmpty() && _user->photosCount < 0 && _user->photoId) {
if (_user->photos.isEmpty() && _user->photosCount < 0 && _user->photoId && _user->photoId != UnknownPeerPhotoId) {
_index = 0;
}
for (int i = 0, l = _user->photos.size(); i < l; ++i) {
@@ -798,9 +797,9 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) {
_caption = Text();
QString already = _doc->already(true);
if (_doc->sticker && !_doc->sticker->img->isNull() && _doc->sticker->img->loaded()) {
if (_doc->sticker() && !_doc->sticker()->img->isNull() && _doc->sticker()->img->loaded()) {
_currentGif.stop();
_current = _doc->sticker->img->pix();
_current = _doc->sticker()->img->pix();
} else if (!already.isEmpty()) {
QImageReader reader(already);
if (reader.canRead()) {
@@ -826,33 +825,33 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) {
style::sprite thumbs[] = { st::mvDocBlue, st::mvDocGreen, st::mvDocRed, st::mvDocYellow };
style::color colors[] = { st::mvDocBlueColor, st::mvDocGreenColor, st::mvDocRedColor, st::mvDocYellowColor };
QString name = _doc->name.toLower(), mime = _doc->mime.toLower();
if (name.endsWith(QLatin1String(".doc")) ||
name.endsWith(QLatin1String(".txt")) ||
name.endsWith(QLatin1String(".psd")) ||
mime.startsWith(QLatin1String("text/"))
if (name.endsWith(qstr(".doc")) ||
name.endsWith(qstr(".txt")) ||
name.endsWith(qstr(".psd")) ||
mime.startsWith(qstr("text/"))
) {
_docIcon = thumbs[0];
_docIconColor = colors[0];
} else if (
name.endsWith(QLatin1String(".xls")) ||
name.endsWith(QLatin1String(".csv"))
name.endsWith(qstr(".xls")) ||
name.endsWith(qstr(".csv"))
) {
_docIcon = thumbs[1];
_docIconColor = colors[1];
} else if (
name.endsWith(QLatin1String(".pdf")) ||
name.endsWith(QLatin1String(".ppt")) ||
name.endsWith(QLatin1String(".key"))
name.endsWith(qstr(".pdf")) ||
name.endsWith(qstr(".ppt")) ||
name.endsWith(qstr(".key"))
) {
_docIcon = thumbs[2];
_docIconColor = colors[2];
} else if (
name.endsWith(QLatin1String(".zip")) ||
name.endsWith(QLatin1String(".rar")) ||
name.endsWith(QLatin1String(".ai")) ||
name.endsWith(QLatin1String(".mp3")) ||
name.endsWith(QLatin1String(".mov")) ||
name.endsWith(QLatin1String(".avi"))
name.endsWith(qstr(".zip")) ||
name.endsWith(qstr(".rar")) ||
name.endsWith(qstr(".ai")) ||
name.endsWith(qstr(".mp3")) ||
name.endsWith(qstr(".mov")) ||
name.endsWith(qstr(".avi"))
) {
_docIcon = thumbs[3];
_docIconColor = colors[3];
@@ -904,7 +903,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) {
// _docSize is updated in updateControls()
_docRect = QRect((width() - st::mvDocSize.width()) / 2, (height() - st::mvDocSize.height()) / 2, st::mvDocSize.width(), st::mvDocSize.height());
_docIconRect = rtlrect(_docRect.x() + st::mvDocPadding, _docRect.y() + st::mvDocPadding, st::mvDocBlue.pxWidth(), st::mvDocBlue.pxHeight(), width());
_docIconRect = myrtlrect(_docRect.x() + st::mvDocPadding, _docRect.y() + st::mvDocPadding, st::mvDocBlue.pxWidth(), st::mvDocBlue.pxHeight());
} else if (!_current.isNull()) {
_current.setDevicePixelRatio(cRetinaFactor());
_w = _current.width() / cIntRetinaFactor();
@@ -1008,7 +1007,7 @@ void MediaView::paintEvent(QPaintEvent *e) {
QRect imgRect(_x, _y, _w, _h);
const QPixmap *toDraw = _currentGif.isNull() ? &_current : &_currentGif.current(_currentGif.w, _currentGif.h, false);
if (imgRect.intersects(r)) {
if (toDraw->hasAlpha() && (!_doc || !_doc->sticker || _doc->sticker->img->isNull())) {
if (toDraw->hasAlpha() && (!_doc || !_doc->sticker() || _doc->sticker()->img->isNull())) {
p.fillRect(imgRect, _transparentBrush);
}
if (_zoom) {
@@ -1262,11 +1261,6 @@ void MediaView::paintEvent(QPaintEvent *e) {
}
}
}
// static uint64 t = getms();
// uint64 t2 = getms();
// LOG(("paint: %1, wait: %2, name: %3, icon: %4").arg(t2 - ms).arg(t2 - t).arg(logBool(name)).arg(logBool(icon)));
// t = t2;
}
void MediaView::keyPressEvent(QKeyEvent *e) {
@@ -1413,7 +1407,7 @@ void MediaView::preloadData(int32 delta) {
switch (media->type()) {
case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->full->load(); break;
case MediaTypeDocument: static_cast<HistoryDocument*>(media)->document()->thumb->load(); break;
case MediaTypeSticker: static_cast<HistorySticker*>(media)->document()->sticker->img->load(); break;
case MediaTypeSticker: static_cast<HistorySticker*>(media)->document()->sticker()->img->load(); break;
}
}
}
@@ -1826,7 +1820,7 @@ void MediaView::findCurrent() {
}
}
if (_history->_overviewCount[_overview] < 0) {
if (_history->_overviewCount[_overview] < 0 || (!_index && _history->_overviewCount[_overview] > 0)) {
loadBack();
}
}
@@ -1875,7 +1869,7 @@ void MediaView::userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mt
photo->thumb->load();
u->photos.push_back(photo);
}
if (App::wnd()) App::wnd()->mediaOverviewUpdated(u);
if (App::wnd()) App::wnd()->mediaOverviewUpdated(u, OverviewCount);
}
void MediaView::updateHeader() {
@@ -1911,7 +1905,7 @@ void MediaView::updateHeader() {
hwidth = width() / 3;
_headerText = st::mvThickFont->m.elidedText(_headerText, Qt::ElideMiddle, hwidth);
}
_headerNav = rtlrect(st::mvTextLeft, height() - st::mvHeaderTop, hwidth, st::mvThickFont->height, width());
_headerNav = myrtlrect(st::mvTextLeft, height() - st::mvHeaderTop, hwidth, st::mvThickFont->height);
}
//
//void MediaView::updatePolaroid() {

View File

@@ -55,7 +55,7 @@ public:
updateOver(mapFromGlobal(QCursor::pos()));
}
void mediaOverviewUpdated(PeerData *peer);
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
void documentUpdated(DocumentData *doc);
void changingMsgId(HistoryItem *row, MsgId newId);
void updateDocSize();

View File

@@ -606,7 +606,7 @@ void MTPabstractTcpConnection::socketRead() {
}
MTPautoConnection::MTPautoConnection(QThread *thread) : status(WaitingBoth),
tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()), _tcpTimeout(MTPMinReceiveDelay) {
tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()), _tcpTimeout(MTPMinReceiveDelay), _flags(0) {
moveToThread(thread);
manager.moveToThread(thread);
@@ -615,6 +615,7 @@ tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()), _tcpTimeo
httpStartTimer.moveToThread(thread);
httpStartTimer.setSingleShot(true);
connect(&httpStartTimer, SIGNAL(timeout()), this, SLOT(onHttpStart()));
tcpTimeoutTimer.moveToThread(thread);
tcpTimeoutTimer.setSingleShot(true);
connect(&tcpTimeoutTimer, SIGNAL(timeout()), this, SLOT(onTcpTimeoutTimer()));
@@ -628,7 +629,7 @@ tcpNonce(MTP::nonce<MTPint128>()), httpNonce(MTP::nonce<MTPint128>()), _tcpTimeo
void MTPautoConnection::onHttpStart() {
if (status == HttpReady) {
DEBUG_LOG(("Connection Info: Http-transport chosen by timer"));
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by timer").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
status = UsingHttp;
sock.disconnectFromHost();
emit connected();
@@ -639,7 +640,7 @@ void MTPautoConnection::onSocketConnected() {
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
mtpBuffer buffer(_preparePQFake(tcpNonce));
DEBUG_LOG(("Connection Info: sending fake req_pq through tcp transport"));
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP/%1 transport").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
tcpTimeoutTimer.start(_tcpTimeout);
@@ -677,7 +678,7 @@ void MTPautoConnection::onSocketDisconnected() {
} else if (status == WaitingTcp || status == UsingTcp) {
emit disconnected();
} else if (status == HttpReady) {
DEBUG_LOG(("Connection Info: Http-transport chosen by socket disconnect"));
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by socket disconnect").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
status = UsingHttp;
emit connected();
}
@@ -724,6 +725,7 @@ void MTPautoConnection::httpSend(mtpBuffer &buffer) {
void MTPautoConnection::disconnectFromServer() {
if (status == FinishedWork) return;
status = FinishedWork;
Requests copy = requests;
requests.clear();
@@ -740,7 +742,6 @@ void MTPautoConnection::disconnectFromServer() {
sock.close();
httpStartTimer.stop();
status = FinishedWork;
}
void MTPautoConnection::connectToServer(const QString &addr, int32 port, int32 flags) {
@@ -750,19 +751,20 @@ void MTPautoConnection::connectToServer(const QString &addr, int32 port, int32 f
_addr = addr;
_port = port;
_flags = flags;
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
sock.connectToHost(QHostAddress(_addr), _port);
mtpBuffer buffer(_preparePQFake(httpNonce));
DEBUG_LOG(("Connection Info: sending fake req_pq through http transport"));
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
httpSend(buffer);
}
bool MTPautoConnection::isConnected() {
return status != FinishedWork && !address.isEmpty();
bool MTPautoConnection::isConnected() const {
return (status == UsingTcp) || (status == UsingHttp);
}
void MTPautoConnection::requestFinished(QNetworkReply *reply) {
@@ -792,13 +794,14 @@ void MTPautoConnection::requestFinished(QNetworkReply *reply) {
status = HttpReady;
httpStartTimer.start(MTPTcpConnectionWaitTimeout);
} else {
DEBUG_LOG(("Connection Info: Http-transport chosen by pq-response, awaited"));
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by pq-response, awaited").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
status = UsingHttp;
sock.disconnectFromHost();
emit connected();
}
}
} catch (Exception &e) {
DEBUG_LOG(("Connection Error: exception in parsing HTTP fake pq-responce, %1").arg(e.what()));
if (status == WaitingBoth) {
status = WaitingTcp;
} else {
@@ -834,7 +837,7 @@ void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) {
status = WaitingHttp;
sock.disconnectFromHost();
} else if (status == HttpReady) {
DEBUG_LOG(("Connection Info: Http-transport chosen by bad tcp response, ready"));
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by bad tcp response, ready").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
status = UsingHttp;
sock.disconnectFromHost();
emit connected();
@@ -853,16 +856,17 @@ void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) {
MTPResPQ res_pq = _readPQFakeReply(data);
const MTPDresPQ &res_pq_data(res_pq.c_resPQ());
if (res_pq_data.vnonce == tcpNonce) {
DEBUG_LOG(("Connection Info: Tcp-transport chosen by pq-response"));
DEBUG_LOG(("Connection Info: TCP/%1-transport chosen by pq-response").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
status = UsingTcp;
emit connected();
}
} catch (Exception &e) {
DEBUG_LOG(("Connection Error: exception in parsing TCP fake pq-responce, %1").arg(e.what()));
if (status == WaitingBoth) {
status = WaitingHttp;
sock.disconnectFromHost();
} else if (status == HttpReady) {
DEBUG_LOG(("Connection Info: Http-transport chosen by bad tcp response, awaited"));
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by bad tcp response, awaited").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
status = UsingHttp;
sock.disconnectFromHost();
emit connected();
@@ -902,7 +906,7 @@ void MTPautoConnection::socketError(QAbstractSocket::SocketError e) {
if (status == WaitingBoth) {
status = WaitingHttp;
} else if (status == HttpReady) {
DEBUG_LOG(("Connection Info: Http-transport chosen by tcp error, ready"));
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by tcp error, ready").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
status = UsingHttp;
emit connected();
} else if (status == WaitingTcp || status == UsingTcp) {
@@ -912,16 +916,64 @@ void MTPautoConnection::socketError(QAbstractSocket::SocketError e) {
}
}
MTPtcpConnection::MTPtcpConnection(QThread *thread) {
MTPtcpConnection::MTPtcpConnection(QThread *thread) : status(WaitingTcp),
tcpNonce(MTP::nonce<MTPint128>()), _tcpTimeout(MTPMinReceiveDelay), _flags(0) {
moveToThread(thread);
tcpTimeoutTimer.moveToThread(thread);
tcpTimeoutTimer.setSingleShot(true);
connect(&tcpTimeoutTimer, SIGNAL(timeout()), this, SLOT(onTcpTimeoutTimer()));
sock.moveToThread(thread);
App::setProxySettings(sock);
connect(&sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
connect(&sock, SIGNAL(connected()), this, SIGNAL(connected()));
connect(&sock, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
connect(&sock, SIGNAL(connected()), this, SLOT(onSocketConnected()));
connect(&sock, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
}
void MTPtcpConnection::onSocketConnected() {
if (status == WaitingTcp) {
mtpBuffer buffer(_preparePQFake(tcpNonce));
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP/%1 transport").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
tcpTimeoutTimer.start(_tcpTimeout);
sendData(buffer);
}
}
void MTPtcpConnection::onTcpTimeoutTimer() {
if (status == WaitingTcp) {
if (_tcpTimeout < MTPMaxReceiveDelay) _tcpTimeout *= 2;
_tcpTimeout = -_tcpTimeout;
QAbstractSocket::SocketState state = sock.state();
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
sock.disconnectFromHost();
} else if (state != QAbstractSocket::ClosingState) {
sock.connectToHost(QHostAddress(_addr), _port);
}
}
}
void MTPtcpConnection::onSocketDisconnected() {
if (_tcpTimeout < 0) {
_tcpTimeout = -_tcpTimeout;
if (status == WaitingTcp) {
sock.connectToHost(QHostAddress(_addr), _port);
return;
}
}
if (status == WaitingTcp || status == UsingTcp) {
emit disconnected();
}
}
void MTPtcpConnection::sendData(mtpBuffer &buffer) {
if (status == FinishedWork) return;
if (buffer.size() < 3) {
LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime)));
TCP_LOG(("TCP Error: bad packet %1").arg(mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str()));
@@ -940,28 +992,51 @@ void MTPtcpConnection::sendData(mtpBuffer &buffer) {
}
void MTPtcpConnection::disconnectFromServer() {
if (status == FinishedWork) return;
status = FinishedWork;
disconnect(&sock, SIGNAL(readyRead()), 0, 0);
sock.close();
}
void MTPtcpConnection::connectToServer(const QString &addr, int32 port, int32 flags) {
_addr = addr;
_port = port;
_flags = flags;
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
sock.connectToHost(QHostAddress(addr), port);
sock.connectToHost(QHostAddress(_addr), _port);
}
void MTPtcpConnection::socketPacket(mtpPrime *packet, uint32 size) {
if (status == FinishedWork) return;
mtpBuffer data = _handleTcpResponse(packet, size);
if (data.size() == 1) {
bool mayBeBadKey = (data[0] == -404) && _sentEncrypted;
emit error(mayBeBadKey);
} else if (status == UsingTcp) {
receivedQueue.push_back(data);
emit receivedData();
} else if (status == WaitingTcp) {
tcpTimeoutTimer.stop();
try {
MTPResPQ res_pq = _readPQFakeReply(data);
const MTPDresPQ &res_pq_data(res_pq.c_resPQ());
if (res_pq_data.vnonce == tcpNonce) {
DEBUG_LOG(("Connection Info: TCP/%1-transport chosen by pq-response").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
status = UsingTcp;
emit connected();
}
} catch (Exception &e) {
DEBUG_LOG(("Connection Error: exception in parsing TCP fake pq-responce, %1").arg(e.what()));
emit error();
}
}
receivedQueue.push_back(data);
emit receivedData();
}
bool MTPtcpConnection::isConnected() {
return sock.state() == QAbstractSocket::ConnectedState;
bool MTPtcpConnection::isConnected() const {
return (status == UsingTcp);
}
int32 MTPtcpConnection::debugState() const {
@@ -969,21 +1044,25 @@ int32 MTPtcpConnection::debugState() const {
}
QString MTPtcpConnection::transport() const {
return qsl("TCP");
return isConnected() ? qsl("TCP") : QString();
}
void MTPtcpConnection::socketError(QAbstractSocket::SocketError e) {
if (status == FinishedWork) return;
_handleTcpError(e, sock);
emit error();
}
MTPhttpConnection::MTPhttpConnection(QThread *thread) {
MTPhttpConnection::MTPhttpConnection(QThread *thread) : status(WaitingHttp), httpNonce(MTP::nonce<MTPint128>()), _flags(0) {
moveToThread(thread);
manager.moveToThread(thread);
App::setProxySettings(manager);
}
void MTPhttpConnection::sendData(mtpBuffer &buffer) {
if (status == FinishedWork) return;
if (buffer.size() < 3) {
LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime)));
TCP_LOG(("TCP Error: bad packet %1").arg(mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str()));
@@ -1002,6 +1081,9 @@ void MTPhttpConnection::sendData(mtpBuffer &buffer) {
}
void MTPhttpConnection::disconnectFromServer() {
if (status == FinishedWork) return;
status = FinishedWork;
Requests copy = requests;
requests.clear();
for (Requests::const_iterator i = copy.cbegin(), e = copy.cend(); i != e; ++i) {
@@ -1018,14 +1100,23 @@ void MTPhttpConnection::connectToServer(const QString &addr, int32 p, int32 flag
address = QUrl(((flags & MTPDdcOption_flag_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(addr).arg(80));//not p - always 80 port for http transport
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
emit connected();
_flags = flags;
mtpBuffer buffer(_preparePQFake(httpNonce));
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
sendData(buffer);
}
bool MTPhttpConnection::isConnected() {
return !address.isEmpty();
bool MTPhttpConnection::isConnected() const {
return (status == UsingHttp);
}
void MTPhttpConnection::requestFinished(QNetworkReply *reply) {
if (status == FinishedWork) return;
reply->deleteLater();
if (reply->error() == QNetworkReply::NoError) {
requests.remove(reply);
@@ -1034,8 +1125,23 @@ void MTPhttpConnection::requestFinished(QNetworkReply *reply) {
if (data.size() == 1) {
emit error();
} else if (!data.isEmpty()) {
receivedQueue.push_back(data);
emit receivedData();
if (status == UsingHttp) {
receivedQueue.push_back(data);
emit receivedData();
} else {
try {
MTPResPQ res_pq = _readPQFakeReply(data);
const MTPDresPQ &res_pq_data(res_pq.c_resPQ());
if (res_pq_data.vnonce == httpNonce) {
DEBUG_LOG(("Connection Info: HTTP/%1-transport connected by pq-response").arg((_flags & MTPDdcOption_flag_ipv6) ? "IPv6" : "IPv4"));
status = UsingHttp;
emit connected();
}
} catch (Exception &e) {
DEBUG_LOG(("Connection Error: exception in parsing HTTP fake pq-responce, %1").arg(e.what()));
emit error();
}
}
}
} else {
if (!requests.remove(reply)) {
@@ -1061,12 +1167,17 @@ int32 MTPhttpConnection::debugState() const {
}
QString MTPhttpConnection::transport() const {
return qsl("HTTP");
if (status == UsingHttp) {
return qsl("HTTP");
} else {
return QString();
}
}
void MTProtoConnectionPrivate::createConn(bool createIPv4, bool createIPv6) {
destroyConn();
if (createIPv4) {
QWriteLocker lock(&stateConnMutex);
if (cConnectionType() == dbictAuto) {
_conn4 = new MTPautoConnection(thread());
} else if (cConnectionType() == dbictTcpProxy) {
@@ -1078,6 +1189,7 @@ void MTProtoConnectionPrivate::createConn(bool createIPv4, bool createIPv6) {
connect(_conn4, SIGNAL(receivedSome()), this, SLOT(onReceivedSome()));
}
if (createIPv6) {
QWriteLocker lock(&stateConnMutex);
if (cConnectionType() == dbictAuto) {
_conn6 = new MTPautoConnection(thread());
} else if (cConnectionType() == dbictTcpProxy) {
@@ -1098,14 +1210,23 @@ void MTProtoConnectionPrivate::createConn(bool createIPv4, bool createIPv6) {
void MTProtoConnectionPrivate::destroyConn(MTPabstractConnection **conn) {
if (conn) {
if (*conn) {
disconnect(*conn, SIGNAL(disconnected()), 0, 0);
disconnect(*conn, SIGNAL(receivedData()), 0, 0);
disconnect(*conn, SIGNAL(receivedSome()), 0, 0);
MTPabstractConnection *toDisconnect = 0;
(*conn)->disconnectFromServer();
(*conn)->deleteLater();
*conn = 0;
{
QWriteLocker lock(&stateConnMutex);
if (*conn) {
toDisconnect = *conn;
disconnect(*conn, SIGNAL(connected()), 0, 0);
disconnect(*conn, SIGNAL(disconnected()), 0, 0);
disconnect(*conn, SIGNAL(error(bool)), 0, 0);
disconnect(*conn, SIGNAL(receivedData()), 0, 0);
disconnect(*conn, SIGNAL(receivedSome()), 0, 0);
*conn = 0;
}
}
if (toDisconnect) {
toDisconnect->disconnectFromServer();
toDisconnect->deleteLater();
}
} else {
destroyConn(&_conn4);
@@ -1200,7 +1321,7 @@ int32 MTProtoConnectionPrivate::getDC() const {
}
int32 MTProtoConnectionPrivate::getState() const {
QReadLocker lock(&stateMutex);
QReadLocker lock(&stateConnMutex);
int32 result = _state;
if (_state < 0) {
if (retryTimer.isActive()) {
@@ -1214,18 +1335,21 @@ int32 MTProtoConnectionPrivate::getState() const {
}
QString MTProtoConnectionPrivate::transport() const {
if ((!_conn4 && !_conn6) || _state < 0) {
QReadLocker lock(&stateConnMutex);
if ((!_conn4 && !_conn6) || (_conn4 && _conn6) || (_state < 0)) {
return QString();
}
return (_conn4 ? _conn4 : _conn6)->transport();
QString result = (_conn4 ? _conn4 : _conn6)->transport();
if (!result.isEmpty() && cTryIPv6()) result += (_conn4 ? "/IPv4" : "/IPv6");
return result;
}
bool MTProtoConnectionPrivate::setState(int32 state, int32 ifState) {
if (ifState != MTProtoConnection::UpdateAlways) {
QReadLocker lock(&stateMutex);
QReadLocker lock(&stateConnMutex);
if (_state != ifState) return false;
}
QWriteLocker lock(&stateMutex);
QWriteLocker lock(&stateConnMutex);
if (_state == state) return false;
_state = state;
if (state < 0) {
@@ -1784,15 +1908,15 @@ void MTProtoConnectionPrivate::socketStart(bool afterConfig) {
port6 = dcIndex6->port;
}
}
bool noIPv4 = (!port4 || ip4.empty()), noIPv6 = (!port6 || ip6.empty());
bool noIPv4 = (!port4 || ip4.empty()), noIPv6 = (!cTryIPv6() || !port6 || ip6.empty());
if (noIPv4 && noIPv6) {
if (afterConfig) {
if (noIPv4) LOG(("MTP Error: DC %1 options for IPv4 not found right after config load!").arg(dc));
if (noIPv6) LOG(("MTP Error: DC %1 options for IPv6 not found right after config load!").arg(dc));
if (cTryIPv6() && noIPv6) LOG(("MTP Error: DC %1 options for IPv6 not found right after config load!").arg(dc));
return restart();
}
if (noIPv4) DEBUG_LOG(("MTP Info: DC %1 options for IPv4 not found, waiting for config").arg(dc));
if (noIPv6) DEBUG_LOG(("MTP Info: DC %1 options for IPv6 not found, waiting for config").arg(dc));
if (cTryIPv6() && noIPv6) DEBUG_LOG(("MTP Info: DC %1 options for IPv6 not found, waiting for config").arg(dc));
connect(mtpConfigLoader(), SIGNAL(loaded()), this, SLOT(onConfigLoaded()));
mtpConfigLoader()->load();
return;
@@ -2916,7 +3040,7 @@ void MTProtoConnectionPrivate::onConnected6() {
QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData) return;
disconnect(_conn6, SIGNAL(connected()), this, SLOT(onConnected()));
disconnect(_conn6, SIGNAL(connected()), this, SLOT(onConnected6()));
if (!_conn6->isConnected()) {
LOG(("Connection Error: not connected in onConnected(), state: %1").arg(_conn6->debugState()));
return restart();
@@ -3479,7 +3603,7 @@ void MTProtoConnectionPrivate::sendRequestNotSecure(const TRequest &request) {
onSentSome(buffer.size() * sizeof(mtpPrime));
} catch(Exception &e) {
} catch (Exception &e) {
return restart();
}
}
@@ -3516,7 +3640,7 @@ bool MTProtoConnectionPrivate::readResponseNotSecure(TResponse &response) {
}
const mtpPrime *from(answer + 5), *end(from + len - 5);
response.read(from, end);
} catch(Exception &e) {
} catch (Exception &e) {
return false;
}
return true;

View File

@@ -43,7 +43,12 @@ enum {
MTPDreplyKeyboardMarkup_flag_single_use = (1 << 1),
MTPDreplyKeyboardMarkup_flag_personal = (1 << 2),
MTPDreplyKeyboardMarkup_flag_FORCE_REPLY = (1 << 30), // client side flag for forceReply
MTPDreplyKeyboardMarkup_flag_ZERO = (1 << 31) // client side flag for zeroMarkup
MTPDreplyKeyboardMarkup_flag_ZERO = (1 << 31), // client side flag for zeroMarkup
MTPDstickerSet_flag_installed = (1 << 0),
MTPDstickerSet_flag_disabled = (1 << 1),
MTPDstickerSet_flag_official = (1 << 2),
MTPDstickerSet_flag_NOT_LOADED = (1 << 31), // client side flag for not yet loaded set
};
static const MTPReplyMarkup MTPnullMarkup = MTP_replyKeyboardMarkup(MTP_int(0), MTP_vector<MTPKeyboardButtonRow>(0));
@@ -141,7 +146,7 @@ public:
virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32
virtual void disconnectFromServer() = 0;
virtual void connectToServer(const QString &addr, int32 port, int32 flags) = 0;
virtual bool isConnected() = 0;
virtual bool isConnected() const = 0;
virtual bool usingHttpWait() {
return false;
}
@@ -209,7 +214,7 @@ public:
void sendData(mtpBuffer &buffer);
void disconnectFromServer();
void connectToServer(const QString &addr, int32 port, int32 flags);
bool isConnected();
bool isConnected() const;
bool usingHttpWait();
bool needHttpWait();
@@ -256,7 +261,7 @@ private:
Requests requests;
QString _addr;
int32 _port, _tcpTimeout;
int32 _port, _tcpTimeout, _flags;
QTimer tcpTimeoutTimer;
};
@@ -271,7 +276,7 @@ public:
void sendData(mtpBuffer &buffer);
void disconnectFromServer();
void connectToServer(const QString &addr, int32 port, int32 flags);
bool isConnected();
bool isConnected() const;
int32 debugState() const;
@@ -281,10 +286,29 @@ public slots:
void socketError(QAbstractSocket::SocketError e);
void onSocketConnected();
void onSocketDisconnected();
void onTcpTimeoutTimer();
protected:
void socketPacket(mtpPrime *packet, uint32 packetSize);
private:
enum Status {
WaitingTcp = 0,
UsingTcp,
FinishedWork
};
Status status;
MTPint128 tcpNonce;
QString _addr;
int32 _port, _tcpTimeout, _flags;
QTimer tcpTimeoutTimer;
};
class MTPhttpConnection : public MTPabstractConnection {
@@ -297,7 +321,7 @@ public:
void sendData(mtpBuffer &buffer);
void disconnectFromServer();
void connectToServer(const QString &addr, int32 port, int32 flags);
bool isConnected();
bool isConnected() const;
bool usingHttpWait();
bool needHttpWait();
@@ -311,6 +335,15 @@ public slots:
private:
enum Status {
WaitingHttp = 0,
UsingHttp,
FinishedWork
};
Status status;
MTPint128 httpNonce;
int32 _flags;
QNetworkAccessManager manager;
QUrl address;
@@ -414,7 +447,7 @@ private:
void clearMessages();
bool setState(int32 state, int32 ifState = MTProtoConnection::UpdateAlways);
mutable QReadWriteLock stateMutex;
mutable QReadWriteLock stateConnMutex;
int32 _state;
bool _needSessionReset;

View File

@@ -366,7 +366,7 @@ static const mtpTypeId mtpLayers[] = {
mtpc_invokeWithLayer17,
mtpc_invokeWithLayer18,
}, mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
static const mtpPrime mtpCurrentLayer = 31;
static const mtpPrime mtpCurrentLayer = 32;
template <typename bareT>
class MTPBoxed : public bareT {

View File

@@ -3887,6 +3887,8 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
}
switch (stage) {
case 0: to.add(" duration: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" performer: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
@@ -3949,9 +3951,7 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
}
switch (stage) {
case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" packs: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" sets: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" documents: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" sets: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
@@ -4262,10 +4262,13 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 6: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;
@@ -4885,6 +4888,7 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
}
switch (stage) {
case 0: to.add(" stickerset: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" disabled: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
break;

View File

@@ -338,13 +338,13 @@ enum {
mtpc_documentAttributeAnimated = 0x11b58939,
mtpc_documentAttributeSticker = 0x3a556302,
mtpc_documentAttributeVideo = 0x5910cccb,
mtpc_documentAttributeAudio = 0x51448e5,
mtpc_documentAttributeAudio = 0xded218e0,
mtpc_documentAttributeFilename = 0x15590068,
mtpc_messages_stickersNotModified = 0xf1749a22,
mtpc_messages_stickers = 0x8a8ecd32,
mtpc_stickerPack = 0x12b299d4,
mtpc_messages_allStickersNotModified = 0xe86602c3,
mtpc_messages_allStickers = 0x5ce352ec,
mtpc_messages_allStickers = 0xd51dafdb,
mtpc_disabledFeature = 0xae636f24,
mtpc_updateReadHistoryInbox = 0x9961fd5c,
mtpc_updateReadHistoryOutbox = 0x2f2f21bf,
@@ -377,7 +377,7 @@ enum {
mtpc_inputStickerSetEmpty = 0xffb62b95,
mtpc_inputStickerSetID = 0x9de7a269,
mtpc_inputStickerSetShortName = 0x861cc8a0,
mtpc_stickerSet = 0xa7a43b17,
mtpc_stickerSet = 0xcd303b41,
mtpc_messages_stickerSet = 0xb60a24a6,
mtpc_user = 0x22e49072,
mtpc_botCommand = 0xc27ac8c7,
@@ -513,7 +513,7 @@ enum {
mtpc_messages_checkChatInvite = 0x3eadb1bb,
mtpc_messages_importChatInvite = 0x6c50051c,
mtpc_messages_getStickerSet = 0x2619a90e,
mtpc_messages_installStickerSet = 0xefbbfae9,
mtpc_messages_installStickerSet = 0x7b30c3a6,
mtpc_messages_uninstallStickerSet = 0xf96e55de,
mtpc_messages_startBot = 0x1b3e0ffc
};
@@ -7146,7 +7146,7 @@ private:
friend MTPdocumentAttribute MTP_documentAttributeAnimated();
friend MTPdocumentAttribute MTP_documentAttributeSticker(const MTPstring &_alt, const MTPInputStickerSet &_stickerset);
friend MTPdocumentAttribute MTP_documentAttributeVideo(MTPint _duration, MTPint _w, MTPint _h);
friend MTPdocumentAttribute MTP_documentAttributeAudio(MTPint _duration);
friend MTPdocumentAttribute MTP_documentAttributeAudio(MTPint _duration, const MTPstring &_title, const MTPstring &_performer);
friend MTPdocumentAttribute MTP_documentAttributeFilename(const MTPstring &_file_name);
mtpTypeId _type;
@@ -7254,7 +7254,7 @@ private:
explicit MTPmessages_allStickers(MTPDmessages_allStickers *_data);
friend MTPmessages_allStickers MTP_messages_allStickersNotModified();
friend MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPStickerSet> &_sets, const MTPVector<MTPDocument> &_documents);
friend MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerSet> &_sets);
mtpTypeId _type;
};
@@ -7819,7 +7819,7 @@ public:
private:
explicit MTPstickerSet(MTPDstickerSet *_data);
friend MTPstickerSet MTP_stickerSet(const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_short_name);
friend MTPstickerSet MTP_stickerSet(MTPint _flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_short_name, MTPint _count, MTPint _hash);
};
typedef MTPBoxed<MTPstickerSet> MTPStickerSet;
@@ -10916,10 +10916,12 @@ class MTPDdocumentAttributeAudio : public mtpDataImpl<MTPDdocumentAttributeAudio
public:
MTPDdocumentAttributeAudio() {
}
MTPDdocumentAttributeAudio(MTPint _duration) : vduration(_duration) {
MTPDdocumentAttributeAudio(MTPint _duration, const MTPstring &_title, const MTPstring &_performer) : vduration(_duration), vtitle(_title), vperformer(_performer) {
}
MTPint vduration;
MTPstring vtitle;
MTPstring vperformer;
};
class MTPDdocumentAttributeFilename : public mtpDataImpl<MTPDdocumentAttributeFilename> {
@@ -10958,13 +10960,11 @@ class MTPDmessages_allStickers : public mtpDataImpl<MTPDmessages_allStickers> {
public:
MTPDmessages_allStickers() {
}
MTPDmessages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPStickerSet> &_sets, const MTPVector<MTPDocument> &_documents) : vhash(_hash), vpacks(_packs), vsets(_sets), vdocuments(_documents) {
MTPDmessages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerSet> &_sets) : vhash(_hash), vsets(_sets) {
}
MTPstring vhash;
MTPVector<MTPStickerPack> vpacks;
MTPVector<MTPStickerSet> vsets;
MTPVector<MTPDocument> vdocuments;
};
class MTPDdisabledFeature : public mtpDataImpl<MTPDdisabledFeature> {
@@ -11229,13 +11229,16 @@ class MTPDstickerSet : public mtpDataImpl<MTPDstickerSet> {
public:
MTPDstickerSet() {
}
MTPDstickerSet(const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_short_name) : vid(_id), vaccess_hash(_access_hash), vtitle(_title), vshort_name(_short_name) {
MTPDstickerSet(MTPint _flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_short_name, MTPint _count, MTPint _hash) : vflags(_flags), vid(_id), vaccess_hash(_access_hash), vtitle(_title), vshort_name(_short_name), vcount(_count), vhash(_hash) {
}
MTPint vflags;
MTPlong vid;
MTPlong vaccess_hash;
MTPstring vtitle;
MTPstring vshort_name;
MTPint vcount;
MTPint vhash;
};
class MTPDmessages_stickerSet : public mtpDataImpl<MTPDmessages_stickerSet> {
@@ -16920,26 +16923,29 @@ public:
class MTPmessages_installStickerSet { // RPC method 'messages.installStickerSet'
public:
MTPInputStickerSet vstickerset;
MTPBool vdisabled;
MTPmessages_installStickerSet() {
}
MTPmessages_installStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_installStickerSet) {
read(from, end, cons);
}
MTPmessages_installStickerSet(const MTPInputStickerSet &_stickerset) : vstickerset(_stickerset) {
MTPmessages_installStickerSet(const MTPInputStickerSet &_stickerset, MTPBool _disabled) : vstickerset(_stickerset), vdisabled(_disabled) {
}
uint32 innerLength() const {
return vstickerset.innerLength();
return vstickerset.innerLength() + vdisabled.innerLength();
}
mtpTypeId type() const {
return mtpc_messages_installStickerSet;
}
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_installStickerSet) {
vstickerset.read(from, end);
vdisabled.read(from, end);
}
void write(mtpBuffer &to) const {
vstickerset.write(to);
vdisabled.write(to);
}
typedef MTPBool ResponseType;
@@ -16952,7 +16958,7 @@ public:
}
MTPmessages_InstallStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_installStickerSet>(from, end, cons) {
}
MTPmessages_InstallStickerSet(const MTPInputStickerSet &_stickerset) : MTPBoxed<MTPmessages_installStickerSet>(MTPmessages_installStickerSet(_stickerset)) {
MTPmessages_InstallStickerSet(const MTPInputStickerSet &_stickerset, MTPBool _disabled) : MTPBoxed<MTPmessages_installStickerSet>(MTPmessages_installStickerSet(_stickerset, _disabled)) {
}
};
@@ -24857,7 +24863,7 @@ inline uint32 MTPdocumentAttribute::innerLength() const {
}
case mtpc_documentAttributeAudio: {
const MTPDdocumentAttributeAudio &v(c_documentAttributeAudio());
return v.vduration.innerLength();
return v.vduration.innerLength() + v.vtitle.innerLength() + v.vperformer.innerLength();
}
case mtpc_documentAttributeFilename: {
const MTPDdocumentAttributeFilename &v(c_documentAttributeFilename());
@@ -24897,6 +24903,8 @@ inline void MTPdocumentAttribute::read(const mtpPrime *&from, const mtpPrime *en
if (!data) setData(new MTPDdocumentAttributeAudio());
MTPDdocumentAttributeAudio &v(_documentAttributeAudio());
v.vduration.read(from, end);
v.vtitle.read(from, end);
v.vperformer.read(from, end);
} break;
case mtpc_documentAttributeFilename: _type = cons; {
if (!data) setData(new MTPDdocumentAttributeFilename());
@@ -24927,6 +24935,8 @@ inline void MTPdocumentAttribute::write(mtpBuffer &to) const {
case mtpc_documentAttributeAudio: {
const MTPDdocumentAttributeAudio &v(c_documentAttributeAudio());
v.vduration.write(to);
v.vtitle.write(to);
v.vperformer.write(to);
} break;
case mtpc_documentAttributeFilename: {
const MTPDdocumentAttributeFilename &v(c_documentAttributeFilename());
@@ -24967,8 +24977,8 @@ inline MTPdocumentAttribute MTP_documentAttributeSticker(const MTPstring &_alt,
inline MTPdocumentAttribute MTP_documentAttributeVideo(MTPint _duration, MTPint _w, MTPint _h) {
return MTPdocumentAttribute(new MTPDdocumentAttributeVideo(_duration, _w, _h));
}
inline MTPdocumentAttribute MTP_documentAttributeAudio(MTPint _duration) {
return MTPdocumentAttribute(new MTPDdocumentAttributeAudio(_duration));
inline MTPdocumentAttribute MTP_documentAttributeAudio(MTPint _duration, const MTPstring &_title, const MTPstring &_performer) {
return MTPdocumentAttribute(new MTPDdocumentAttributeAudio(_duration, _title, _performer));
}
inline MTPdocumentAttribute MTP_documentAttributeFilename(const MTPstring &_file_name) {
return MTPdocumentAttribute(new MTPDdocumentAttributeFilename(_file_name));
@@ -25058,7 +25068,7 @@ inline uint32 MTPmessages_allStickers::innerLength() const {
switch (_type) {
case mtpc_messages_allStickers: {
const MTPDmessages_allStickers &v(c_messages_allStickers());
return v.vhash.innerLength() + v.vpacks.innerLength() + v.vsets.innerLength() + v.vdocuments.innerLength();
return v.vhash.innerLength() + v.vsets.innerLength();
}
}
return 0;
@@ -25075,9 +25085,7 @@ inline void MTPmessages_allStickers::read(const mtpPrime *&from, const mtpPrime
if (!data) setData(new MTPDmessages_allStickers());
MTPDmessages_allStickers &v(_messages_allStickers());
v.vhash.read(from, end);
v.vpacks.read(from, end);
v.vsets.read(from, end);
v.vdocuments.read(from, end);
} break;
default: throw mtpErrorUnexpected(cons, "MTPmessages_allStickers");
}
@@ -25087,9 +25095,7 @@ inline void MTPmessages_allStickers::write(mtpBuffer &to) const {
case mtpc_messages_allStickers: {
const MTPDmessages_allStickers &v(c_messages_allStickers());
v.vhash.write(to);
v.vpacks.write(to);
v.vsets.write(to);
v.vdocuments.write(to);
} break;
}
}
@@ -25105,8 +25111,8 @@ inline MTPmessages_allStickers::MTPmessages_allStickers(MTPDmessages_allStickers
inline MTPmessages_allStickers MTP_messages_allStickersNotModified() {
return MTPmessages_allStickers(mtpc_messages_allStickersNotModified);
}
inline MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPStickerSet> &_sets, const MTPVector<MTPDocument> &_documents) {
return MTPmessages_allStickers(new MTPDmessages_allStickers(_hash, _packs, _sets, _documents));
inline MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerSet> &_sets) {
return MTPmessages_allStickers(new MTPDmessages_allStickers(_hash, _sets));
}
inline MTPdisabledFeature::MTPdisabledFeature() : mtpDataOwner(new MTPDdisabledFeature()) {
@@ -25777,7 +25783,7 @@ inline MTPstickerSet::MTPstickerSet() : mtpDataOwner(new MTPDstickerSet()) {
inline uint32 MTPstickerSet::innerLength() const {
const MTPDstickerSet &v(c_stickerSet());
return v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vtitle.innerLength() + v.vshort_name.innerLength();
return v.vflags.innerLength() + v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vtitle.innerLength() + v.vshort_name.innerLength() + v.vcount.innerLength() + v.vhash.innerLength();
}
inline mtpTypeId MTPstickerSet::type() const {
return mtpc_stickerSet;
@@ -25787,22 +25793,28 @@ inline void MTPstickerSet::read(const mtpPrime *&from, const mtpPrime *end, mtpT
if (!data) setData(new MTPDstickerSet());
MTPDstickerSet &v(_stickerSet());
v.vflags.read(from, end);
v.vid.read(from, end);
v.vaccess_hash.read(from, end);
v.vtitle.read(from, end);
v.vshort_name.read(from, end);
v.vcount.read(from, end);
v.vhash.read(from, end);
}
inline void MTPstickerSet::write(mtpBuffer &to) const {
const MTPDstickerSet &v(c_stickerSet());
v.vflags.write(to);
v.vid.write(to);
v.vaccess_hash.write(to);
v.vtitle.write(to);
v.vshort_name.write(to);
v.vcount.write(to);
v.vhash.write(to);
}
inline MTPstickerSet::MTPstickerSet(MTPDstickerSet *_data) : mtpDataOwner(_data) {
}
inline MTPstickerSet MTP_stickerSet(const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_short_name) {
return MTPstickerSet(new MTPDstickerSet(_id, _access_hash, _title, _short_name));
inline MTPstickerSet MTP_stickerSet(MTPint _flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_short_name, MTPint _count, MTPint _hash) {
return MTPstickerSet(new MTPDstickerSet(_flags, _id, _access_hash, _title, _short_name, _count, _hash));
}
inline MTPmessages_stickerSet::MTPmessages_stickerSet() : mtpDataOwner(new MTPDmessages_stickerSet()) {

View File

@@ -524,7 +524,7 @@ documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
documentAttributeAnimated#11b58939 = DocumentAttribute;
documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute;
documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
documentAttributeAudio#51448e5 duration:int = DocumentAttribute;
documentAttributeAudio#ded218e0 duration:int title:string performer:string = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
messages.stickersNotModified#f1749a22 = messages.Stickers;
@@ -533,7 +533,7 @@ messages.stickers#8a8ecd32 hash:string stickers:Vector<Document> = messages.Stic
stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
messages.allStickersNotModified#e86602c3 = messages.AllStickers;
messages.allStickers#5ce352ec hash:string packs:Vector<StickerPack> sets:Vector<StickerSet> documents:Vector<Document> = messages.AllStickers;
messages.allStickers#d51dafdb hash:string sets:Vector<StickerSet> = messages.AllStickers;
disabledFeature#ae636f24 feature:string description:string = DisabledFeature;
@@ -588,7 +588,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
stickerSet#a7a43b17 id:long access_hash:long title:string short_name:string = StickerSet;
stickerSet#cd303b41 flags:# id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
@@ -767,6 +767,6 @@ messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
messages.importChatInvite#6c50051c hash:string = Updates;
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
messages.installStickerSet#efbbfae9 stickerset:InputStickerSet = Bool;
messages.installStickerSet#7b30c3a6 stickerset:InputStickerSet disabled:Bool = Bool;
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
messages.startBot#1b3e0ffc bot:InputUser chat_id:int random_id:long start_param:string = Updates;

View File

@@ -40,13 +40,16 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const
, _photosInRow(1)
, _photosToAdd(0)
, _selMode(false)
, _width(0)
, _audioLeft(st::msgMargin.left())
, _audioWidth(st::msgMinWidth)
, _audioHeight(st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom())
, _width(st::wndMinWidth)
, _height(0)
, _minHeight(0)
, _addToY(0)
, _cursor(style::cur_default)
, _dragAction(NoDrag)
, _dragItem(0)
, _dragItem(0), _selectedMsgId(0)
, _dragItemIndex(-1)
, _mousedItem(0)
, _mousedItemIndex(-1)
@@ -65,6 +68,8 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const
, _touchTime(0)
, _menu(0) {
resize(_width, height());
App::contextItem(0);
_touchSelectTimer.setSingleShot(true);
@@ -75,6 +80,10 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const
mediaOverviewUpdated();
setMouseTracking(true);
if (_type == OverviewAudioDocuments) {
}
}
bool OverviewInner::event(QEvent *e) {
@@ -131,7 +140,7 @@ void OverviewInner::touchUpdateSpeed() {
void OverviewInner::fixItemIndex(int32 &current, MsgId msgId) const {
if (!msgId) {
current = -1;
} else if (_type == OverviewPhotos) {
} else if (_type == OverviewPhotos || _type == OverviewAudioDocuments) {
int32 l = _hist->_overview[_type].size();
if (current < 0 || current >= l || _hist->_overview[_type][current] != msgId) {
current = -1;
@@ -164,6 +173,10 @@ bool OverviewInner::itemHasPoint(MsgId msgId, int32 index, int32 x, int32 y) con
if (x >= 0 && x < _vsize && y >= 0 && y < _vsize) {
return true;
}
} else if (_type == OverviewAudioDocuments) {
if (x >= _audioLeft && x < _audioLeft + _audioWidth && y >= 0 && y < _audioHeight) {
return true;
}
} else {
HistoryItem *item = App::histItemById(msgId);
HistoryMedia *media = item ? item->getMedia(true) : 0;
@@ -183,6 +196,8 @@ bool OverviewInner::itemHasPoint(MsgId msgId, int32 index, int32 x, int32 y) con
int32 OverviewInner::itemHeight(MsgId msgId, int32 index) const {
if (_type == OverviewPhotos) {
return _vsize;
} else if (_type == OverviewAudioDocuments) {
return _audioHeight;
}
fixItemIndex(index, msgId);
@@ -198,7 +213,7 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32
}
index += delta;
if (_type == OverviewPhotos) {
if (_type == OverviewPhotos || _type == OverviewAudioDocuments) {
if (index < 0 || index >= _hist->_overview[_type].size()) {
msgId = 0;
index = -1;
@@ -232,6 +247,8 @@ void OverviewInner::updateMsg(MsgId itemId, int32 itemIndex) {
int32 vsize = (_vsize + st::overviewPhotoSkip);
int32 row = (_photosToAdd + itemIndex) / _photosInRow, col = (_photosToAdd + itemIndex) % _photosInRow;
update(int32(col * w), _addToY + int32(row * vsize), qCeil(w), vsize);
} else if (_type == OverviewAudioDocuments) {
update(_audioLeft, _addToY + int32(itemIndex * _audioHeight), _audioWidth, _audioHeight);
} else {
HistoryItem *item = App::histItemById(itemId);
HistoryMedia *media = item ? item->getMedia(true) : 0;
@@ -367,12 +384,11 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but
_dragStartPos = mapMouseToItem(mapFromGlobal(screenPos), _dragItem, _dragItemIndex);
_dragWasInactive = App::wnd()->inactivePress();
if (_dragWasInactive) App::wnd()->inactivePress(false);
bool textLink = textlnkDown() && !textlnkDown()->encoded().isEmpty();
if (textLink) {
if (textlnkDown() && _selected.isEmpty()) {
_dragAction = PrepareDrag;
} else if (!_selected.isEmpty()) {
if (_selected.cbegin().value() == FullItemSel) {
if (_selected.constFind(_dragItem) != _selected.cend() && App::hoveredItem()) {
if (_selected.constFind(_dragItem) != _selected.cend() && textlnkDown()) {
_dragAction = PrepareDrag; // start items drag
} else {
_dragAction = PrepareSelect; // start items select
@@ -382,23 +398,25 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but
if (_dragAction == NoDrag && _dragItem) {
bool afterDragSymbol = false , uponSymbol = false;
uint16 symbol = 0;
if (textlnkDown()) {
_dragSymbol = symbol;
uint32 selStatus = (_dragSymbol << 16) | _dragSymbol;
if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) {
if (!_selected.isEmpty()) {
updateMsg(_selected.cbegin().key(), -1);
_selected.clear();
if (!_dragWasInactive) {
if (textlnkDown()) {
_dragSymbol = symbol;
uint32 selStatus = (_dragSymbol << 16) | _dragSymbol;
if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) {
if (!_selected.isEmpty()) {
updateMsg(_selected.cbegin().key(), -1);
_selected.clear();
}
_selected.insert(_dragItem, selStatus);
_dragAction = Selecting;
updateMsg(_dragItem, _dragItemIndex);
_overview->updateTopBarSelection();
} else {
_dragAction = PrepareSelect;
}
_selected.insert(_dragItem, selStatus);
_dragAction = Selecting;
updateMsg(_dragItem, _dragItemIndex);
_overview->updateTopBarSelection();
} else {
_dragAction = PrepareSelect;
_dragAction = PrepareSelect; // start items select
}
} else {
_dragAction = PrepareSelect; // start items select
}
}
@@ -461,6 +479,11 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu
if (i != _selected.cend() && i.value() == FullItemSel) {
_selected.erase(i);
updateMsg(_dragItem, _dragItemIndex);
} else if (i == _selected.cend() && _dragItem > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) {
if (_selected.size() < MaxSelectedItems) {
_selected.insert(_dragItem, FullItemSel);
updateMsg(_dragItem, _dragItemIndex);
}
} else {
_selected.clear();
parentWidget()->update();
@@ -481,6 +504,73 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu
_overview->updateTopBarSelection();
}
void OverviewInner::onDragExec() {
if (_dragAction != Dragging) return;
bool uponSelected = false;
if (_dragItem) {
bool afterDragSymbol;
uint16 symbol;
if (!_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) {
uponSelected = _selected.contains(_dragItem);
} else {
uponSelected = false;
}
}
QString sel;
QList<QUrl> urls;
bool forwardSelected = false;
if (uponSelected) {
forwardSelected = !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel && cWideMode();
} else if (textlnkDown()) {
sel = textlnkDown()->encoded();
if (!sel.isEmpty() && sel.at(0) != '/' && sel.at(0) != '@' && sel.at(0) != '#') {
// urls.push_back(QUrl::fromEncoded(sel.toUtf8())); // Google Chrome crashes in Mac OS X O_o
}
}
if (!sel.isEmpty() || forwardSelected) {
updateDragSelection(0, -1, 0, -1, false);
_overview->noSelectingScroll();
QDrag *drag = new QDrag(App::wnd());
QMimeData *mimeData = new QMimeData;
if (!sel.isEmpty()) mimeData->setText(sel);
if (!urls.isEmpty()) mimeData->setUrls(urls);
if (forwardSelected) {
mimeData->setData(qsl("application/x-td-forward-selected"), "1");
}
drag->setMimeData(mimeData);
drag->exec(Qt::CopyAction);
return;
} else {
HistoryItem *pressedLnkItem = App::pressedLinkItem(), *pressedItem = App::pressedItem();
QLatin1String lnkType = (textlnkDown() && pressedLnkItem) ? textlnkDown()->type() : qstr("");
bool lnkPhoto = (lnkType == qstr("PhotoLink")),
lnkVideo = (lnkType == qstr("VideoOpenLink")),
lnkAudio = (lnkType == qstr("AudioOpenLink")),
lnkDocument = (lnkType == qstr("DocumentOpenLink"));
if (lnkPhoto || lnkVideo || lnkAudio || lnkDocument) {
QDrag *drag = new QDrag(App::wnd());
QMimeData *mimeData = new QMimeData;
mimeData->setData(qsl("application/x-td-forward-pressed-link"), "1");
if (lnkDocument) {
QString already = static_cast<DocumentOpenLink*>(textlnkDown().data())->document()->already(true);
if (!already.isEmpty()) {
QList<QUrl> urls;
urls.push_back(QUrl::fromLocalFile(already));
mimeData->setUrls(urls);
}
}
drag->setMimeData(mimeData);
drag->exec(Qt::CopyAction);
return;
}
}
}
void OverviewInner::touchScrollUpdated(const QPoint &screenPos) {
_touchPos = screenPos;
_overview->touchScroll(_touchPos - _touchPrevPos);
@@ -495,7 +585,7 @@ void OverviewInner::applyDragSelection() {
}
if (_dragSelecting) {
for (int32 i = _dragSelToIndex; i <= _dragSelFromIndex; ++i) {
MsgId msgid = (_type == OverviewPhotos) ? _hist->_overview[_type][i] : _items[i].msgid;
MsgId msgid = (_type == OverviewPhotos || _type == OverviewAudioDocuments) ? _hist->_overview[_type][i] : _items[i].msgid;
if (!msgid) continue;
SelectedItems::iterator j = _selected.find(msgid);
@@ -514,7 +604,7 @@ void OverviewInner::applyDragSelection() {
}
} else {
for (int32 i = _dragSelToIndex; i <= _dragSelFromIndex; ++i) {
MsgId msgid = (_type == OverviewPhotos) ? _hist->_overview[_type][i] : _items[i].msgid;
MsgId msgid = (_type == OverviewPhotos || _type == OverviewAudioDocuments) ? _hist->_overview[_type][i] : _items[i].msgid;
if (!msgid) continue;
SelectedItems::iterator j = _selected.find(msgid);
@@ -537,6 +627,8 @@ QPoint OverviewInner::mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex) {
float64 w = (_width - st::overviewPhotoSkip) / float64(_photosInRow);
p.setX(p.x() - int32(col * w) - st::overviewPhotoSkip);
p.setY(p.y() - _addToY - row * (_vsize + st::overviewPhotoSkip) - st::overviewPhotoSkip);
} else if (_type == OverviewAudioDocuments) {
p.setY(p.y() - _addToY - itemIndex * _audioHeight);
} else {
p.setY(p.y() - _addToY - (_height - _items[itemIndex].y));
}
@@ -547,6 +639,16 @@ void OverviewInner::clear() {
_cached.clear();
}
int32 OverviewInner::itemTop(MsgId msgId) const {
if (_type == OverviewAudioDocuments) {
int32 index = _hist->_overview[_type].indexOf(msgId);
if (index >= 0) {
return _addToY + int32(index * _audioHeight);
}
}
return -1;
}
QPixmap OverviewInner::genPix(PhotoData *photo, int32 size) {
size *= cIntRetinaFactor();
QImage img = (photo->full->loaded() ? photo->full : (photo->medium->loaded() ? photo->medium : photo->thumb))->pix().toImage();
@@ -672,6 +774,32 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
}
}
}
} else if (_type == OverviewAudioDocuments) {
int32 from = int32(r.top() - _addToY) / int32(_audioHeight);
int32 to = int32(r.bottom() - _addToY) / int32(_audioHeight) + 1;
History::MediaOverview &overview(_hist->_overview[_type]);
int32 count = overview.size();
p.translate(_audioLeft, _addToY + from * _audioHeight);
for (int32 index = from; index < to; ++index) {
if (index >= count) break;
HistoryItem *item = App::histItemById(overview[index]);
HistoryMedia *m = item ? item->getMedia(true) : 0;
if (!m || m->type() != MediaTypeDocument) continue;
uint32 sel = 0;
if (index >= selfrom && index <= selto) {
sel = (_dragSelecting && item->id > 0) ? FullItemSel : 0;
} else if (hasSel) {
SelectedItems::const_iterator i = _selected.constFind(item->id);
if (i != selEnd) {
sel = i.value();
}
}
static_cast<HistoryDocument*>(m)->drawInPlaylist(p, item, (sel == FullItemSel), ((_menu ? (App::contextItem() ? App::contextItem()->id : 0) : _selectedMsgId) == item->id), _audioWidth);
p.translate(0, _audioHeight);
}
} else {
p.translate(0, st::msgMargin.top() + _addToY);
int32 y = 0, w = _width - st::msgMargin.left() - st::msgMargin.right();
@@ -750,6 +878,7 @@ void OverviewInner::onUpdateSelected() {
TextLinkPtr lnk;
HistoryItem *item = 0;
int32 index = -1;
int32 newsel = 0;
if (_type == OverviewPhotos) {
float64 w = (float64(_width - st::overviewPhotoSkip) / _photosInRow);
int32 inRow = int32((m.x() - (st::overviewPhotoSkip / 2)) / w), vsize = (_vsize + st::overviewPhotoSkip);
@@ -785,6 +914,43 @@ void OverviewInner::onUpdateSelected() {
} else {
return;
}
} else if (_type == OverviewAudioDocuments) {
int32 i = int32((m.y() - _addToY) / _audioHeight), count = _hist->_overview[_type].size();
if (!count) return;
bool upon = true;
if (m.y() < _addToY) {
i = 0;
upon = false;
}
if (i >= count) {
i = count - 1;
upon = false;
}
MsgId msgid = _hist->_overview[_type][i];
HistoryItem *histItem = App::histItemById(msgid);
if (histItem) {
item = histItem;
index = i;
if (upon && m.x() >= _audioLeft && m.x() < _audioLeft + _audioWidth) {
HistoryMedia *media = item->getMedia(true);
if (media && media->type() == MediaTypeDocument) {
lnk = static_cast<HistoryDocument*>(media)->linkInPlaylist();
newsel = item->id;
}
}
if (newsel != _selectedMsgId) {
updateMsg(App::histItemById(_selectedMsgId));
_selectedMsgId = newsel;
updateMsg(item);
}
} else {
if (newsel != _selectedMsgId) {
updateMsg(App::histItemById(_selectedMsgId));
_selectedMsgId = newsel;
}
return;
}
} else {
int32 w = _width - st::msgMargin.left() - st::msgMargin.right();
if (_items.isEmpty()) return;
@@ -824,9 +990,9 @@ void OverviewInner::onUpdateSelected() {
}
left += st::msgPhotoSkip;
}
bool inText = false;
HistoryCursorState cursorState = HistoryDefaultCursorState;
TextLinkPtr link;
media->getState(link, inText, m.x() - left, m.y() - y - st::msgMargin.top(), item, w);
media->getState(link, cursorState, m.x() - left, m.y() - y - st::msgMargin.top(), item, w);
if (link) lnk = link;
}
} else {
@@ -841,7 +1007,7 @@ void OverviewInner::onUpdateSelected() {
m = mapMouseToItem(m, _mousedItem, _mousedItemIndex);
Qt::CursorShape cur = style::cur_default;
bool inText = false, lnkChanged = false;
bool lnkChanged = false;
if (lnk != textlnkOver()) {
lnkChanged = true;
updateMsg(App::hoveredLinkItem());
@@ -866,6 +1032,7 @@ void OverviewInner::onUpdateSelected() {
if (_mousedItem != _dragItem || (m - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()) {
if (_dragAction == PrepareDrag) {
_dragAction = Dragging;
QTimer::singleShot(1, this, SLOT(onDragExec()));
} else if (_dragAction == PrepareSelect) {
_dragAction = Selecting;
}
@@ -878,7 +1045,7 @@ void OverviewInner::onUpdateSelected() {
_selected[_dragItem] = 0;
updateDragSelection(0, -1, 0, -1, false);
} else {
bool selectingDown = (_type == OverviewPhotos ? (_mousedItemIndex > _dragItemIndex) : (_mousedItemIndex < _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && (_type == OverviewPhotos ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y())));
bool selectingDown = ((_type == OverviewPhotos || _type == OverviewAudioDocuments) ? (_mousedItemIndex > _dragItemIndex) : (_mousedItemIndex < _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && (_type == OverviewPhotos ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y())));
MsgId dragSelFrom = _dragItem, dragSelTo = _mousedItem;
int32 dragSelFromIndex = _dragItemIndex, dragSelToIndex = _mousedItemIndex;
if (!itemHasPoint(dragSelFrom, dragSelFromIndex, _dragStartPos.x(), _dragStartPos.y())) { // maybe exclude dragSelFrom
@@ -887,6 +1054,10 @@ void OverviewInner::onUpdateSelected() {
if (_dragStartPos.x() >= _vsize || ((_mousedItem == dragSelFrom) && (m.x() < _dragStartPos.x() + QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
}
} else if (_type == OverviewAudioDocuments) {
if (_dragStartPos.y() >= itemHeight(dragSelFrom, dragSelFromIndex) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
}
} else {
if (_dragStartPos.y() >= (itemHeight(dragSelFrom, dragSelFromIndex) - st::msgMargin.bottom()) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
@@ -897,6 +1068,10 @@ void OverviewInner::onUpdateSelected() {
if (_dragStartPos.x() < 0 || ((_mousedItem == dragSelFrom) && (m.x() >= _dragStartPos.x() - QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
}
} else if (_type == OverviewAudioDocuments) {
if (_dragStartPos.y() < 0 || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
}
} else {
if (_dragStartPos.y() < st::msgMargin.top() || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
@@ -910,6 +1085,10 @@ void OverviewInner::onUpdateSelected() {
if (m.x() < 0) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1);
}
} else if (_type == OverviewAudioDocuments) {
if (m.y() < 0) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
}
} else {
if (m.y() < st::msgMargin.top()) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
@@ -920,6 +1099,10 @@ void OverviewInner::onUpdateSelected() {
if (m.x() >= _vsize) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
}
} else if (_type == OverviewAudioDocuments) {
if (m.y() >= itemHeight(dragSelTo, dragSelToIndex)) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
}
} else {
if (m.y() >= itemHeight(dragSelTo, dragSelToIndex) - st::msgMargin.bottom()) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1);
@@ -931,7 +1114,7 @@ void OverviewInner::onUpdateSelected() {
MsgId dragFirstAffected = dragSelFrom;
int32 dragFirstAffectedIndex = dragSelFromIndex;
while (dragFirstAffectedIndex >= 0 && dragFirstAffected <= 0) {
moveToNextItem(dragFirstAffected, dragFirstAffectedIndex, dragSelTo, ((selectingDown && (_type == OverviewPhotos)) || (!selectingDown && (_type != OverviewPhotos))) ? -1 : 1);
moveToNextItem(dragFirstAffected, dragFirstAffectedIndex, dragSelTo, ((selectingDown && (_type == OverviewPhotos || _type == OverviewAudioDocuments)) || (!selectingDown && (_type != OverviewPhotos && _type != OverviewAudioDocuments))) ? -1 : 1);
}
if (dragFirstAffectedIndex >= 0) {
SelectedItems::const_iterator i = _selected.constFind(dragFirstAffected);
@@ -1007,6 +1190,10 @@ void OverviewInner::enterEvent(QEvent *e) {
}
void OverviewInner::leaveEvent(QEvent *e) {
if (_selectedMsgId > 0) {
updateMsg(App::histItemById(_selectedMsgId));
_selectedMsgId = 0;
}
if (textlnkOver()) {
updateMsg(App::hoveredLinkItem());
textlnkOver(TextLinkPtr());
@@ -1021,7 +1208,9 @@ void OverviewInner::leaveEvent(QEvent *e) {
void OverviewInner::resizeEvent(QResizeEvent *e) {
_width = width();
showAll();
_audioWidth = qMin(_width - st::profilePadding.left() - st::profilePadding.right(), int(st::profileMaxWidth));
_audioLeft = (_width - _audioWidth) / 2;
showAll(true);
onUpdateSelected();
update();
}
@@ -1030,6 +1219,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (_menu) {
_menu->deleteLater();
_menu = 0;
updateMsg(App::contextItem());
if (_selectedMsgId > 0) updateMsg(App::histItemById(_selectedMsgId));
}
if (e->reason() == QContextMenuEvent::Mouse) {
dragActionUpdate(e->globalPos());
@@ -1089,6 +1280,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_menu->addAction(lang(lng_context_select_msg), this, SLOT(selectMessage()))->setEnabled(true);
}
App::contextItem(App::hoveredLinkItem());
updateMsg(App::contextItem());
if (_selectedMsgId > 0) updateMsg(App::histItemById(_selectedMsgId));
} else if (App::mousedItem() && App::mousedItem()->id == _mousedItem) {
_menu = new ContextMenu(_overview);
_menu->addAction(lang(lng_context_to_msg), this, SLOT(goToMessage()))->setEnabled(true);
@@ -1106,6 +1299,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_menu->addAction(lang(lng_context_select_msg), this, SLOT(selectMessage()))->setEnabled(true);
}
App::contextItem(App::mousedItem());
updateMsg(App::contextItem());
if (_selectedMsgId > 0) updateMsg(App::histItemById(_selectedMsgId));
}
if (_menu) {
_menu->deleteOnHide();
@@ -1118,7 +1313,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeight) {
if (width() == nwidth && minHeight == _minHeight) return scrollTop;
_minHeight = minHeight;
_addToY = (_height < _minHeight) ? (_minHeight - _height) : 0;
_addToY = (_type == OverviewAudioDocuments) ? st::playlistPadding : ((_height < _minHeight) ? (_minHeight - _height) : 0);
if (_type == OverviewPhotos && _resizeIndex < 0) {
_resizeIndex = _photosInRow * ((scrollTop + minHeight) / int32(_vsize + st::overviewPhotoSkip)) + _photosInRow - 1;
_resizeSkip = (scrollTop + minHeight) - ((scrollTop + minHeight) / int32(_vsize + st::overviewPhotoSkip)) * int32(_vsize + st::overviewPhotoSkip);
@@ -1241,6 +1436,8 @@ void OverviewInner::openContextFile() {
void OverviewInner::onMenuDestroy(QObject *obj) {
if (_menu == obj) {
_menu = 0;
updateMsg(App::contextItem());
if (_selectedMsgId > 0) updateMsg(App::histItemById(_selectedMsgId));
}
}
@@ -1304,14 +1501,15 @@ void OverviewInner::onTouchScrollTimer() {
}
}
void OverviewInner::mediaOverviewUpdated() {
void OverviewInner::mediaOverviewUpdated(bool fromResize) {
int32 oldHeight = _height;
if (_type != OverviewPhotos) {
if (_type != OverviewPhotos && _type != OverviewAudioDocuments) {
History::MediaOverview &o(_hist->_overview[_type]);
int32 l = o.size();
_items.reserve(2 * l); // day items
int32 y = 0, in = 0;
int32 w = _width - st::msgMargin.left() - st::msgMargin.right();
bool allGood = true;
QDate prevDate;
for (int32 i = 0; i < l; ++i) {
@@ -1319,14 +1517,36 @@ void OverviewInner::mediaOverviewUpdated() {
if (allGood) {
if (_items.size() > in && _items.at(in).msgid == msgid) {
prevDate = _items.at(in).date;
y = _items.at(in).y;
if (fromResize) {
HistoryItem *item = App::histItemById(msgid);
HistoryMedia *media = item ? item->getMedia(true) : 0;
if (media) {
y += media->countHeight(item, w) + st::msgMargin.top() + st::msgMargin.bottom(); // item height
}
_items[in].y = y;
} else {
y = _items.at(in).y;
}
++in;
continue;
}
if (_items.size() > in + 1 && !_items.at(in).msgid && _items.at(in + 1).msgid == msgid) { // day item
if (fromResize) {
y += st::msgServiceFont->height + st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); // day item height
_items[in].y = y;
}
++in;
prevDate = _items.at(in).date;
y = _items.at(in).y;
if (fromResize) {
HistoryItem *item = App::histItemById(msgid);
HistoryMedia *media = item ? item->getMedia(true) : 0;
if (media) {
y += media->countHeight(item, w) + st::msgMargin.top() + st::msgMargin.bottom(); // item height
}
_items[in].y = y;
} else {
y = _items.at(in).y;
}
++in;
continue;
}
@@ -1353,7 +1573,6 @@ void OverviewInner::mediaOverviewUpdated() {
} else {
prevDate = date;
}
int32 w = _width - st::msgMargin.left() - st::msgMargin.right();
media->initDimensions(item);
y += media->countHeight(item, w) + st::msgMargin.top() + st::msgMargin.bottom(); // item height
if (_items.size() > in) {
@@ -1378,8 +1597,10 @@ void OverviewInner::mediaOverviewUpdated() {
}
if (_height != y) {
_height = y;
_addToY = (_height < _minHeight) ? (_minHeight - _height) : 0;
resize(width(), _minHeight > _height ? _minHeight : _height);
if (!fromResize) {
_addToY = (_type == OverviewAudioDocuments) ? st::playlistPadding : ((_height < _minHeight) ? (_minHeight - _height) : 0);
resize(width(), _minHeight > _height ? _minHeight : _height);
}
}
}
@@ -1388,9 +1609,11 @@ void OverviewInner::mediaOverviewUpdated() {
fixItemIndex(_mousedItemIndex, _mousedItem);
fixItemIndex(_dragItemIndex, _dragItem);
resizeEvent(0);
if (_height != oldHeight) {
_overview->scrollBy(_height - oldHeight);
if (!fromResize) {
resizeEvent(0);
if (_height != oldHeight) {
_overview->scrollBy(_height - oldHeight);
}
}
}
@@ -1442,7 +1665,7 @@ void OverviewInner::itemRemoved(HistoryItem *item) {
}
void OverviewInner::itemResized(HistoryItem *item, bool scrollToIt) {
if (_type != OverviewPhotos) {
if (_type != OverviewPhotos && _type != OverviewAudioDocuments) {
HistoryMedia *media = item ? item->getMedia(true) : 0;
if (!media) return;
@@ -1460,7 +1683,7 @@ void OverviewInner::itemResized(HistoryItem *item, bool scrollToIt) {
_items[j].y += newh;
}
_height = _items[l - 1].y;
_addToY = (_height < _minHeight) ? (_minHeight - _height) : 0;
_addToY = (_type == OverviewAudioDocuments) ? st::playlistPadding : ((_height < _minHeight) ? (_minHeight - _height) : 0);
resize(width(), _minHeight > _height ? _minHeight : _height);
if (scrollToIt) {
if (_addToY + _height - from > _scroll->scrollTop() + _scroll->height()) {
@@ -1490,6 +1713,11 @@ void OverviewInner::msgUpdated(const HistoryItem *msg) {
int32 row = (_photosToAdd + index) / _photosInRow, col = (_photosToAdd + index) % _photosInRow;
update(int32(col * w), _addToY + int32(row * vsize), qCeil(w), vsize);
}
} else if (_type == OverviewAudioDocuments) {
int32 index = _hist->_overview[_type].indexOf(msgid);
if (index >= 0) {
update(_audioLeft, _addToY + int32(index * _audioHeight), _audioWidth, _audioHeight);
}
} else {
for (int32 i = 0, l = _items.size(); i != l; ++i) {
if (_items[i].msgid == msgid) {
@@ -1503,7 +1731,7 @@ void OverviewInner::msgUpdated(const HistoryItem *msg) {
}
}
void OverviewInner::showAll() {
void OverviewInner::showAll(bool recountHeights) {
int32 newHeight = height();
if (_type == OverviewPhotos) {
_photosInRow = int32(width() - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip);
@@ -1518,10 +1746,16 @@ void OverviewInner::showAll() {
}
int32 rows = ((_photosToAdd + count) / _photosInRow) + (((_photosToAdd + count) % _photosInRow) ? 1 : 0);
newHeight = _height = (_vsize + st::overviewPhotoSkip) * rows + st::overviewPhotoSkip;
_addToY = (_height < _minHeight) ? (_minHeight - _height) : 0;
} else if (_type == OverviewAudioDocuments) {
int32 count = _hist->_overview[_type].size(), fullCount = _hist->_overviewCount[_type];
newHeight = _height = count * _audioHeight + 2 * st::playlistPadding;
} else {
if (recountHeights && _type == OverviewVideos) { // recount heights because of captions
mediaOverviewUpdated(true);
}
newHeight = _height;
}
_addToY = (_type == OverviewAudioDocuments) ? st::playlistPadding : ((_height < _minHeight) ? (_minHeight - _height) : 0);
if (newHeight < _minHeight) {
newHeight = _minHeight;
}
@@ -1531,6 +1765,7 @@ void OverviewInner::showAll() {
}
OverviewInner::~OverviewInner() {
_dragAction = NoDrag;
}
OverviewWidget::OverviewWidget(QWidget *parent, const PeerData *peer, MediaOverviewType type) : QWidget(parent)
@@ -1555,6 +1790,8 @@ OverviewWidget::OverviewWidget(QWidget *parent, const PeerData *peer, MediaOverv
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
_scrollTimer.setSingleShot(false);
connect(App::main()->player(), SIGNAL(playerSongChanged(MsgId)), this, SLOT(onPlayerSongChanged(MsgId)));
switchType(type);
}
@@ -1575,8 +1812,12 @@ void OverviewWidget::onScroll() {
}
void OverviewWidget::resizeEvent(QResizeEvent *e) {
int32 st = _scroll.scrollTop();
_scroll.resize(size());
int32 newScrollTop = _inner.resizeToWidth(width(), _scroll.scrollTop(), height());
int32 newScrollTop = _inner.resizeToWidth(width(), st, height());
if (int32 addToY = App::main() ? App::main()->contentScrollAddToY() : 0) {
newScrollTop += addToY;
}
if (newScrollTop != _scroll.scrollTop()) {
_noDropResizeIndex = true;
_scroll.scrollToY(newScrollTop);
@@ -1594,33 +1835,36 @@ void OverviewWidget::paintEvent(QPaintEvent *e) {
return;
}
bool hasTopBar = !App::main()->topBar()->isHidden();
QRect r(e->rect());
if (type() == OverviewPhotos) {
if (type() == OverviewPhotos || type() == OverviewAudioDocuments) {
p.fillRect(r, st::white->b);
} else if (cTileBackground()) {
int left = r.left(), top = r.top(), right = r.left() + r.width(), bottom = r.top() + r.height();
if (right > 0 && bottom > 0) {
QRect fill(left, top + (hasTopBar ? st::topBarHeight : 0), right, bottom + (hasTopBar ? st::topBarHeight : 0));
if (hasTopBar) p.translate(0, -st::topBarHeight);
p.fillRect(fill, QBrush(*cChatBackground()));
if (hasTopBar) p.translate(0, st::topBarHeight);
}
} else {
bool hasTopBar = !App::main()->topBar()->isHidden(), hasPlayer = !App::main()->player()->isHidden();
QRect fill(0, 0, width(), App::main()->height());
int fromy = hasTopBar ? (-st::topBarHeight) : 0, x = 0, y = 0;
int fromy = (hasTopBar ? (-st::topBarHeight) : 0) + (hasPlayer ? (-st::playerHeight) : 0), x = 0, y = 0;
QPixmap cached = App::main()->cachedBackground(fill, x, y);
if (cached.isNull()) {
bool smooth = p.renderHints().testFlag(QPainter::SmoothPixmapTransform);
p.setRenderHint(QPainter::SmoothPixmapTransform);
const QPixmap &pix(*cChatBackground());
if (cTileBackground()) {
int left = r.left(), top = r.top(), right = r.left() + r.width(), bottom = r.top() + r.height();
float64 w = pix.width() / cRetinaFactor(), h = pix.height() / cRetinaFactor();
int sx = qFloor(left / w), sy = qFloor((top - fromy) / h), cx = qCeil(right / w), cy = qCeil((bottom - fromy) / h);
for (int i = sx; i < cx; ++i) {
for (int j = sy; j < cy; ++j) {
p.drawPixmap(QPointF(i * w, fromy + j * h), pix);
}
}
} else {
bool smooth = p.renderHints().testFlag(QPainter::SmoothPixmapTransform);
p.setRenderHint(QPainter::SmoothPixmapTransform);
QRect to, from;
App::main()->backgroundParams(fill, to, from);
to.moveTop(to.top() + fromy);
p.drawPixmap(to, *cChatBackground(), from);
QRect to, from;
App::main()->backgroundParams(fill, to, from);
to.moveTop(to.top() + fromy);
p.drawPixmap(to, pix, from);
if (!smooth) p.setRenderHint(QPainter::SmoothPixmapTransform, false);
if (!smooth) p.setRenderHint(QPainter::SmoothPixmapTransform, false);
}
} else {
p.drawPixmap(x, fromy + y, cached);
}
@@ -1654,6 +1898,13 @@ void OverviewWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth)
}
}
void OverviewWidget::topBarShadowParams(int32 &x, float64 &o) {
if (animating() && a_coord.current() >= 0) {
x = a_coord.current();
o = a_alpha.current();
}
}
void OverviewWidget::topBarClick() {
App::main()->showBackFromStack();
}
@@ -1675,6 +1926,7 @@ void OverviewWidget::switchType(MediaOverviewType type) {
case OverviewVideos: _header = lang(lng_profile_videos_header); break;
case OverviewDocuments: _header = lang(lng_profile_files_header); break;
case OverviewAudios: _header = lang(lng_profile_audios_header); break;
case OverviewAudioDocuments: _header = lang(lng_profile_audio_files_header); break;
}
noSelectingScroll();
App::main()->topBar()->showSelected(0);
@@ -1706,12 +1958,36 @@ int32 OverviewWidget::lastScrollTop() const {
return _scroll.scrollTop();
}
int32 OverviewWidget::countBestScroll() const {
if (type() == OverviewAudioDocuments && audioPlayer()) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing) {
int32 top = _inner.itemTop(playing.msgId);
if (top >= 0) {
return snap(top - int(_scroll.height() - (st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom())) / 2, 0, _scroll.scrollTopMax());
}
}
}
return _scroll.scrollTopMax();
}
void OverviewWidget::fastShow(bool back, int32 lastScrollTop) {
stopGif();
resizeEvent(0);
_scrollSetAfterShow = (lastScrollTop < 0 ? countBestScroll() : lastScrollTop);
show();
_inner.setFocus();
doneShow();
}
void OverviewWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back, int32 lastScrollTop) {
stopGif();
_bgAnimCache = bgAnimCache;
_bgAnimTopBarCache = bgAnimTopBarCache;
resizeEvent(0);
_scroll.scrollToY(lastScrollTop < 0 ? _scroll.scrollTopMax() : lastScrollTop);
_scroll.scrollToY(lastScrollTop < 0 ? countBestScroll() : lastScrollTop);
_animCache = myGrab(this, rect());
App::main()->topBar()->stopAnim();
_animTopBarCache = myGrab(App::main()->topBar(), QRect(0, 0, width(), st::topBarHeight));
@@ -1741,10 +2017,7 @@ bool OverviewWidget::animStep(float64 ms) {
a_alpha.finish();
_bgAnimCache = _animCache = _animTopBarCache = _bgAnimTopBarCache = QPixmap();
App::main()->topBar()->stopAnim();
_scroll.show();
_scroll.scrollToY(_scrollSetAfterShow);
activate();
onScroll();
doneShow();
} else {
a_bgCoord.update(dt1, st::introHideFunc);
a_bgAlpha.update(dt1, st::introAlphaHideFunc);
@@ -1756,8 +2029,15 @@ bool OverviewWidget::animStep(float64 ms) {
return res;
}
void OverviewWidget::mediaOverviewUpdated(PeerData *p) {
if (peer() == p) {
void OverviewWidget::doneShow() {
_scroll.show();
_scroll.scrollToY(_scrollSetAfterShow);
activate();
onScroll();
}
void OverviewWidget::mediaOverviewUpdated(PeerData *p, MediaOverviewType t) {
if (peer() == p && t == type()) {
_inner.mediaOverviewUpdated();
onScroll();
updateTopBarSelection();
@@ -1825,6 +2105,15 @@ void OverviewWidget::onScrollTimer() {
_scroll.scrollToY(_scroll.scrollTop() + d);
}
void OverviewWidget::onPlayerSongChanged(MsgId msgId) {
if (type() == OverviewAudioDocuments) {
// int32 top = _inner.itemTop(msgId);
// if (top > 0) {
// _scroll.scrollToY(snap(top - int(_scroll.height() - (st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom())) / 2, 0, _scroll.scrollTopMax()));
// }
}
}
void OverviewWidget::checkSelectingScroll(QPoint point) {
if (point.y() < _scroll.scrollTop()) {
_scrollDelta = point.y() - _scroll.scrollTop();

View File

@@ -26,6 +26,7 @@ public:
OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const PeerData *peer, MediaOverviewType type);
void clear();
int32 itemTop(MsgId msgId) const;
bool event(QEvent *e);
void touchEvent(QTouchEvent *e);
@@ -57,7 +58,7 @@ public:
void setSelectMode(bool enabled);
void mediaOverviewUpdated();
void mediaOverviewUpdated(bool fromResize = false);
void changingMsgId(HistoryItem *row, MsgId newId);
void msgUpdated(const HistoryItem *msg);
void itemRemoved(HistoryItem *item);
@@ -88,6 +89,8 @@ public slots:
void onTouchSelect();
void onTouchScrollTimer();
void onDragExec();
private:
void fixItemIndex(int32 &current, MsgId msgId) const;
@@ -107,7 +110,7 @@ private:
void applyDragSelection();
QPixmap genPix(PhotoData *photo, int32 size);
void showAll();
void showAll(bool recountHeights = false);
OverviewWidget *_overview;
ScrollArea *_scroll;
@@ -128,6 +131,9 @@ private:
CachedSizes _cached;
bool _selMode;
// audio documents
int32 _audioLeft, _audioWidth, _audioHeight;
// other
typedef struct _CachedItem {
_CachedItem() : msgid(0), y(0) {
@@ -140,6 +146,7 @@ private:
} CachedItem;
typedef QVector<CachedItem> CachedItems;
CachedItems _items;
int32 _width, _height, _minHeight, _addToY;
// selection support, like in HistoryWidget
@@ -155,7 +162,7 @@ private:
};
DragAction _dragAction;
QPoint _dragStartPos, _dragPos;
MsgId _dragItem;
MsgId _dragItem, _selectedMsgId;
int32 _dragItemIndex;
MsgId _mousedItem;
int32 _mousedItemIndex;
@@ -197,6 +204,7 @@ public:
void scrollBy(int32 add);
void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
void topBarShadowParams(int32 &x, float64 &o);
void topBarClick();
PeerData *peer() const;
@@ -206,11 +214,15 @@ public:
int32 lastWidth() const;
int32 lastScrollTop() const;
int32 countBestScroll() const;
void fastShow(bool back = false, int32 lastScrollTop = -1);
void animShow(const QPixmap &oldAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false, int32 lastScrollTop = -1);
bool animStep(float64 ms);
void mediaOverviewUpdated(PeerData *peer);
void doneShow();
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
void changingMsgId(HistoryItem *row, MsgId newId);
void msgUpdated(PeerId peer, const HistoryItem *msg);
void itemRemoved(HistoryItem *item);
@@ -235,6 +247,7 @@ public slots:
void onScroll();
void onScrollTimer();
void onPlayerSongChanged(MsgId msgId);
void onForwardSelected();
void onDeleteSelected();

View File

@@ -0,0 +1,625 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "style.h"
#include "lang.h"
#include "boxes/addcontactbox.h"
#include "application.h"
#include "window.h"
#include "playerwidget.h"
#include "mainwidget.h"
#include "localstorage.h"
#include "audio.h"
PlayerWidget::PlayerWidget(QWidget *parent) : TWidget(parent),
_prevAvailable(false), _nextAvailable(false), _fullAvailable(false),
_over(OverNone), _down(OverNone), _downCoord(0), _downFrequency(AudioVoiceMsgFrequency), _downProgress(0.),
_stateAnim(animFunc(this, &PlayerWidget::stateStep)),
_index(-1), _history(0), _timeWidth(0), _repeat(false), _showPause(false), _position(0), _duration(0), _loaded(0),
a_progress(0., 0.), a_loadProgress(0., 0.), _progressAnim(animFunc(this, &PlayerWidget::progressStep)) {
resize(st::wndMinWidth, st::playerHeight);
setMouseTracking(true);
memset(_stateHovers, 0, sizeof(_stateHovers));
}
void PlayerWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
QRect r(e->rect()), checkr(myrtlrect(r));
p.fillRect(r, st::playerBg->b);
if (!_playbackRect.contains(checkr)) {
if (_fullAvailable && checkr.intersects(_prevRect)) {
if (_prevAvailable) {
float64 o = _stateHovers[OverPrev];
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
} else {
p.setOpacity(st::playerUnavailableOpacity);
}
p.drawSpriteCenterLeft(_prevRect, width(), st::playerPrev);
}
if (checkr.intersects(_playRect)) {
float64 o = _stateHovers[OverPlay];
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
p.drawSpriteCenterLeft(_playRect, width(), (_showPause || _down == OverPlayback) ? st::playerPause : st::playerPlay);
}
if (_fullAvailable && checkr.intersects(_nextRect)) {
if (_nextAvailable) {
float64 o = _stateHovers[OverNext];
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
} else {
p.setOpacity(st::playerUnavailableOpacity);
}
p.drawSpriteCenterLeft(_nextRect, width(), st::playerNext);
}
if (checkr.intersects(_closeRect)) {
float64 o = _stateHovers[OverClose];
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
p.drawSpriteCenterLeft(_closeRect, width(), st::playerClose);
}
if (checkr.intersects(_volumeRect)) {
float64 o = _stateHovers[OverVolume];
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
int32 top = _volumeRect.y() + (_volumeRect.height() - st::playerVolume.pxHeight()) / 2;
int32 left = _volumeRect.x() + (_volumeRect.width() - st::playerVolume.pxWidth()) / 2;
int32 mid = left + qRound(st::playerVolume.pxWidth() * cSongVolume());
int32 right = left + st::playerVolume.pxWidth();
if (rtl()) {
left = width() - left;
mid = width() - mid;
right = width() - right;
if (mid < left) {
p.drawPixmap(QRect(mid, top, left - mid, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.x() + (mid - right) * cIntRetinaFactor(), st::playerVolume.y(), (left - mid) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
}
if (right < mid) {
p.setOpacity(st::playerUnavailableOpacity);
p.drawPixmap(QRect(right, top, mid - right, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.x(), st::playerVolume.y(), (mid - right) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
}
} else {
if (mid > left) {
p.drawPixmap(QRect(left, top, mid - left, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.x(), st::playerVolume.y(), (mid - left) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
}
if (right > mid) {
p.setOpacity(st::playerUnavailableOpacity);
p.drawPixmap(QRect(mid, top, right - mid, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.x() + (mid - left) * cIntRetinaFactor(), st::playerVolume.y(), (right - mid) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
}
}
}
if (_fullAvailable && checkr.intersects(_fullRect)) {
float64 o = _stateHovers[OverFull];
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
p.drawSpriteCenterLeft(_fullRect, width(), st::playerFull);
}
if (checkr.intersects(_repeatRect)) {
float64 o = _stateHovers[OverRepeat];
p.setOpacity(_repeat ? 1. : (o * st::playerInactiveOpacity + (1. - o) * st::playerUnavailableOpacity));
p.drawSpriteCenterLeft(_repeatRect, width(), st::playerRepeat);
}
p.setOpacity(1.);
p.setPen(st::playerTimeFg->p);
p.setFont(st::linkFont->f);
p.drawTextLeft(_infoRect.x() + _infoRect.width() - _timeWidth, _infoRect.y() + (_infoRect.height() - st::linkFont->height) / 2, width(), _time, _timeWidth);
textstyleSet(&st::playerNameStyle);
p.setPen(st::playerFg->p);
_name.drawElided(p, _infoRect.x() + (rtl() ? (_timeWidth + st::playerSkip) : 0), _infoRect.y() + (_infoRect.height() - st::linkFont->height) / 2, _infoRect.width() - _timeWidth - st::playerSkip);
textstyleRestore();
}
if (_duration) {
float64 prg = (_down == OverPlayback) ? _downProgress : a_progress.current();
int32 from = _playbackRect.x(), mid = qRound(_playbackRect.x() + prg * _playbackRect.width()), end = _playbackRect.x() + _playbackRect.width();
if (mid > from) {
p.fillRect(rtl() ? (width() - mid) : from, height() - st::playerLineHeight, mid - from, _playbackRect.height(), st::playerLineActive->b);
}
if (end > mid) {
p.fillRect(rtl() ? (width() - end) : mid, height() - st::playerLineHeight, end - mid, st::playerLineHeight, st::playerLineInactive->b);
}
if (_stateHovers[OverPlayback] > 0) {
p.setOpacity(_stateHovers[OverPlayback]);
int32 x = mid - (st::playerMoverSize.width() / 2);
p.fillRect(rtl() ? (width() - x - st::playerMoverSize.width()) : x, height() - st::playerMoverSize.height(), st::playerMoverSize.width(), st::playerMoverSize.height(), st::playerLineActive->b);
}
} else if (a_loadProgress.current() > 0) {
int32 from = _playbackRect.x(), mid = qRound(_playbackRect.x() + a_loadProgress.current() * _playbackRect.width());
if (mid > from) {
p.fillRect(rtl() ? (width() - mid) : from, height() - st::playerLineHeight, mid - from, _playbackRect.height(), st::playerLineInactive->b);
}
}
}
void PlayerWidget::mousePressEvent(QMouseEvent *e) {
QPoint pos(myrtlpoint(e->pos()));
if (e->button() == Qt::LeftButton) {
_down = OverNone;
if (_song && _over == OverPlay) {
playPausePressed();
return;
} else if (_over == OverPrev) {
prevPressed();
} else if (_over == OverNext) {
nextPressed();
} else if (_over == OverClose) {
_down = OverClose;
} else if (_over == OverVolume) {
_down = OverVolume;
_downCoord = pos.x() - _volumeRect.x();
cSetSongVolume(snap((_downCoord - ((_volumeRect.width() - st::playerVolume.pxWidth()) / 2)) / float64(st::playerVolume.pxWidth()), 0., 1.));
emit audioPlayer()->songVolumeChanged();
rtlupdate(_volumeRect);
} else if (_over == OverPlayback) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0;
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing == _song && playingDuration) {
if (playingState == AudioPlayerPlaying || playingState == AudioPlayerStarting || playingState == AudioPlayerResuming) {
audioPlayer()->pauseresume(OverviewDocuments);
}
_down = OverPlayback;
_downProgress = snap((pos.x() - _playbackRect.x()) / float64(_playbackRect.width()), 0., 1.);
_downDuration = playingDuration;
_downFrequency = (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
rtlupdate(_playbackRect);
updateDownTime();
}
} else if (_over == OverFull && _song) {
if (HistoryItem *item = App::histItemById(_song.msgId)) {
App::main()->showMediaOverview(item->history()->peer, OverviewAudioDocuments);
}
} else if (_over == OverRepeat) {
_repeat = !_repeat;
updateOverRect(OverRepeat);
}
}
}
void PlayerWidget::updateDownTime() {
QString time = formatDurationText(qRound(_downDuration * _downProgress) / _downFrequency);
if (time != _time) {
_time = time;
_timeWidth = st::linkFont->m.width(_time);
rtlupdate(_infoRect);
}
}
void PlayerWidget::updateOverState(OverState newState) {
bool result = true;
if (_over != newState) {
updateOverRect(_over);
updateOverRect(newState);
if (_over != OverNone) {
_stateAnimations.remove(_over);
_stateAnimations[-_over] = getms() - ((1. - _stateHovers[_over]) * st::playerDuration);
if (!_stateAnim.animating()) _stateAnim.start();
} else {
result = false;
}
_over = newState;
if (newState != OverNone) {
_stateAnimations.remove(-_over);
_stateAnimations[_over] = getms() - (_stateHovers[_over] * st::playerDuration);
if (!_stateAnim.animating()) _stateAnim.start();
setCursor(style::cur_pointer);
} else {
setCursor(style::cur_default);
}
}
}
void PlayerWidget::updateOverRect(OverState state) {
switch (state) {
case OverPrev: rtlupdate(_prevRect); break;
case OverPlay: rtlupdate(_playRect); break;
case OverNext: rtlupdate(_nextRect); break;
case OverClose: rtlupdate(_closeRect); break;
case OverVolume: rtlupdate(_volumeRect); break;
case OverFull: rtlupdate(_fullRect); break;
case OverRepeat: rtlupdate(_repeatRect); break;
case OverPlayback: rtlupdate(_playbackRect); break;
}
}
void PlayerWidget::updateControls() {
_fullAvailable = (_index >= 0);
_prevAvailable = _fullAvailable && (_index > 0);
_nextAvailable = _fullAvailable && (_index < _history->_overview[OverviewAudioDocuments].size() - 1);
resizeEvent(0);
update();
if (_index >= 0 && _index < MediaOverviewStartPerPage) {
if (_history->_overviewCount[OverviewAudioDocuments] < 0 || _history->_overviewCount[OverviewAudioDocuments] > 0) {
if (App::main()) App::main()->loadMediaBack(_history->peer, OverviewAudioDocuments);
}
}
}
void PlayerWidget::findCurrent() {
_index = -1;
if (!_history) return;
const History::MediaOverview *o = &_history->_overview[OverviewAudioDocuments];
for (int i = 0, l = o->size(); i < l; ++i) {
if (o->at(i) == _song.msgId) {
_index = i;
break;
}
}
if (_index < 0) return;
if (_index < o->size() - 1) {
if (HistoryItem *next = App::histItemById(o->at(_index + 1))) {
if (HistoryDocument *document = static_cast<HistoryDocument*>(next->getMedia())) {
if (document->document()->already(true).isEmpty() && document->document()->data.isEmpty()) {
if (!document->document()->loader) {
DocumentOpenLink::doOpen(document->document());
document->document()->openOnSave = document->document()->openOnSaveMsgId = 0;
}
}
}
}
}
}
void PlayerWidget::startPlay(MsgId msgId) {
if (HistoryItem *item = App::histItemById(msgId)) {
if (HistoryDocument *doc = static_cast<HistoryDocument*>(item->getMedia())) {
audioPlayer()->play(SongMsgId(doc->document(), item->id));
updateState();
}
}
}
void PlayerWidget::clearSelection() {
for (StateAnimations::const_iterator i = _stateAnimations.cbegin(); i != _stateAnimations.cend(); ++i) {
_stateHovers[qAbs(i.key())] = 0;
}
_stateAnimations.clear();
}
void PlayerWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
if (_history && _history->peer == peer && type == OverviewAudioDocuments) {
_index = -1;
for (int i = 0, l = _history->_overview[OverviewAudioDocuments].size(); i < l; ++i) {
if (_history->_overview[OverviewAudioDocuments].at(i) == _song.msgId) {
_index = i;
break;
}
}
updateControls();
}
}
bool PlayerWidget::seekingSong(const SongMsgId &song) const {
return (_down == OverPlayback) && (song == _song);
}
bool PlayerWidget::stateStep(float64 msc) {
bool result = false;
uint64 ms = getms();
for (StateAnimations::iterator i = _stateAnimations.begin(); i != _stateAnimations.cend();) {
int32 over = qAbs(i.key());
updateOverRect(OverState(over));
float64 dt = float64(ms - i.value()) / st::playerDuration;
if (dt >= 1) {
_stateHovers[over] = (i.key() > 0) ? 1 : 0;
i = _stateAnimations.erase(i);
} else {
_stateHovers[over] = (i.key() > 0) ? dt : (1 - dt);
++i;
}
}
return !_stateAnimations.isEmpty();
}
void PlayerWidget::mouseMoveEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
updateSelected();
}
void PlayerWidget::leaveEvent(QEvent *e) {
_lastMousePos = QCursor::pos();
updateSelected();
}
void PlayerWidget::updateSelected() {
QPoint pos(myrtlpoint(mapFromGlobal(_lastMousePos)));
if (_down == OverVolume) {
int32 delta = (pos.x() - _volumeRect.x()) - _downCoord;
float64 startFrom = snap((_downCoord - ((_volumeRect.width() - st::playerVolume.pxWidth()) / 2)) / float64(st::playerVolume.pxWidth()), 0., 1.);
float64 add = delta / float64(4 * st::playerVolume.pxWidth()), result = snap(startFrom + add, 0., 1.);
if (result != cSongVolume()) {
cSetSongVolume(result);
emit audioPlayer()->songVolumeChanged();
rtlupdate(_volumeRect);
}
} else if (_down == OverPlayback) {
_downProgress = snap((pos.x() - _playbackRect.x()) / float64(_playbackRect.width()), 0., 1.);
rtlupdate(_playbackRect);
updateDownTime();
} else if (_down == OverNone) {
bool inInfo = ((pos.x() >= _infoRect.x()) && (pos.x() < _fullRect.x() + _fullRect.width()) && (pos.y() >= _playRect.y()) && (pos.y() <= _playRect.y() + _playRect.height()));
if (_prevAvailable && _prevRect.contains(pos)) {
updateOverState(OverPrev);
} else if (_nextAvailable && _nextRect.contains(pos)) {
updateOverState(OverNext);
} else if (_playRect.contains(pos)) {
updateOverState(OverPlay);
} else if (_closeRect.contains(pos)) {
updateOverState(OverClose);
} else if (_volumeRect.contains(pos)) {
updateOverState(OverVolume);
} else if (_repeatRect.contains(pos)) {
updateOverState(OverRepeat);
} else if (_duration && _playbackRect.contains(pos)) {
updateOverState(OverPlayback);
} else if (_fullAvailable && inInfo) {
updateOverState(OverFull);
} else if (_over != OverNone) {
updateOverState(OverNone);
}
}
}
void PlayerWidget::mouseReleaseEvent(QMouseEvent *e) {
if (_down == OverVolume) {
mouseMoveEvent(e);
Local::writeUserSettings();
} else if (_down == OverPlayback) {
mouseMoveEvent(e);
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0;
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing == _song && playingDuration) {
_downDuration = playingDuration;
audioPlayer()->seek(qRound(_downProgress * _downDuration));
_showPause = true;
a_progress = anim::fvalue(_downProgress, _downProgress);
_progressAnim.stop();
}
update();
} else if (_down == OverClose && _over == OverClose) {
stopPressed();
}
_down = OverNone;
}
void PlayerWidget::playPressed() {
if (!_song || isHidden()) return;
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
if (playingState == AudioPlayerPausing || playingState == AudioPlayerPaused || playingState == AudioPlayerPausedAtEnd) {
audioPlayer()->pauseresume(OverviewDocuments);
}
} else {
audioPlayer()->play(_song);
if (App::main()) App::main()->documentPlayProgress(_song);
}
}
void PlayerWidget::pausePressed() {
if (!_song || isHidden()) return;
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
if (playingState == AudioPlayerStarting || playingState == AudioPlayerResuming || playingState == AudioPlayerPlaying || playingState == AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewDocuments);
}
}
}
void PlayerWidget::playPausePressed() {
if (!_song || isHidden()) return;
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
audioPlayer()->pauseresume(OverviewDocuments);
} else {
audioPlayer()->play(_song);
if (App::main()) App::main()->documentPlayProgress(_song);
}
}
void PlayerWidget::prevPressed() {
if (isHidden()) return;
const History::MediaOverview *o = _history ? &_history->_overview[OverviewAudioDocuments] : 0;
if (audioPlayer() && o && _index > 0 && _index <= o->size() && !o->isEmpty()) {
startPlay(o->at(_index - 1));
}
}
void PlayerWidget::nextPressed() {
if (isHidden()) return;
const History::MediaOverview *o = _history ? &_history->_overview[OverviewAudioDocuments] : 0;
if (audioPlayer() && o && _index >= 0 && _index < o->size() - 1) {
startPlay(o->at(_index + 1));
}
}
void PlayerWidget::stopPressed() {
if (!_song || isHidden()) return;
audioPlayer()->stop(OverviewDocuments);
if (App::main()) App::main()->hidePlayer();
}
void PlayerWidget::resizeEvent(QResizeEvent *e) {
int32 availh = (height() - st::playerLineHeight);
int32 ch = st::playerPlay.pxHeight() + st::playerSkip, ct = (availh - ch) / 2;
_playbackRect = QRect(cWideMode() ? st::dlgShadow : 0, height() - st::playerMoverSize.height(), width() - (cWideMode() ? st::dlgShadow : 0), st::playerMoverSize.height());
_prevRect = _fullAvailable ? QRect(st::playerSkip / 2, ct, st::playerPrev.pxWidth() + st::playerSkip, ch) : QRect();
_playRect = QRect(_fullAvailable ? (_prevRect.x() + _prevRect.width()) : (st::playerSkip / 2), ct, st::playerPlay.pxWidth() + st::playerSkip, ch);
_nextRect = _fullAvailable ? QRect(_playRect.x() + _playRect.width(), ct, st::playerNext.pxWidth() + st::playerSkip, ch) : QRect();
_closeRect = QRect(width() - st::playerSkip / 2 - st::playerClose.pxWidth() - st::playerSkip, ct, st::playerClose.pxWidth() + st::playerSkip, ch);
_volumeRect = QRect(_closeRect.x() - st::playerVolume.pxWidth() - st::playerSkip, ct, st::playerVolume.pxWidth() + st::playerSkip, ch);
_repeatRect = QRect(_volumeRect.x() - st::playerRepeat.pxWidth() - st::playerSkip, ct, st::playerRepeat.pxWidth() + st::playerSkip, ch);
_fullRect = _fullAvailable ? QRect(_repeatRect.x() - st::playerFull.pxWidth() - st::playerSkip, ct, st::playerFull.pxWidth() + st::playerSkip, ch) : QRect();
int32 infoLeft = (_fullAvailable ? (_nextRect.x() + _nextRect.width()) : (_playRect.x() + _playRect.width()));
_infoRect = QRect(infoLeft + st::playerSkip / 2, 0, (_fullAvailable ? _fullRect.x() : _repeatRect.x()) - infoLeft - st::playerSkip, availh);
update();
}
bool PlayerWidget::progressStep(float64 ms) {
float64 dt = ms / (2 * AudioVoiceMsgUpdateView);
bool res = true;
if (_duration && dt >= 1) {
a_progress.finish();
a_loadProgress.finish();
res = false;
} else {
a_progress.update(qMin(dt, 1.), anim::linear);
a_loadProgress.update(1. - (st::radialDuration / (st::radialDuration + ms)), anim::linear);
}
rtlupdate(_playbackRect);
return res;
}
void PlayerWidget::updateState() {
updateState(SongMsgId(), AudioPlayerStopped, 0, 0, 0);
}
void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState, int64 playingPosition, int64 playingDuration, int32 playingFrequency) {
if (!playing) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
}
bool songChanged = false;
if (playing && _song != playing) {
songChanged = true;
_song = playing;
if (HistoryItem *item = App::histItemById(_song.msgId)) {
_history = item->history();
findCurrent();
} else {
_history = 0;
_index = -1;
}
SongData *song = _song.song->song();
if (song->performer.isEmpty()) {
_name.setText(st::linkFont, song->title.isEmpty() ? (_song.song->name.isEmpty() ? qsl("Unknown Track") : _song.song->name) : song->title, _textNameOptions);
} else {
TextCustomTagsMap custom;
custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink()));
_name.setRichText(st::linkFont, QString::fromUtf8("[c]%1[/c] \xe2\x80\x93 %2").arg(textRichPrepare(song->performer)).arg(song->title.isEmpty() ? qsl("Unknown Track") : textRichPrepare(song->title)), _textNameOptions, custom);
}
updateControls();
}
qint64 position = 0, duration = 0, display = 0;
if (playing == _song) {
if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
display = position = playingPosition;
duration = playingDuration;
} else {
display = playingDuration;
}
display = display / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
} else if (_song) {
display = _song.song->song()->duration;
}
bool showPause = false, stopped = ((playingState & AudioPlayerStoppedMask) || playingState == AudioPlayerFinishing);
bool wasPlaying = !!_duration;
if (!stopped) {
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
}
QString time;
float64 progress = 0.;
int32 loaded;
float64 loadProgress = 1.;
if (duration || !_song.song->loader) {
time = (_down == OverPlayback) ? _time : formatDurationText(display);
progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.;
loaded = duration ? _song.song->size : 0;
} else {
loaded = _song.song->loader ? _song.song->loader->currentOffset() : 0;
time = formatDownloadText(loaded, _song.song->size);
loadProgress = snap(float64(loaded) / qMax(_song.song->size, 1), 0., 1.);
}
if (time != _time || showPause != _showPause) {
if (_time != time) {
_time = time;
_timeWidth = st::linkFont->m.width(_time);
}
_showPause = showPause;
if (duration != _duration || position != _position || loaded != _loaded) {
if (!songChanged && ((!stopped && duration && _duration) || (!duration && _loaded != loaded))) {
a_progress.start(progress);
a_loadProgress.start(loadProgress);
_progressAnim.start();
} else {
a_progress = anim::fvalue(progress, progress);
a_loadProgress = anim::fvalue(loadProgress, loadProgress);
_progressAnim.stop();
}
_position = position;
_duration = duration;
_loaded = loaded;
}
update();
} else if (duration != _duration || position != _position || loaded != _loaded) {
if (!songChanged && ((!stopped && duration && _duration) || (!duration && _loaded != loaded))) {
a_progress.start(progress);
a_loadProgress.start(loadProgress);
_progressAnim.start();
} else {
a_progress = anim::fvalue(progress, progress);
a_loadProgress = anim::fvalue(loadProgress, loadProgress);
_progressAnim.stop();
}
_position = position;
_duration = duration;
_loaded = loaded;
}
if (wasPlaying && playingState == AudioPlayerStoppedAtEnd) {
if (_repeat) {
startPlay(_song.msgId);
} else {
nextPressed();
}
}
if (songChanged) {
emit playerSongChanged(_song.msgId);
}
}

View File

@@ -0,0 +1,113 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "audio.h"
class PlayerWidget : public TWidget {
Q_OBJECT
public:
PlayerWidget(QWidget *parent);
void paintEvent(QPaintEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void leaveEvent(QEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void resizeEvent(QResizeEvent *e);
void playPressed();
void pausePressed();
void playPausePressed();
void prevPressed();
void nextPressed();
void stopPressed();
bool progressStep(float64 ms);
bool stateStep(float64 ms);
void updateState(SongMsgId playing, AudioPlayerState playingState, int64 playingPosition, int64 playingDuration, int32 playingFrequency);
void updateState();
void clearSelection();
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
bool seekingSong(const SongMsgId &song) const;
signals:
void playerSongChanged(MsgId msgId);
private:
enum OverState {
OverNone = 0,
OverPrev,
OverPlay,
OverNext,
OverClose,
OverVolume,
OverFull,
OverRepeat,
OverPlayback,
OverStateCount
};
void updateDownTime();
void updateOverState(OverState newState);
void updateOverRect(OverState state);
void updateControls();
void findCurrent();
void startPlay(MsgId msgId);
QPoint _lastMousePos;
void updateSelected();
bool _prevAvailable, _nextAvailable, _fullAvailable;
OverState _over, _down;
int32 _downCoord;
int64 _downDuration;
int32 _downFrequency;
float64 _downProgress;
float64 _stateHovers[OverStateCount];
typedef QMap<int32, uint64> StateAnimations;
StateAnimations _stateAnimations;
Animation _stateAnim;
SongMsgId _song;
int32 _index;
History *_history;
QRect _playRect, _prevRect, _nextRect, _playbackRect;
QRect _closeRect, _volumeRect, _fullRect, _repeatRect, _infoRect;
int32 _timeWidth;
bool _repeat;
QString _time;
Text _name;
bool _showPause;
int64 _position, _duration;
int32 _loaded;
anim::fvalue a_progress, a_loadProgress;
Animation _progressAnim;
};

View File

@@ -77,14 +77,21 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
if (_peerUser) {
_phoneText = _peerUser->phone.isEmpty() ? QString() : App::formatPhone(_peerUser->phone);
App::api()->requestFullPeer(_peer);
} else if (_peerChat->photoId) {
PhotoData *ph = App::photo(_peerChat->photoId);
if (ph->date) {
_photoLink = TextLinkPtr(new PhotoLink(ph, _peer));
PhotoData *userPhoto = (_peerUser->photoId && _peerUser->photoId != UnknownPeerPhotoId) ? App::photo(_peerUser->photoId) : 0;
if (userPhoto && userPhoto->date) {
_photoLink = TextLinkPtr(new PhotoLink(userPhoto, _peer));
}
if ((_peerUser->botInfo && !_peerUser->botInfo->inited) || (_peerUser->photoId == UnknownPeerPhotoId) || (_peerUser->photoId && !userPhoto->date)) {
App::api()->requestFullPeer(_peer);
}
} else {
App::api()->requestFullPeer(_peer);
PhotoData *chatPhoto = (_peerChat->photoId && _peerChat->photoId != UnknownPeerPhotoId) ? App::photo(_peerChat->photoId) : 0;
if (chatPhoto && chatPhoto->date) {
_photoLink = TextLinkPtr(new PhotoLink(chatPhoto, _peer));
}
if (_peerChat->photoId == UnknownPeerPhotoId) {
App::api()->requestFullPeer(_peer);
}
}
// profile
@@ -300,7 +307,6 @@ void ProfileInner::onMediaAudios() {
}
void ProfileInner::onInvitationLink() {
DEBUG_LOG(("Setting text to clipboard from invite url: %1").arg(_peerChat->invitationUrl));
QApplication::clipboard()->setText(_peerChat->invitationUrl);
App::wnd()->showLayer(new ConfirmBox(lang(lng_group_invite_copied), true));
}
@@ -326,7 +332,7 @@ void ProfileInner::chatInviteDone(const MTPExportedChatInvite &result) {
void ProfileInner::onFullPeerUpdated(PeerData *peer) {
if (peer != _peer) return;
if (_peerUser) {
PhotoData *userPhoto = _peerUser->photoId ? App::photo(_peerUser->photoId) : 0;
PhotoData *userPhoto = (_peerUser->photoId && _peerUser->photoId != UnknownPeerPhotoId) ? App::photo(_peerUser->photoId) : 0;
if (userPhoto && userPhoto->date) {
_photoLink = TextLinkPtr(new PhotoLink(userPhoto, _peer));
} else {
@@ -377,9 +383,9 @@ void ProfileInner::peerUpdated(PeerData *data) {
PhotoData *photo = 0;
if (_peerUser) {
_phoneText = _peerUser->phone.isEmpty() ? QString() : App::formatPhone(_peerUser->phone);
if (_peerUser->photoId) photo = App::photo(_peerUser->photoId);
if (_peerUser->photoId && _peerUser->photoId != UnknownPeerPhotoId) photo = App::photo(_peerUser->photoId);
} else {
if (_peerChat->photoId) photo = App::photo(_peerChat->photoId);
if (_peerChat->photoId && _peerChat->photoId != UnknownPeerPhotoId) photo = App::photo(_peerChat->photoId);
}
_photoLink = (photo && photo->date) ? TextLinkPtr(new PhotoLink(photo, _peer)) : TextLinkPtr();
if (_peer->name != _nameCache) {
@@ -512,7 +518,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
p.setPen(st::black->p);
p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + st::profileStatusTop + st::linkFont->ascent, '@' + _peerUser->username);
}
p.setPen((_peerUser && App::onlineColorUse(_peerUser->onlineTill, l_time) ? st::profileOnlineColor : st::profileOfflineColor)->p);
p.setPen((_peerUser && App::onlineColorUse(_peerUser, l_time) ? st::profileOnlineColor : st::profileOfflineColor)->p);
p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop + st::linkFont->ascent, _onlineText);
if (_chatAdmin && !_peerChat->invitationUrl.isEmpty()) {
p.setPen(st::black->p);
@@ -573,6 +579,8 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
p.setPen(st::black->p);
int oneState = 0; // < 0 - loading, 0 - no media, > 0 - link shown
for (int i = 0; i < OverviewCount; ++i) {
if (i == OverviewAudioDocuments) continue;
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
if (count < 0) {
if (!oneState) oneState = count;
@@ -643,7 +651,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
p.setFont(st::linkFont->f);
data->name.drawElided(p, _left + st::profileListPhotoSize + st::profileListPadding.width(), top + st::profileListNameTop, _width - _kickWidth - st::profileListPadding.width() - st::profileListPhotoSize - st::profileListPadding.width());
p.setFont(st::profileSubFont->f);
p.setPen((App::onlineColorUse(user->onlineTill, l_time) ? st::profileOnlineColor : st::profileOfflineColor)->p);
p.setPen((App::onlineColorUse(user, l_time) ? st::profileOnlineColor : st::profileOfflineColor)->p);
p.drawText(_left + st::profileListPhotoSize + st::profileListPadding.width(), top + st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, data->online);
if (data->cankick) {
@@ -853,6 +861,8 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
_mediaShowAll.move(_left + _width - _mediaShowAll.width(), top);
int wasCount = 0; // < 0 - loading, 0 - no media, > 0 - link shown
for (int i = 0; i < OverviewCount; ++i) {
if (i == OverviewAudioDocuments) continue;
if (_allMediaTypes) {
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
if (count > 0) {
@@ -906,12 +916,10 @@ void ProfileInner::onMenuDestroy(QObject *obj) {
}
void ProfileInner::onCopyPhone() {
DEBUG_LOG(("Setting text to clipboard from user phone: %1").arg(_phoneText));
QApplication::clipboard()->setText(_phoneText);
}
void ProfileInner::onCopyUsername() {
DEBUG_LOG(("Setting text to clipboard from username: @%1").arg(_peerUser->username));
QApplication::clipboard()->setText('@' + _peerUser->username);
}
@@ -953,7 +961,7 @@ void ProfileInner::updateNotifySettings() {
_enableNotifications.setChecked(_peer->notify == EmptyNotifySettings || _peer->notify == UnknownNotifySettings || _peer->notify->mute < unixtime());
}
void ProfileInner::mediaOverviewUpdated(PeerData *peer) {
void ProfileInner::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
if (peer == _peer) {
resizeEvent(0);
showAll();
@@ -1025,6 +1033,8 @@ void ProfileInner::showAll() {
// shared media
bool first = false, wasCount = false, manyCounts = false;
for (int i = 0; i < OverviewCount; ++i) {
if (i == OverviewAudioDocuments) continue;
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
if (count > 0) {
if (wasCount) {
@@ -1079,9 +1089,9 @@ void ProfileInner::updateInvitationLink() {
} else {
_createInvitationLink.setText(lang(lng_group_invite_create_new));
_invitationText = _peerChat->invitationUrl;
if (_invitationText.startsWith(QLatin1String("http://"), Qt::CaseInsensitive)) {
if (_invitationText.startsWith(qstr("http://"), Qt::CaseInsensitive)) {
_invitationText = _invitationText.mid(7);
} else if (_invitationText.startsWith(QLatin1String("https://"), Qt::CaseInsensitive)) {
} else if (_invitationText.startsWith(qstr("https://"), Qt::CaseInsensitive)) {
_invitationText = _invitationText.mid(8);
}
}
@@ -1132,8 +1142,13 @@ void ProfileWidget::onScroll() {
}
void ProfileWidget::resizeEvent(QResizeEvent *e) {
int32 addToY = App::main() ? App::main()->contentScrollAddToY() : 0;
int32 newScrollY = _scroll.scrollTop() + addToY;
_scroll.resize(size());
_inner.resize(width(), _inner.height());
if (addToY) {
_scroll.scrollToY(newScrollY);
}
}
void ProfileWidget::mousePressEvent(QMouseEvent *e) {
@@ -1172,6 +1187,13 @@ void ProfileWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth)
}
}
void ProfileWidget::topBarShadowParams(int32 &x, float64 &o) {
if (animating() && a_coord.current() >= 0) {
x = a_coord.current();
o = a_alpha.current();
}
}
void ProfileWidget::topBarClick() {
App::main()->showBackFromStack();
}
@@ -1249,8 +1271,8 @@ void ProfileWidget::updateNotifySettings() {
_inner.updateNotifySettings();
}
void ProfileWidget::mediaOverviewUpdated(PeerData *peer) {
_inner.mediaOverviewUpdated(peer);
void ProfileWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
_inner.mediaOverviewUpdated(peer, type);
}
void ProfileWidget::clear() {

View File

@@ -53,7 +53,7 @@ public:
void loadProfilePhotos(int32 yFrom);
void updateNotifySettings();
void mediaOverviewUpdated(PeerData *peer);
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
~ProfileInner();
@@ -187,6 +187,7 @@ public:
void dropEvent(QDropEvent *e);
void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
void topBarShadowParams(int32 &x, float64 &o);
void topBarClick();
PeerData *peer() const;
@@ -200,7 +201,7 @@ public:
void updateOnlineDisplayTimer();
void updateNotifySettings();
void mediaOverviewUpdated(PeerData *peer);
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
void clear();
~ProfileWidget();

View File

@@ -352,7 +352,7 @@ namespace {
public:
_PsInitializer() {
QString cdesktop = QString(getenv("XDG_CURRENT_DESKTOP")).toLower();
noQtTrayIcon = (cdesktop == QLatin1String("unity")) || (cdesktop == QLatin1String("pantheon")) || (cdesktop == QLatin1String("gnome"));
noQtTrayIcon = (cdesktop == qstr("unity")) || (cdesktop == qstr("pantheon")) || (cdesktop == qstr("gnome"));
if (noQtTrayIcon) cSetSupportTray(false);
std::cout << "libs init..\n";
@@ -460,7 +460,7 @@ namespace {
void setupUnity() {
if (!useGtkBase || !noQtTrayIcon) return;
QLibrary lib_unity(QLatin1String("unity"), 9, 0);
QLibrary lib_unity(qstr("unity"), 9, 0);
if (!loadLibrary(lib_unity, "unity", 9)) return;
if (!loadFunction(lib_unity, "unity_launcher_entry_get_for_desktop_id", ps_unity_launcher_entry_get_for_desktop_id)) return;

View File

@@ -41,7 +41,7 @@ namespace {
Window *wnd = Application::wnd();
if (!wnd) return false;
return false;
return wnd->psFilterNativeEvent(message);
}
};
_PsEventFilter *_psEventFilter = 0;
@@ -460,6 +460,10 @@ void PsMainWindow::psActivateNotify(NotifyWindow *w) {
objc_activateWnd(w->winId());
}
bool PsMainWindow::psFilterNativeEvent(void *event) {
return _private.filterNativeEvent(event);
}
namespace {
QRect _monitorRect;
uint64 _monitorLastGot = 0;

View File

@@ -36,7 +36,7 @@ public:
void darkModeChanged();
void notifyClicked(unsigned long long peer, int msgid);
void notifyReplied(unsigned long long peer, int msgid, const char *str);
};
class NotifyWindow;
@@ -72,6 +72,8 @@ public:
return posInited;
}
bool psFilterNativeEvent(void *event);
void psActivateNotify(NotifyWindow *w);
void psClearNotifies(PeerId peerId = 0);
void psNotifyShown(NotifyWindow *w);

View File

@@ -33,7 +33,9 @@ public:
void clearNotifies(uint64 peer = 0);
void enableShadow(WId winId);
bool filterNativeEvent(void *event);
virtual void activeSpaceChanged() {
}
virtual void darkModeChanged() {

View File

@@ -19,6 +19,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "pspecific_mac_p.h"
#include "window.h"
#include "mainwidget.h"
#include "application.h"
#include "lang.h"
@@ -27,6 +28,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CFURL.h>
#include <IOKit/hidsystem/ev_keymap.h>
@interface qVisualize : NSObject {
}
@@ -304,6 +307,41 @@ void PsMacWindowPrivate::enableShadow(WId winId) {
// [[(NSView*)winId window] setHasShadow:YES];
}
bool PsMacWindowPrivate::filterNativeEvent(void *event) {
NSEvent *e = static_cast<NSEvent*>(event);
if (e && [e type] == NSSystemDefined && [e subtype] == 8) {
int keyCode = (([e data1] & 0xFFFF0000) >> 16);
int keyFlags = ([e data1] & 0x0000FFFF);
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
int keyRepeat = (keyFlags & 0x1);
switch (keyCode) {
case NX_KEYTYPE_PLAY:
if (keyState == 0) { // Play pressed and released
if (App::main()) App::main()->player()->playPausePressed();
return true;
}
break;
case NX_KEYTYPE_FAST:
if (keyState == 0) { // Next pressed and released
if (App::main()) App::main()->player()->nextPressed();
return true;
}
break;
case NX_KEYTYPE_REWIND:
if (keyState == 0) { // Previous pressed and released
if (App::main()) App::main()->player()->prevPressed();
return true;
}
break;
}
}
return false;
}
void PsMacWindowPrivate::clearNotifies(unsigned long long peer) {
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
if (peer) {

View File

@@ -52,6 +52,11 @@ bool gSupportTray = true;
DBIWorkMode gWorkMode = dbiwmWindowAndTray;
DBIConnectionType gConnectionType = dbictAuto;
ConnectionProxy gConnectionProxy;
#ifdef Q_OS_WIN
bool gTryIPv6 = false;
#else
bool gTryIPv6 = true;
#endif
bool gSeenTrayTooltip = false;
bool gRestartingUpdate = false, gRestarting = false, gRestartingToSettings = false, gWriteProtected = false;
int32 gLastUpdateCheck = 0;
@@ -94,8 +99,6 @@ EmojiColorVariants gEmojiVariants;
QByteArray gStickersHash;
EmojiStickersMap gEmojiStickers;
RecentStickerPreload gRecentStickersPreload;
RecentStickerPack gRecentStickers;
StickerSets gStickerSets;
@@ -153,6 +156,8 @@ int gNotifyDefaultDelay = 1500;
int gOtherOnline = 0;
float64 gSongVolume = 0.9;
void settingsParseArgs(int argc, char *argv[]) {
#ifdef Q_OS_MAC
gCustomNotifies = (QSysInfo::macVersion() < QSysInfo::MV_10_8);
@@ -286,7 +291,7 @@ RecentStickerPack &cGetRecentStickers() {
recent.reserve(p.size());
for (RecentStickerPreload::const_iterator i = p.cbegin(), e = p.cend(); i != e; ++i) {
DocumentData *doc = App::document(i->first);
if (!doc || !doc->sticker) continue;
if (!doc || !doc->sticker()) continue;
recent.push_back(qMakePair(doc, i->second));
}

View File

@@ -109,6 +109,7 @@ DeclareSetting(TWindowPos, WindowPos);
DeclareSetting(bool, SupportTray);
DeclareSetting(DBIWorkMode, WorkMode);
DeclareSetting(DBIConnectionType, ConnectionType);
DeclareSetting(bool, TryIPv6);
DeclareSetting(DBIDefaultAttach, DefaultAttach);
DeclareSetting(ConnectionProxy, ConnectionProxy);
DeclareSetting(bool, SeenTrayTooltip);
@@ -188,9 +189,6 @@ struct DocumentData;
typedef QVector<DocumentData*> StickerPack;
DeclareSetting(QByteArray, StickersHash);
typedef QMap<DocumentData*, EmojiPtr> EmojiStickersMap;
DeclareSetting(EmojiStickersMap, EmojiStickers);
typedef QList<QPair<DocumentData*, int16> > RecentStickerPackOld;
typedef QVector<QPair<uint64, ushort> > RecentStickerPreload;
typedef QVector<QPair<DocumentData*, ushort> > RecentStickerPack;
@@ -201,12 +199,14 @@ RecentStickerPack &cGetRecentStickers();
DeclareSetting(uint64, LastStickersUpdate);
static const uint64 DefaultStickerSetId = 0, CustomStickerSetId = 0xFFFFFFFFFFFFFFFFLLU, RecentStickerSetId = 0xFFFFFFFFFFFFFFFELLU;
static const uint64 DefaultStickerSetId = 0; // for backward compatibility
static const uint64 CustomStickerSetId = 0xFFFFFFFFFFFFFFFFLLU, RecentStickerSetId = 0xFFFFFFFFFFFFFFFELLU;
struct StickerSet {
StickerSet(uint64 id, uint64 access, const QString &title, const QString &shortName) : id(id), access(access), title(title), shortName(shortName) {
StickerSet(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, int32 flags) : id(id), access(access), title(title), shortName(shortName), count(count), hash(hash), flags(flags) {
}
uint64 id, access;
QString title, shortName;
int32 count, hash, flags;
StickerPack stickers;
};
typedef QMap<uint64, StickerSet> StickerSets;
@@ -304,4 +304,6 @@ DeclareSetting(int, NotifyDefaultDelay);
DeclareSetting(int, OtherOnline);
DeclareSetting(float64, SongVolume);
void settingsParseArgs(int argc, char *argv[]);

View File

@@ -182,7 +182,7 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
_passwordEdit(this, lang(lng_cloud_password_set)),
_passwordTurnOff(this, lang(lng_passcode_turn_off)),
_hasPasswordRecovery(false),
_connectionType(this, lng_connection_auto(lt_type, QString())),
_connectionType(this, lang(lng_connection_auto_connecting)),
_connectionTypeText(lang(lng_connection_type) + ' '),
_connectionTypeWidth(st::linkFont->m.width(_connectionTypeText)),
_showSessions(this, lang(lng_settings_show_sessions)),
@@ -190,7 +190,7 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
{
if (self()) {
_nameText.setText(st::setNameFont, _nameCache, _textNameOptions);
PhotoData *selfPhoto = self()->photoId ? App::photo(self()->photoId) : 0;
PhotoData *selfPhoto = (self()->photoId && self()->photoId != UnknownPeerPhotoId) ? App::photo(self()->photoId) : 0;
if (selfPhoto && selfPhoto->date) _photoLink = TextLinkPtr(new PhotoLink(selfPhoto, self()));
MTP::send(MTPusers_GetFullUser(self()->inputUser), rpcDone(&SettingsInner::gotFullSelf), RPCFailHandlerPtr(), 0, 10);
onReloadPassword();
@@ -312,7 +312,7 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
void SettingsInner::peerUpdated(PeerData *data) {
if (self() && data == self()) {
if (self()->photoId) {
if (self()->photoId && self()->photoId != UnknownPeerPhotoId) {
PhotoData *selfPhoto = App::photo(self()->photoId);
if (selfPhoto->date) {
_photoLink = TextLinkPtr(new PhotoLink(selfPhoto, self()));
@@ -731,14 +731,14 @@ void SettingsInner::keyPressEvent(QKeyEvent *e) {
int32 size = _secretText.size(), from = 0;
while (size > from) {
QStringRef str(_secretText.midRef(from));
if (str == QLatin1String("debugmode")) {
if (str == qstr("debugmode")) {
QString text = cDebug() ? qsl("Do you want to disable DEBUG logs?") : qsl("Do you want to enable DEBUG logs?\n\nAll network events will be logged.");
ConfirmBox *box = new ConfirmBox(text);
connect(box, SIGNAL(confirmed()), App::app(), SLOT(onSwitchDebugMode()));
App::wnd()->showLayer(box);
from = size;
break;
} else if (str == QLatin1String("testmode")) {
} else if (str == qstr("testmode")) {
QString text = cTestMode() ? qsl("Do you want to disable TEST mode?") : qsl("Do you want to enable TEST mode?\n\nYou will be switched to test cloud.");
ConfirmBox *box = new ConfirmBox(text);
connect(box, SIGNAL(confirmed()), App::app(), SLOT(onSwitchTestMode()));
@@ -820,18 +820,19 @@ void SettingsInner::updateOnlineDisplay() {
}
void SettingsInner::updateConnectionType() {
QString connection;
switch (cConnectionType()) {
case dbictAuto: {
QString transport = MTP::dctransport();
if (transport.isEmpty()) {
_connectionType.setText(lang(lng_connection_auto_connecting));
} else {
_connectionType.setText(lng_connection_auto(lt_type, transport));
}
connection = transport.isEmpty() ? lang(lng_connection_auto_connecting) : lng_connection_auto(lt_transport, transport);
} break;
case dbictHttpProxy:
case dbictTcpProxy: {
QString transport = MTP::dctransport();
connection = transport.isEmpty() ? lang(lng_connection_proxy_connecting) : lng_connection_proxy(lt_transport, transport);
} break;
case dbictHttpProxy: _connectionType.setText(lang(lng_connection_http_proxy)); break;
case dbictTcpProxy: _connectionType.setText(lang(lng_connection_tcp_proxy)); break;
}
_connectionType.setText(connection);
}
void SettingsInner::passcodeChanged() {
@@ -850,7 +851,7 @@ void SettingsInner::gotFullSelf(const MTPUserFull &selfFull) {
if (!self()) return;
App::feedPhoto(selfFull.c_userFull().vprofile_photo);
App::feedUsers(MTP_vector<MTPUser>(1, selfFull.c_userFull().vuser));
PhotoData *selfPhoto = self()->photoId ? App::photo(self()->photoId) : 0;
PhotoData *selfPhoto = (self()->photoId && self()->photoId != UnknownPeerPhotoId) ? App::photo(self()->photoId) : 0;
if (selfPhoto && selfPhoto->date) {
_photoLink = TextLinkPtr(new PhotoLink(selfPhoto, self()));
} else {

View File

@@ -126,30 +126,38 @@ void PeerData::updateName(const QString &newName, const QString &newNameOrPhone,
NameFirstChars oldChars = chars;
fillNames();
App::history(id)->updateNameText();
nameUpdated();
if (App::main()) {
emit App::main()->peerNameChanged(this, oldNames, oldChars);
}
nameUpdated();
}
void UserData::setPhoto(const MTPUserProfilePhoto &p) {
PhotoId newPhotoId = photoId;
ImagePtr newPhoto = photo;
switch (p.type()) {
case mtpc_userProfilePhoto: {
const MTPDuserProfilePhoto d(p.c_userProfilePhoto());
photoId = d.vphoto_id.v;
photo = ImagePtr(160, 160, d.vphoto_small, userDefPhoto(colorIndex));
// App::feedPhoto(App::photoFromUserPhoto(MTP_int(id & 0xFFFFFFFF), MTP_int(unixtime()), p));
newPhotoId = d.vphoto_id.v;
newPhoto = ImagePtr(160, 160, d.vphoto_small, userDefPhoto(colorIndex));
//App::feedPhoto(App::photoFromUserPhoto(MTP_int(id & 0xFFFFFFFF), MTP_int(unixtime()), p));
} break;
default: {
photoId = 0;
newPhotoId = 0;
if (id == ServiceUserId) {
photo = ImagePtr(QPixmap::fromImage(App::wnd()->iconLarge().scaledToWidth(160, Qt::SmoothTransformation), Qt::ColorOnly), "PNG");
if (photo->isNull()) {
newPhoto = ImagePtr(QPixmap::fromImage(App::wnd()->iconLarge().scaledToWidth(160, Qt::SmoothTransformation), Qt::ColorOnly), "PNG");
}
} else {
photo = userDefPhoto(colorIndex);
newPhoto = userDefPhoto(colorIndex);
}
} break;
}
emit App::main()->peerPhotoChanged(this);
if (newPhotoId != photoId || newPhoto.v() != photo.v()) {
photoId = newPhotoId;
photo = newPhoto;
emit App::main()->peerPhotoChanged(this);
}
}
void PeerData::fillNames() {
@@ -198,7 +206,6 @@ void UserData::setName(const QString &first, const QString &last, const QString
void UserData::setPhone(const QString &newPhone) {
phone = newPhone;
++nameVersion;
}
void UserData::setBotInfoVersion(int32 version) {
@@ -209,7 +216,10 @@ void UserData::setBotInfoVersion(int32 version) {
botInfo = new BotInfo();
botInfo->version = version;
} else if (botInfo->version < version) {
botInfo->commands.clear();
if (!botInfo->commands.isEmpty()) {
botInfo->commands.clear();
if (App::main()) App::main()->botCommandsChanged(this);
}
botInfo->description.clear();
botInfo->shareText.clear();
botInfo->version = version;
@@ -219,6 +229,9 @@ void UserData::setBotInfoVersion(int32 version) {
void UserData::setBotInfo(const MTPBotInfo &info) {
switch (info.type()) {
case mtpc_botInfoEmpty:
if (botInfo && !botInfo->commands.isEmpty()) {
if (App::main()) App::main()->botCommandsChanged(this);
}
delete botInfo;
botInfo = 0;
break;
@@ -240,15 +253,37 @@ void UserData::setBotInfo(const MTPBotInfo &info) {
botInfo->shareText = qs(d.vshare_text);
const QVector<MTPBotCommand> &v(d.vcommands.c_vector().v);
botInfo->commands.clear();
botInfo->commands.reserve(v.size());
bool changedCommands = false;
int32 j = 0;
for (int32 i = 0, l = v.size(); i < l; ++i) {
if (v.at(i).type() == mtpc_botCommand) {
botInfo->commands.push_back(BotCommand(qs(v.at(i).c_botCommand().vcommand), qs(v.at(i).c_botCommand().vdescription)));
if (v.at(i).type() != mtpc_botCommand) continue;
QString cmd = qs(v.at(i).c_botCommand().vcommand), desc = qs(v.at(i).c_botCommand().vdescription);
if (botInfo->commands.size() <= j) {
botInfo->commands.push_back(BotCommand(cmd, desc));
changedCommands = true;
} else {
if (botInfo->commands[j].command != cmd) {
botInfo->commands[j].command = cmd;
changedCommands = true;
}
if (botInfo->commands[j].setDescription(desc)) {
changedCommands = true;
}
}
++j;
}
while (j < botInfo->commands.size()) {
botInfo->commands.pop_back();
changedCommands = true;
}
botInfo->inited = true;
if (changedCommands && App::main()) {
App::main()->botCommandsChanged(this);
}
} break;
}
}
@@ -258,13 +293,15 @@ void UserData::nameUpdated() {
}
void UserData::madeAction() {
if (botInfo || isServiceUser(id)) return;
int32 t = unixtime();
if (onlineTill <= 0 && -onlineTill < t) {
onlineTill = -t - SetOnlineAfterActivity;
if (App::main()) App::main()->peerUpdated(this);
App::markPeerUpdated(this);
} else if (onlineTill > 0 && onlineTill < t + 1) {
onlineTill = t + SetOnlineAfterActivity;
if (App::main()) App::main()->peerUpdated(this);
App::markPeerUpdated(this);
}
}
@@ -274,7 +311,7 @@ void ChatData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) {
const MTPDchatPhoto d(p.c_chatPhoto());
photo = ImagePtr(160, 160, d.vphoto_small, chatDefPhoto(colorIndex));
photoFull = ImagePtr(640, 640, d.vphoto_big, chatDefPhoto(colorIndex));
if (phId) {
if (phId != UnknownPeerPhotoId) {
photoId = phId;
}
} break;
@@ -433,16 +470,16 @@ void AudioOpenLink::onClick(Qt::MouseButton button) const {
if ((!data->user && !data->date) || button != Qt::LeftButton) return;
QString already = data->already(true);
bool play = audioPlayer();
bool play = App::hoveredLinkItem() && audioPlayer();
if (!already.isEmpty() || (!data->data.isEmpty() && play)) {
if (play) {
AudioData *playing = 0;
AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing == data && playingState != AudioPlayerStopped) {
audioPlayer()->pauseresume();
if (playing.msgId == App::hoveredLinkItem()->id && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewAudios);
} else {
audioPlayer()->play(data);
audioPlayer()->play(AudioMsgId(data, App::hoveredLinkItem()->id));
if (App::main()) App::main()->audioMarkRead(data);
}
} else {
@@ -454,7 +491,7 @@ void AudioOpenLink::onClick(Qt::MouseButton button) const {
if (data->status != FileReady) return;
bool mp3 = (data->mime == QLatin1String("audio/mp3"));
bool mp3 = (data->mime == qstr("audio/mp3"));
QString filename = saveFileName(lang(lng_save_audio), mp3 ? qsl("MP3 Audio (*.mp3);;All files (*.*)") : qsl("OGG Opus Audio (*.ogg);;All files (*.*)"), qsl("audio"), mp3 ? qsl(".mp3") : qsl(".ogg"), false);
if (!filename.isEmpty()) {
data->openOnSave = 1;
@@ -475,7 +512,7 @@ void AudioSaveLink::doSave(AudioData *data, bool forceSavingAs) {
} else {
QFileInfo alreadyInfo(already);
QDir alreadyDir(already.isEmpty() ? QDir() : alreadyInfo.dir());
bool mp3 = (data->mime == QLatin1String("audio/mp3"));
bool mp3 = (data->mime == qstr("audio/mp3"));
QString name = already.isEmpty() ? (mp3 ? qsl(".mp3") : qsl(".ogg")) : alreadyInfo.fileName();
QString filename = saveFileName(lang(lng_save_audio), mp3 ? qsl("MP3 Audio (*.mp3);;All files (*.*)") : qsl("OGG Opus Audio (*.ogg);;All files (*.*)"), qsl("audio"), name, forceSavingAs, alreadyDir);
if (!filename.isEmpty()) {
@@ -536,13 +573,24 @@ QString AudioData::already(bool check) {
return location.name;
}
void DocumentOpenLink::onClick(Qt::MouseButton button) const {
DocumentData *data = document();
if (!data->date || button != Qt::LeftButton) return;
void DocumentOpenLink::doOpen(DocumentData *data) {
if (!data->date) return;
bool play = data->song() && App::hoveredLinkItem() && audioPlayer();
QString already = data->already(true);
if (!already.isEmpty()) {
if (data->size < MediaViewImageSizeLimit) {
if (!already.isEmpty() || (!data->data.isEmpty() && play)) {
if (play) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing.msgId == App::hoveredLinkItem()->id && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewDocuments);
} else {
SongMsgId song(data, App::hoveredLinkItem()->id);
audioPlayer()->play(song);
if (App::main()) App::main()->documentPlayProgress(song);
}
} else if (data->size < MediaViewImageSizeLimit) {
QImageReader reader(already);
if (reader.canRead()) {
if (reader.supportsAnimation() && reader.imageCount() > 1 && App::hoveredLinkItem()) {
@@ -585,6 +633,11 @@ void DocumentOpenLink::onClick(Qt::MouseButton button) const {
}
}
void DocumentOpenLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
doOpen(document());
}
void DocumentSaveLink::doSave(DocumentData *data, bool forceSavingAs) {
if (!data->date) return;
@@ -637,7 +690,7 @@ void DocumentCancelLink::onClick(Qt::MouseButton button) const {
}
DocumentData::DocumentData(const DocumentId &id, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) :
id(id), type(FileDocument), duration(0), access(access), date(date), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0), sticker(0) {
id(id), type(FileDocument), access(access), date(date), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0), _additional(0) {
setattributes(attributes);
location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
}
@@ -649,12 +702,17 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
const MTPDdocumentAttributeImageSize &d(attributes[i].c_documentAttributeImageSize());
dimensions = QSize(d.vw.v, d.vh.v);
} break;
case mtpc_documentAttributeAnimated: if (type == FileDocument || type == StickerDocument) type = AnimatedDocument; break;
case mtpc_documentAttributeAnimated: if (type == FileDocument || type == StickerDocument) {
type = AnimatedDocument;
delete _additional;
_additional = 0;
} break;
case mtpc_documentAttributeSticker: {
const MTPDdocumentAttributeSticker &d(attributes[i].c_documentAttributeSticker());
if (type == FileDocument) type = StickerDocument;
if (type == StickerDocument && !sticker) sticker = new StickerData();
if (sticker) {
if (type == FileDocument) {
type = StickerDocument;
StickerData *sticker = new StickerData();
_additional = sticker;
sticker->alt = qs(d.valt);
sticker->set = d.vstickerset;
}
@@ -662,17 +720,28 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
case mtpc_documentAttributeVideo: {
const MTPDdocumentAttributeVideo &d(attributes[i].c_documentAttributeVideo());
type = VideoDocument;
duration = d.vduration.v;
// duration = d.vduration.v;
dimensions = QSize(d.vw.v, d.vh.v);
} break;
case mtpc_documentAttributeAudio: {
const MTPDdocumentAttributeAudio &d(attributes[i].c_documentAttributeAudio());
type = AudioDocument;
duration = d.vduration.v;
type = SongDocument;
SongData *song = new SongData();
_additional = song;
song->duration = d.vduration.v;
song->title = qs(d.vtitle);
song->performer = qs(d.vperformer);
} break;
case mtpc_documentAttributeFilename: name = qs(attributes[i].c_documentAttributeFilename().vfile_name); break;
}
}
if (type == StickerDocument) {
if (dimensions.width() <= 0 || dimensions.height() <= 0 || dimensions.width() > StickerMaxSize || dimensions.height() > StickerMaxSize || size > StickerInMemory) {
type = FileDocument;
delete _additional;
_additional = 0;
}
}
}
void DocumentData::save(const QString &toFile) {

View File

@@ -106,6 +106,8 @@ struct PeerData {
static const uint64 UserNoAccess = 0xFFFFFFFFFFFFFFFFULL;
class PeerLink : public ITextLink {
TEXT_LINK_CLASS(PeerLink)
public:
PeerLink(PeerData *peer) : _peer(peer) {
}
@@ -118,11 +120,35 @@ private:
PeerData *_peer;
};
struct BotCommand {
BotCommand(const QString &command, const QString &description) : command(command), description(description) {
class BotCommand {
public:
BotCommand(const QString &command, const QString &description) : command(command), _description(description) {
}
QString command, description;
QString command;
bool setDescription(const QString &description) {
if (_description != description) {
_description = description;
_descriptionText = Text();
return true;
}
return false;
}
const Text &descriptionText() const {
if (_descriptionText.isEmpty() && !_description.isEmpty()) {
_descriptionText.setText(st::mentionFont, _description, _textNameOptions);
}
return _descriptionText;
}
private:
QString _description;
mutable Text _descriptionText;
};
struct BotInfo {
BotInfo() : inited(false), readsAllHistory(false), cantJoinGroups(false), version(0), text(st::msgMinWidth) {
}
@@ -136,9 +162,11 @@ struct BotInfo {
QString startToken, startGroupToken;
};
static const PhotoId UnknownPeerPhotoId = 0xFFFFFFFFFFFFFFFFULL;
struct PhotoData;
struct UserData : public PeerData {
UserData(const PeerId &id) : PeerData(id), photoId(0), lnk(new PeerLink(this)), onlineTill(0), contact(-1), photosCount(-1), botInfo(0) {
UserData(const PeerId &id) : PeerData(id), photoId(UnknownPeerPhotoId), lnk(new PeerLink(this)), onlineTill(0), contact(-1), photosCount(-1), botInfo(0) {
}
void setPhoto(const MTPUserProfilePhoto &photo);
void setName(const QString &first, const QString &last, const QString &phoneName, const QString &username);
@@ -167,9 +195,9 @@ struct UserData : public PeerData {
};
struct ChatData : public PeerData {
ChatData(const PeerId &id) : PeerData(id), count(0), date(0), version(0), left(false), forbidden(true), botStatus(0), photoId(0) {
ChatData(const PeerId &id) : PeerData(id), count(0), date(0), version(0), left(false), forbidden(true), botStatus(0), photoId(UnknownPeerPhotoId) {
}
void setPhoto(const MTPChatPhoto &photo, const PhotoId &phId = 0);
void setPhoto(const MTPChatPhoto &photo, const PhotoId &phId = UnknownPeerPhotoId);
int32 count;
int32 date;
int32 version;
@@ -234,6 +262,8 @@ struct PhotoData {
};
class PhotoLink : public ITextLink {
TEXT_LINK_CLASS(PhotoLink)
public:
PhotoLink(PhotoData *photo) : _photo(photo), _peer(0) {
}
@@ -313,6 +343,8 @@ struct VideoData {
};
class VideoLink : public ITextLink {
TEXT_LINK_CLASS(VideoLink)
public:
VideoLink(VideoData *video) : _video(video) {
}
@@ -325,6 +357,8 @@ private:
};
class VideoSaveLink : public VideoLink {
TEXT_LINK_CLASS(VideoSaveLink)
public:
VideoSaveLink(VideoData *video) : VideoLink(video) {
}
@@ -333,6 +367,8 @@ public:
};
class VideoOpenLink : public VideoLink {
TEXT_LINK_CLASS(VideoOpenLink)
public:
VideoOpenLink(VideoData *video) : VideoLink(video) {
}
@@ -340,6 +376,8 @@ public:
};
class VideoCancelLink : public VideoLink {
TEXT_LINK_CLASS(VideoCancelLink)
public:
VideoCancelLink(VideoData *video) : VideoLink(video) {
}
@@ -399,7 +437,30 @@ struct AudioData {
int32 md5[8];
};
struct AudioMsgId {
AudioMsgId() : audio(0), msgId(0) {
}
AudioMsgId(AudioData *audio, MsgId msgId) : audio(audio), msgId(msgId) {
}
operator bool() const {
return audio;
}
AudioData *audio;
MsgId msgId;
};
inline bool operator<(const AudioMsgId &a, const AudioMsgId &b) {
return quintptr(a.audio) < quintptr(b.audio) || (quintptr(a.audio) == quintptr(b.audio) && a.msgId < b.msgId);
}
inline bool operator==(const AudioMsgId &a, const AudioMsgId &b) {
return a.audio == b.audio && a.msgId == b.msgId;
}
inline bool operator!=(const AudioMsgId &a, const AudioMsgId &b) {
return !(a == b);
}
class AudioLink : public ITextLink {
TEXT_LINK_CLASS(AudioLink)
public:
AudioLink(AudioData *audio) : _audio(audio) {
}
@@ -412,6 +473,8 @@ private:
};
class AudioSaveLink : public AudioLink {
TEXT_LINK_CLASS(AudioSaveLink)
public:
AudioSaveLink(AudioData *audio) : AudioLink(audio) {
}
@@ -420,6 +483,8 @@ public:
};
class AudioOpenLink : public AudioLink {
TEXT_LINK_CLASS(AudioOpenLink)
public:
AudioOpenLink(AudioData *audio) : AudioLink(audio) {
}
@@ -427,13 +492,26 @@ public:
};
class AudioCancelLink : public AudioLink {
TEXT_LINK_CLASS(AudioCancelLink)
public:
AudioCancelLink(AudioData *audio) : AudioLink(audio) {
}
void onClick(Qt::MouseButton button) const;
};
struct StickerData {
enum DocumentType {
FileDocument = 0,
VideoDocument = 1,
SongDocument = 2,
StickerDocument = 3,
AnimatedDocument = 4,
};
struct DocumentAdditionalData {
};
struct StickerData : public DocumentAdditionalData {
StickerData() : set(MTP_inputStickerSetEmpty()) {
}
ImagePtr img;
@@ -445,20 +523,20 @@ struct StickerData {
StorageImageLocation loc; // doc thumb location
};
enum DocumentType {
FileDocument,
VideoDocument,
AudioDocument,
StickerDocument,
AnimatedDocument
struct SongData : public DocumentAdditionalData {
SongData() : duration(0) {
}
int32 duration;
QString title, performer;
};
struct DocumentData {
DocumentData(const DocumentId &id, const uint64 &access = 0, int32 date = 0, const QVector<MTPDocumentAttribute> &attributes = QVector<MTPDocumentAttribute>(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0);
void setattributes(const QVector<MTPDocumentAttribute> &attributes);
void forget() {
thumb->forget();
if (sticker) sticker->img->forget();
if (sticker()) sticker()->img->forget();
replyPreview->forget();
}
@@ -488,15 +566,20 @@ struct DocumentData {
loader = 0;
}
~DocumentData() {
delete sticker;
delete _additional;
}
QString already(bool check = false);
StickerData *sticker() {
return (type == StickerDocument) ? static_cast<StickerData*>(_additional) : 0;
}
SongData *song() {
return (type == SongDocument) ? static_cast<SongData*>(_additional) : 0;
}
DocumentId id;
DocumentType type;
QSize dimensions;
int32 duration;
uint64 access;
int32 date;
QString name, mime;
@@ -512,12 +595,35 @@ struct DocumentData {
FileLocation location;
QByteArray data;
StickerData *sticker;
DocumentAdditionalData *_additional;
int32 md5[8];
};
struct SongMsgId {
SongMsgId() : song(0), msgId(0) {
}
SongMsgId(DocumentData *song, MsgId msgId) : song(song), msgId(msgId) {
}
operator bool() const {
return song;
}
DocumentData *song;
MsgId msgId;
};
inline bool operator<(const SongMsgId &a, const SongMsgId &b) {
return quintptr(a.song) < quintptr(b.song) || (quintptr(a.song) == quintptr(b.song) && a.msgId < b.msgId);
}
inline bool operator==(const SongMsgId &a, const SongMsgId &b) {
return a.song == b.song && a.msgId == b.msgId;
}
inline bool operator!=(const SongMsgId &a, const SongMsgId &b) {
return !(a == b);
}
class DocumentLink : public ITextLink {
TEXT_LINK_CLASS(DocumentLink)
public:
DocumentLink(DocumentData *document) : _document(document) {
}
@@ -530,6 +636,8 @@ private:
};
class DocumentSaveLink : public DocumentLink {
TEXT_LINK_CLASS(DocumentSaveLink)
public:
DocumentSaveLink(DocumentData *document) : DocumentLink(document) {
}
@@ -538,13 +646,18 @@ public:
};
class DocumentOpenLink : public DocumentLink {
TEXT_LINK_CLASS(DocumentOpenLink)
public:
DocumentOpenLink(DocumentData *document) : DocumentLink(document) {
}
static void doOpen(DocumentData *document);
void onClick(Qt::MouseButton button) const;
};
class DocumentCancelLink : public DocumentLink {
TEXT_LINK_CLASS(DocumentCancelLink)
public:
DocumentCancelLink(DocumentData *document) : DocumentLink(document) {
}
@@ -558,9 +671,9 @@ enum WebPageType {
WebPageArticle
};
inline WebPageType toWebPageType(const QString &type) {
if (type == QLatin1String("photo")) return WebPagePhoto;
if (type == QLatin1String("video")) return WebPageVideo;
if (type == QLatin1String("profile")) return WebPageProfile;
if (type == qstr("photo")) return WebPagePhoto;
if (type == qstr("video")) return WebPageVideo;
if (type == qstr("profile")) return WebPageProfile;
return WebPageArticle;
}

View File

@@ -199,6 +199,7 @@ private:
};
#define qsl(s) QStringLiteral(s)
#define qstr(s) QLatin1String(s, sizeof(s) - 1)
static const QRegularExpression::PatternOptions reMultiline(QRegularExpression::DotMatchesEverythingOption | QRegularExpression::MultilineOption);
@@ -247,7 +248,7 @@ enum DataBlockId {
dbiLastUpdateCheck = 0x0d,
dbiWindowPosition = 0x0e,
dbiConnectionType = 0x0f,
// 16 reserved
// 0x10 reserved
dbiDefaultAttach = 0x11,
dbiCatsAndDogs = 0x12,
dbiReplaceEmojis = 0x13,
@@ -258,7 +259,7 @@ enum DataBlockId {
dbiRecentEmojisOld = 0x18,
dbiLoggedPhoneNumber = 0x19,
dbiMutedPeers = 0x1a,
// 27 reserved
// 0x1b reserved
dbiNotifyView = 0x1c,
dbiSendToMenu = 0x1d,
dbiCompressPastedImage = 0x1e,
@@ -271,6 +272,8 @@ enum DataBlockId {
dbiEmojiVariants = 0x25,
dbiRecentStickers = 0x26,
dbiDcOption = 0x27,
dbiTryIPv6 = 0x28,
dbiSongVolume = 0x29,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,

View File

@@ -1426,7 +1426,7 @@ void Window::notifyShowNext(NotifyWindow *remove) {
if (j == notifyWhenMaps.end()) {
history->clearNotifications();
i = notifyWaiters.erase(i);
if (notifyHistory) notifyWaiter = notifyWaiters.find(notifyHistory);
notifyWaiter = notifyHistory ? notifyWaiters.find(notifyHistory) : notifyWaiters.end();
continue;
}
do {
@@ -1442,7 +1442,7 @@ void Window::notifyShowNext(NotifyWindow *remove) {
if (!history->currentNotification()) {
notifyWhenMaps.remove(history);
i = notifyWaiters.erase(i);
if (notifyHistory) notifyWaiter = notifyWaiters.find(notifyHistory);
notifyWaiter = notifyHistory ? notifyWaiters.find(notifyHistory) : notifyWaiters.end();
continue;
}
uint64 when = i.value().when;
@@ -1712,10 +1712,10 @@ void Window::sendPaths() {
}
}
void Window::mediaOverviewUpdated(PeerData *peer) {
if (main) main->mediaOverviewUpdated(peer);
void Window::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
if (main) main->mediaOverviewUpdated(peer, type);
if (!_mediaView || _mediaView->isHidden()) return;
_mediaView->mediaOverviewUpdated(peer);
_mediaView->mediaOverviewUpdated(peer, type);
}
void Window::documentUpdated(DocumentData *doc) {

View File

@@ -226,7 +226,7 @@ public:
void sendPaths();
void mediaOverviewUpdated(PeerData *peer);
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
void documentUpdated(DocumentData *doc);
void changingMsgId(HistoryItem *row, MsgId newId);

View File

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

View File

@@ -96,6 +96,7 @@ SOURCES += \
./SourceFiles/overviewwidget.cpp \
./SourceFiles/passcodewidget.cpp \
./SourceFiles/profilewidget.cpp \
./SourceFiles/playerwidget.cpp \
./SourceFiles/localimageloader.cpp \
./SourceFiles/localstorage.cpp \
./SourceFiles/logs.cpp \
@@ -182,6 +183,7 @@ HEADERS += \
./SourceFiles/overviewwidget.h \
./SourceFiles/passcodewidget.h \
./SourceFiles/profilewidget.h \
./SourceFiles/playerwidget.h \
./SourceFiles/localimageloader.h \
./SourceFiles/localstorage.h \
./SourceFiles/logs.h \

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -903,6 +903,18 @@
<ClCompile Include="GeneratedFiles\Release\moc_autoupdater.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\playerwidget.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_playerwidget.cpp">
<Filter>Generated Files\Deploy</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_playerwidget.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_playerwidget.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SourceFiles\stdafx.h">
@@ -1198,6 +1210,9 @@
<CustomBuild Include="SourceFiles\autoupdater.h">
<Filter>Source Files</Filter>
</CustomBuild>
<CustomBuild Include="SourceFiles\playerwidget.h">
<Filter>Source Files</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Image Include="SourceFiles\art\icon256.ico" />

View File

@@ -64,6 +64,8 @@
07AF95F51AFD03B90060B057 /* qrc_telegram_mac.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07AF95F31AFD03B90060B057 /* qrc_telegram_mac.cpp */; };
07AF95F91AFD03C80060B057 /* telegram_emojis.qrc in Resources */ = {isa = PBXBuildFile; fileRef = 07AF95F71AFD03C80060B057 /* telegram_emojis.qrc */; };
07AF95FA1AFD03C80060B057 /* telegram_mac.qrc in Resources */ = {isa = PBXBuildFile; fileRef = 07AF95F81AFD03C80060B057 /* telegram_mac.qrc */; };
07B604321B46A0EC00CA29FE /* playerwidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07B604301B46A0EC00CA29FE /* playerwidget.cpp */; };
07B604351B46A20900CA29FE /* moc_playerwidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07B604341B46A20900CA29FE /* moc_playerwidget.cpp */; };
07BE850F1A2093C9008ACB9F /* localstorage.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07BE850D1A2093C9008ACB9F /* localstorage.cpp */; };
07BE85121A20961F008ACB9F /* moc_localstorage.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07BE85111A20961F008ACB9F /* moc_localstorage.cpp */; };
07C4753B1967DF1C00CAAFE9 /* switcher.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07C475391967DF1C00CAAFE9 /* switcher.cpp */; };
@@ -305,6 +307,9 @@
07AF95F31AFD03B90060B057 /* qrc_telegram_mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = qrc_telegram_mac.cpp; path = GeneratedFiles/qrc_telegram_mac.cpp; sourceTree = SOURCE_ROOT; };
07AF95F71AFD03C80060B057 /* telegram_emojis.qrc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = telegram_emojis.qrc; path = SourceFiles/telegram_emojis.qrc; sourceTree = SOURCE_ROOT; };
07AF95F81AFD03C80060B057 /* telegram_mac.qrc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = telegram_mac.qrc; path = SourceFiles/telegram_mac.qrc; sourceTree = SOURCE_ROOT; };
07B604301B46A0EC00CA29FE /* playerwidget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = playerwidget.cpp; path = SourceFiles/playerwidget.cpp; sourceTree = SOURCE_ROOT; };
07B604311B46A0EC00CA29FE /* playerwidget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = playerwidget.h; path = SourceFiles/playerwidget.h; sourceTree = SOURCE_ROOT; };
07B604341B46A20900CA29FE /* moc_playerwidget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_playerwidget.cpp; path = GeneratedFiles/Debug/moc_playerwidget.cpp; sourceTree = SOURCE_ROOT; };
07BE850D1A2093C9008ACB9F /* localstorage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = localstorage.cpp; path = SourceFiles/localstorage.cpp; sourceTree = SOURCE_ROOT; };
07BE850E1A2093C9008ACB9F /* localstorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = localstorage.h; path = SourceFiles/localstorage.h; sourceTree = SOURCE_ROOT; };
07BE85111A20961F008ACB9F /* moc_localstorage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_localstorage.cpp; path = GeneratedFiles/Debug/moc_localstorage.cpp; sourceTree = SOURCE_ROOT; };
@@ -914,6 +919,7 @@
07A69330199277BA0099CB9F /* mediaview.cpp */,
0732E4A7199E262300D50FE7 /* overviewwidget.cpp */,
07DE929F1AA4923200A18F6F /* passcodewidget.cpp */,
07B604301B46A0EC00CA29FE /* playerwidget.cpp */,
CF32DF59C7823E4F3397EF3C /* profilewidget.cpp */,
5A7F88F9C7F08D3DDE6EEF6B /* localimageloader.cpp */,
07BE850D1A2093C9008ACB9F /* localstorage.cpp */,
@@ -952,6 +958,7 @@
07A69331199277BA0099CB9F /* mediaview.h */,
0732E4A8199E262300D50FE7 /* overviewwidget.h */,
07DE92A21AA4924400A18F6F /* passcodewidget.h */,
07B604311B46A0EC00CA29FE /* playerwidget.h */,
220B97F8F62C720E6059A64B /* profilewidget.h */,
AD0C395D671BC024083A5FC7 /* localimageloader.h */,
07BE850E1A2093C9008ACB9F /* localstorage.h */,
@@ -1106,6 +1113,7 @@
801973D3334D0FCA849CF485 /* Debug */ = {
isa = PBXGroup;
children = (
07B604341B46A20900CA29FE /* moc_playerwidget.cpp */,
07C759711B1F7E2800662169 /* moc_autoupdater.cpp */,
0710CA041B0B9404001B4272 /* moc_stickersetbox.cpp */,
0755AEDA1AD12A80004D738A /* moc_abstractbox.cpp */,
@@ -1610,6 +1618,7 @@
06EABCC49D2EEE4076322BE7 /* moc_mtp.cpp in Compile Sources */,
0755AEDE1AD12A80004D738A /* moc_intropwdcheck.cpp in Compile Sources */,
07DE92AA1AA4928200A18F6F /* moc_autolockbox.cpp in Compile Sources */,
07B604351B46A20900CA29FE /* moc_playerwidget.cpp in Compile Sources */,
8F6F5D7F82036331E8C6DAE6 /* moc_mtpConnection.cpp in Compile Sources */,
B780F9E21269259B90A1F32A /* moc_mtpDC.cpp in Compile Sources */,
07080BCF1A43588C00741A51 /* lang_auto.cpp in Compile Sources */,
@@ -1638,6 +1647,7 @@
60CB4898955209B665E7B07D /* moc_twidget.cpp in Compile Sources */,
7062978F12EEA525893A5E6F /* moc_aboutbox.cpp in Compile Sources */,
E8B28580819B882A5964561A /* moc_addcontactbox.cpp in Compile Sources */,
07B604321B46A0EC00CA29FE /* playerwidget.cpp in Compile Sources */,
D6874C00733283846ACA9AB2 /* moc_confirmbox.cpp in Compile Sources */,
ED2557A57C6782721DC494AF /* moc_connectionbox.cpp in Compile Sources */,
5FC914F652D1B16FDA8F0634 /* moc_contactsbox.cpp in Compile Sources */,
@@ -1701,7 +1711,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.8.29;
CURRENT_PROJECT_VERSION = 0.8.39;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
@@ -1719,7 +1729,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 0.8.29;
CURRENT_PROJECT_VERSION = 0.8.39;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@@ -1745,10 +1755,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.8.29;
CURRENT_PROJECT_VERSION = 0.8.39;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 0.8;
DYLIB_CURRENT_VERSION = 0.8.29;
DYLIB_CURRENT_VERSION = 0.8.39;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@@ -1888,10 +1898,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.8.29;
CURRENT_PROJECT_VERSION = 0.8.39;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.8;
DYLIB_CURRENT_VERSION = 0.8.29;
DYLIB_CURRENT_VERSION = 0.8.39;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;

View File

@@ -33,7 +33,7 @@ check: first
compilers: GeneratedFiles/qrc_telegram.cpp GeneratedFiles/qrc_telegram_emojis.cpp GeneratedFiles/qrc_telegram_mac.cpp GeneratedFiles/Debug/moc_apiwrap.cpp GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_autoupdater.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp\
GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp\
GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp\
GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_playerwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp\
GeneratedFiles/Debug/moc_passcodewidget.cpp\
GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_localstorage.cpp GeneratedFiles/Debug/moc_mainwidget.cpp\
GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp\
@@ -99,9 +99,9 @@ GeneratedFiles/qrc_telegram_mac.cpp: SourceFiles/telegram_mac.qrc \
SourceFiles/art/osxtray.png
/usr/local/Qt-5.4.0/bin/rcc -name telegram_mac SourceFiles/telegram_mac.qrc -o GeneratedFiles/qrc_telegram_mac.cpp
compiler_moc_header_make_all: GeneratedFiles/Debug/moc_apiwrap.cpp GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_autoupdater.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp GeneratedFiles/Debug/moc_passcodewidget.cpp GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_localstorage.cpp GeneratedFiles/Debug/moc_mainwidget.cpp GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp GeneratedFiles/Debug/moc_types.cpp GeneratedFiles/Debug/moc_window.cpp GeneratedFiles/Debug/moc_mtp.cpp GeneratedFiles/Debug/moc_mtpConnection.cpp GeneratedFiles/Debug/moc_mtpDC.cpp GeneratedFiles/Debug/moc_mtpFileLoader.cpp GeneratedFiles/Debug/moc_mtpSession.cpp GeneratedFiles/Debug/moc_animation.cpp GeneratedFiles/Debug/moc_button.cpp GeneratedFiles/Debug/moc_contextmenu.cpp GeneratedFiles/Debug/moc_countrycodeinput.cpp GeneratedFiles/Debug/moc_countryinput.cpp GeneratedFiles/Debug/moc_flatbutton.cpp GeneratedFiles/Debug/moc_flatcheckbox.cpp GeneratedFiles/Debug/moc_flatinput.cpp GeneratedFiles/Debug/moc_flatlabel.cpp GeneratedFiles/Debug/moc_flattextarea.cpp GeneratedFiles/Debug/moc_switcher.cpp GeneratedFiles/Debug/moc_phoneinput.cpp GeneratedFiles/Debug/moc_scrollarea.cpp GeneratedFiles/Debug/moc_twidget.cpp GeneratedFiles/Debug/moc_aboutbox.cpp GeneratedFiles/Debug/moc_abstractbox.cpp GeneratedFiles/Debug/moc_addcontactbox.cpp GeneratedFiles/Debug/moc_autolockbox.cpp GeneratedFiles/Debug/moc_backgroundbox.cpp GeneratedFiles/Debug/moc_confirmbox.cpp GeneratedFiles/Debug/moc_connectionbox.cpp GeneratedFiles/Debug/moc_contactsbox.cpp GeneratedFiles/Debug/moc_downloadpathbox.cpp GeneratedFiles/Debug/moc_emojibox.cpp GeneratedFiles/Debug/moc_languagebox.cpp GeneratedFiles/Debug/moc_passcodebox.cpp GeneratedFiles/Debug/moc_photocropbox.cpp GeneratedFiles/Debug/moc_photosendbox.cpp GeneratedFiles/Debug/moc_sessionsbox.cpp GeneratedFiles/Debug/moc_stickersetbox.cpp GeneratedFiles/Debug/moc_usernamebox.cpp GeneratedFiles/Debug/moc_intro.cpp GeneratedFiles/Debug/moc_introcode.cpp GeneratedFiles/Debug/moc_introphone.cpp GeneratedFiles/Debug/moc_intropwdcheck.cpp GeneratedFiles/Debug/moc_introsignup.cpp GeneratedFiles/Debug/moc_pspecific_mac.cpp
compiler_moc_header_make_all: GeneratedFiles/Debug/moc_apiwrap.cpp GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_autoupdater.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_playerwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp GeneratedFiles/Debug/moc_passcodewidget.cpp GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_localstorage.cpp GeneratedFiles/Debug/moc_mainwidget.cpp GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp GeneratedFiles/Debug/moc_types.cpp GeneratedFiles/Debug/moc_window.cpp GeneratedFiles/Debug/moc_mtp.cpp GeneratedFiles/Debug/moc_mtpConnection.cpp GeneratedFiles/Debug/moc_mtpDC.cpp GeneratedFiles/Debug/moc_mtpFileLoader.cpp GeneratedFiles/Debug/moc_mtpSession.cpp GeneratedFiles/Debug/moc_animation.cpp GeneratedFiles/Debug/moc_button.cpp GeneratedFiles/Debug/moc_contextmenu.cpp GeneratedFiles/Debug/moc_countrycodeinput.cpp GeneratedFiles/Debug/moc_countryinput.cpp GeneratedFiles/Debug/moc_flatbutton.cpp GeneratedFiles/Debug/moc_flatcheckbox.cpp GeneratedFiles/Debug/moc_flatinput.cpp GeneratedFiles/Debug/moc_flatlabel.cpp GeneratedFiles/Debug/moc_flattextarea.cpp GeneratedFiles/Debug/moc_switcher.cpp GeneratedFiles/Debug/moc_phoneinput.cpp GeneratedFiles/Debug/moc_scrollarea.cpp GeneratedFiles/Debug/moc_twidget.cpp GeneratedFiles/Debug/moc_aboutbox.cpp GeneratedFiles/Debug/moc_abstractbox.cpp GeneratedFiles/Debug/moc_addcontactbox.cpp GeneratedFiles/Debug/moc_autolockbox.cpp GeneratedFiles/Debug/moc_backgroundbox.cpp GeneratedFiles/Debug/moc_confirmbox.cpp GeneratedFiles/Debug/moc_connectionbox.cpp GeneratedFiles/Debug/moc_contactsbox.cpp GeneratedFiles/Debug/moc_downloadpathbox.cpp GeneratedFiles/Debug/moc_emojibox.cpp GeneratedFiles/Debug/moc_languagebox.cpp GeneratedFiles/Debug/moc_passcodebox.cpp GeneratedFiles/Debug/moc_photocropbox.cpp GeneratedFiles/Debug/moc_photosendbox.cpp GeneratedFiles/Debug/moc_sessionsbox.cpp GeneratedFiles/Debug/moc_stickersetbox.cpp GeneratedFiles/Debug/moc_usernamebox.cpp GeneratedFiles/Debug/moc_intro.cpp GeneratedFiles/Debug/moc_introcode.cpp GeneratedFiles/Debug/moc_introphone.cpp GeneratedFiles/Debug/moc_intropwdcheck.cpp GeneratedFiles/Debug/moc_introsignup.cpp GeneratedFiles/Debug/moc_pspecific_mac.cpp
compiler_moc_header_clean:
-$(DEL_FILE) GeneratedFiles/Debug/moc_apiwrap.cpp GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_autoupdater.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp GeneratedFiles/Debug/moc_passcodewidget.cpp GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_localstorage.cpp GeneratedFiles/Debug/moc_mainwidget.cpp GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp GeneratedFiles/Debug/moc_types.cpp GeneratedFiles/Debug/moc_window.cpp GeneratedFiles/Debug/moc_mtp.cpp GeneratedFiles/Debug/moc_mtpConnection.cpp GeneratedFiles/Debug/moc_mtpDC.cpp GeneratedFiles/Debug/moc_mtpFileLoader.cpp GeneratedFiles/Debug/moc_mtpSession.cpp GeneratedFiles/Debug/moc_animation.cpp GeneratedFiles/Debug/moc_button.cpp GeneratedFiles/Debug/moc_contextmenu.cpp GeneratedFiles/Debug/moc_countrycodeinput.cpp GeneratedFiles/Debug/moc_countryinput.cpp GeneratedFiles/Debug/moc_flatbutton.cpp GeneratedFiles/Debug/moc_flatcheckbox.cpp GeneratedFiles/Debug/moc_flatinput.cpp GeneratedFiles/Debug/moc_flatlabel.cpp GeneratedFiles/Debug/moc_flattextarea.cpp GeneratedFiles/Debug/moc_switcher.cpp GeneratedFiles/Debug/moc_phoneinput.cpp GeneratedFiles/Debug/moc_scrollarea.cpp GeneratedFiles/Debug/moc_twidget.cpp GeneratedFiles/Debug/moc_aboutbox.cpp GeneratedFiles/Debug/moc_abstractbox.cpp GeneratedFiles/Debug/moc_addcontactbox.cpp GeneratedFiles/Debug/moc_autolockbox.cpp GeneratedFiles/Debug/moc_backgroundbox.cpp GeneratedFiles/Debug/moc_confirmbox.cpp GeneratedFiles/Debug/moc_connectionbox.cpp GeneratedFiles/Debug/moc_contactsbox.cpp GeneratedFiles/Debug/moc_downloadpathbox.cpp GeneratedFiles/Debug/moc_emojibox.cpp GeneratedFiles/Debug/moc_languagebox.cpp GeneratedFiles/Debug/moc_passcodebox.cpp GeneratedFiles/Debug/moc_photocropbox.cpp GeneratedFiles/Debug/moc_photosendbox.cpp GeneratedFiles/Debug/moc_sessionsbox.cpp GeneratedFiles/Debug/moc_stickersetbox.cpp GeneratedFiles/Debug/moc_usernamedbox.cpp GeneratedFiles/Debug/moc_intro.cpp GeneratedFiles/Debug/moc_introcode.cpp GeneratedFiles/Debug/moc_introphone.cpp GeneratedFiles/Debug/moc_intropwdcheck.cpp GeneratedFiles/Debug/moc_introsignup.cpp GeneratedFiles/Debug/moc_pspecific_mac.cpp
-$(DEL_FILE) GeneratedFiles/Debug/moc_apiwrap.cpp GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_autoupdater.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_playerwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp GeneratedFiles/Debug/moc_passcodewidget.cpp GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_localstorage.cpp GeneratedFiles/Debug/moc_mainwidget.cpp GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp GeneratedFiles/Debug/moc_types.cpp GeneratedFiles/Debug/moc_window.cpp GeneratedFiles/Debug/moc_mtp.cpp GeneratedFiles/Debug/moc_mtpConnection.cpp GeneratedFiles/Debug/moc_mtpDC.cpp GeneratedFiles/Debug/moc_mtpFileLoader.cpp GeneratedFiles/Debug/moc_mtpSession.cpp GeneratedFiles/Debug/moc_animation.cpp GeneratedFiles/Debug/moc_button.cpp GeneratedFiles/Debug/moc_contextmenu.cpp GeneratedFiles/Debug/moc_countrycodeinput.cpp GeneratedFiles/Debug/moc_countryinput.cpp GeneratedFiles/Debug/moc_flatbutton.cpp GeneratedFiles/Debug/moc_flatcheckbox.cpp GeneratedFiles/Debug/moc_flatinput.cpp GeneratedFiles/Debug/moc_flatlabel.cpp GeneratedFiles/Debug/moc_flattextarea.cpp GeneratedFiles/Debug/moc_switcher.cpp GeneratedFiles/Debug/moc_phoneinput.cpp GeneratedFiles/Debug/moc_scrollarea.cpp GeneratedFiles/Debug/moc_twidget.cpp GeneratedFiles/Debug/moc_aboutbox.cpp GeneratedFiles/Debug/moc_abstractbox.cpp GeneratedFiles/Debug/moc_addcontactbox.cpp GeneratedFiles/Debug/moc_autolockbox.cpp GeneratedFiles/Debug/moc_backgroundbox.cpp GeneratedFiles/Debug/moc_confirmbox.cpp GeneratedFiles/Debug/moc_connectionbox.cpp GeneratedFiles/Debug/moc_contactsbox.cpp GeneratedFiles/Debug/moc_downloadpathbox.cpp GeneratedFiles/Debug/moc_emojibox.cpp GeneratedFiles/Debug/moc_languagebox.cpp GeneratedFiles/Debug/moc_passcodebox.cpp GeneratedFiles/Debug/moc_photocropbox.cpp GeneratedFiles/Debug/moc_photosendbox.cpp GeneratedFiles/Debug/moc_sessionsbox.cpp GeneratedFiles/Debug/moc_stickersetbox.cpp GeneratedFiles/Debug/moc_usernamedbox.cpp GeneratedFiles/Debug/moc_intro.cpp GeneratedFiles/Debug/moc_introcode.cpp GeneratedFiles/Debug/moc_introphone.cpp GeneratedFiles/Debug/moc_intropwdcheck.cpp GeneratedFiles/Debug/moc_introsignup.cpp GeneratedFiles/Debug/moc_pspecific_mac.cpp
GeneratedFiles/Debug/moc_apiwrap.cpp: SourceFiles/types.h \
SourceFiles/logs.h \
SourceFiles/apiwrap.h
@@ -179,6 +179,9 @@ GeneratedFiles/Debug/moc_mediaview.cpp: SourceFiles/mediaview.h
GeneratedFiles/Debug/moc_overviewwidget.cpp: SourceFiles/overviewwidget.h
/usr/local/Qt-5.4.0/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.4.0/mkspecs/macx-clang -I. -I/usr/local/Qt-5.4.0/include/QtGui/5.4.0/QtGui -I/usr/local/Qt-5.4.0/include/QtCore/5.4.0/QtCore -I/usr/local/Qt-5.4.0/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.4.0/include -I/usr/local/Qt-5.4.0/include/QtMultimedia -I/usr/local/Qt-5.4.0/include/QtWidgets -I/usr/local/Qt-5.4.0/include/QtNetwork -I/usr/local/Qt-5.4.0/include/QtGui -I/usr/local/Qt-5.4.0/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/overviewwidget.h -o GeneratedFiles/Debug/moc_overviewwidget.cpp
GeneratedFiles/Debug/moc_playerwidget.cpp: SourceFiles/playerwidget.h
/usr/local/Qt-5.4.0/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.4.0/mkspecs/macx-clang -I. -I/usr/local/Qt-5.4.0/include/QtGui/5.4.0/QtGui -I/usr/local/Qt-5.4.0/include/QtCore/5.4.0/QtCore -I/usr/local/Qt-5.4.0/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.4.0/include -I/usr/local/Qt-5.4.0/include/QtMultimedia -I/usr/local/Qt-5.4.0/include/QtWidgets -I/usr/local/Qt-5.4.0/include/QtNetwork -I/usr/local/Qt-5.4.0/include/QtGui -I/usr/local/Qt-5.4.0/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/playerwidget.h -o GeneratedFiles/Debug/moc_playerwidget.cpp
GeneratedFiles/Debug/moc_profilewidget.cpp: SourceFiles/profilewidget.h
/usr/local/Qt-5.4.0/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.4.0/mkspecs/macx-clang -I. -I/usr/local/Qt-5.4.0/include/QtGui/5.4.0/QtGui -I/usr/local/Qt-5.4.0/include/QtCore/5.4.0/QtCore -I/usr/local/Qt-5.4.0/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.4.0/include -I/usr/local/Qt-5.4.0/include/QtMultimedia -I/usr/local/Qt-5.4.0/include/QtWidgets -I/usr/local/Qt-5.4.0/include/QtNetwork -I/usr/local/Qt-5.4.0/include/QtGui -I/usr/local/Qt-5.4.0/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/profilewidget.h -o GeneratedFiles/Debug/moc_profilewidget.cpp

View File

@@ -1,2 +1,2 @@
echo 8029 0.8.29 1
# AppVersion AppVersionStr DevChannel
echo 0.8 8039 0.8.39 1
# AppVersionStrMajor AppVersion AppVersionStr DevChannel

File diff suppressed because it is too large Load Diff

View File

@@ -1,35 +1,36 @@
diff --git a/qtbase/mkspecs/win32-msvc2013/qmake.conf b/qtbase/mkspecs/win32-msvc2013/qmake.conf
index 535904a..6d0e9b9 100644
--- a/qtbase/mkspecs/win32-msvc2013/qmake.conf
+++ b/qtbase/mkspecs/win32-msvc2013/qmake.conf
@@ -25,9 +25,9 @@ QMAKE_YACCFLAGS = -d
QMAKE_CFLAGS = -nologo -Zm200 -Zc:wchar_t -FS
diff --git a/qtbase/mkspecs/common/msvc-desktop.conf b/qtbase/mkspecs/common/msvc-desktop.conf
index e638af6..e44ee5e 100644
--- a/qtbase/mkspecs/common/msvc-desktop.conf
+++ b/qtbase/mkspecs/common/msvc-desktop.conf
@@ -28,9 +28,9 @@ QMAKE_YACCFLAGS = -d
QMAKE_CFLAGS = -nologo -Zc:wchar_t
QMAKE_CFLAGS_WARN_ON = -W3
QMAKE_CFLAGS_WARN_OFF = -W0
-QMAKE_CFLAGS_RELEASE = -O2 -MD -Zc:strictStrings
-QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MD -Zi -Zc:strictStrings
-QMAKE_CFLAGS_RELEASE = -O2 -MD
-QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MD -Zi
-QMAKE_CFLAGS_DEBUG = -Zi -MDd
+QMAKE_CFLAGS_RELEASE = -O2 -MT -Zc:strictStrings
+QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MT -Zi -Zc:strictStrings
+QMAKE_CFLAGS_RELEASE = -O2 -MT
+QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MT -Zi
+QMAKE_CFLAGS_DEBUG = -Zi -MTd
QMAKE_CFLAGS_YACC =
QMAKE_CFLAGS_LTCG = -GL
QMAKE_CFLAGS_MP = -MP
QMAKE_CFLAGS_SSE2 = -arch:SSE2
diff --git a/qtbase/qmake/generators/mac/pbuilder_pbx.cpp b/qtbase/qmake/generators/mac/pbuilder_pbx.cpp
index 0ff4250..9ed555c 100644
index 81bb068..a0fe016 100644
--- a/qtbase/qmake/generators/mac/pbuilder_pbx.cpp
+++ b/qtbase/qmake/generators/mac/pbuilder_pbx.cpp
@@ -1445,11 +1445,15 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
plist_in_text = plist_in_text.replace("@TYPEINFO@",
@@ -1500,11 +1500,15 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
plist_in_text.replace("@TYPEINFO@",
(project->isEmpty("QMAKE_PKGINFO_TYPEINFO")
? QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4).toQString()));
- QFile plist_out_file("Info.plist");
- QFile plist_out_file(Option::output_dir + "/Info.plist");
- if (plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QString plist_dir;
+ if (!project->isEmpty("PLIST_DIR"))
+ plist_dir = project->first("PLIST_DIR").toQString();
+ QString plist_in_filename = QFileInfo(plist_in_file).fileName();
+ QFile plist_out_file(plist_dir + plist_in_filename);
if (plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QFile plist_out_file(Option::output_dir + "/" + plist_dir + plist_in_filename);
+ if (plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream plist_out(&plist_out_file);
plist_out << plist_in_text;
- t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", "Info.plist") << ";\n";
@@ -38,10 +39,10 @@ index 0ff4250..9ed555c 100644
}
}
diff --git a/qtbase/qmake/generators/makefile.cpp b/qtbase/qmake/generators/makefile.cpp
index bf9a9d8..0216f5c 100644
index 4a03faf..2c18c48 100644
--- a/qtbase/qmake/generators/makefile.cpp
+++ b/qtbase/qmake/generators/makefile.cpp
@@ -206,7 +206,7 @@ MakefileGenerator::initOutPaths()
@@ -167,7 +167,7 @@ MakefileGenerator::initOutPaths()
v["PRECOMPILED_DIR"] = v["OBJECTS_DIR"];
static const char * const dirs[] = { "OBJECTS_DIR", "DESTDIR",
"SUBLIBS_DIR", "DLLDESTDIR",
@@ -51,7 +52,7 @@ index bf9a9d8..0216f5c 100644
const ProKey dkey(dirs[x]);
if (v[dkey].isEmpty())
diff --git a/qtbase/src/3rdparty/pcre/pcre16_valid_utf16.c b/qtbase/src/3rdparty/pcre/pcre16_valid_utf16.c
index 1987f27..6b36e4f 100644
index 0907653..96f6e19 100644
--- a/qtbase/src/3rdparty/pcre/pcre16_valid_utf16.c
+++ b/qtbase/src/3rdparty/pcre/pcre16_valid_utf16.c
@@ -101,7 +101,7 @@ for (p = string; length-- > 0; p++)
@@ -63,11 +64,24 @@ index 1987f27..6b36e4f 100644
{
/* High surrogate. Must be a followed by a low surrogate. */
if (length == 0)
diff --git a/qtbase/src/corelib/kernel/qobjectdefs.h b/qtbase/src/corelib/kernel/qobjectdefs.h
index 4d01264..fd3854f 100644
--- a/qtbase/src/corelib/kernel/qobjectdefs.h
+++ b/qtbase/src/corelib/kernel/qobjectdefs.h
@@ -142,7 +142,7 @@ inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
# define Q_DECL_HIDDEN_STATIC_METACALL Q_DECL_HIDDEN
#endif
-#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 306
+#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 306 && false
# define Q_OBJECT_NO_OVERRIDE_WARNING QT_WARNING_DISABLE_CLANG("-Winconsistent-missing-override")
#else
# define Q_OBJECT_NO_OVERRIDE_WARNING
diff --git a/qtbase/src/corelib/tools/qunicodetables.cpp b/qtbase/src/corelib/tools/qunicodetables.cpp
index 072e8ad..2bf3bfd 100644
index 73dce81..76c6933 100644
--- a/qtbase/src/corelib/tools/qunicodetables.cpp
+++ b/qtbase/src/corelib/tools/qunicodetables.cpp
@@ -5360,7 +5360,7 @@ static const Properties uc_properties[] = {
@@ -5839,7 +5839,7 @@ static const Properties uc_properties[] = {
{ 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 7, 4, 4, 21, 11 },
{ 0, 17, 230, 5, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 4, 4, 21, 11 },
{ 18, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 85, 0, 8, 8, 12, 11 },
@@ -77,7 +91,7 @@ index 072e8ad..2bf3bfd 100644
{ 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 },
{ 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 },
diff --git a/qtbase/src/gui/image/qbmphandler.cpp b/qtbase/src/gui/image/qbmphandler.cpp
index 21c1a2f..f293ef9 100644
index f124ced..eb78a13 100644
--- a/qtbase/src/gui/image/qbmphandler.cpp
+++ b/qtbase/src/gui/image/qbmphandler.cpp
@@ -212,6 +212,9 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
@@ -101,7 +115,7 @@ index 21c1a2f..f293ef9 100644
uchar rgb[4];
int rgb_len = t == BMP_OLD ? 3 : 4;
diff --git a/qtbase/src/gui/kernel/qplatformdialoghelper.h b/qtbase/src/gui/kernel/qplatformdialoghelper.h
index e0730cd..00fccad 100644
index 8b2b988..2d1cdd9 100644
--- a/qtbase/src/gui/kernel/qplatformdialoghelper.h
+++ b/qtbase/src/gui/kernel/qplatformdialoghelper.h
@@ -363,6 +363,7 @@ public:
@@ -113,7 +127,7 @@ index e0730cd..00fccad 100644
virtual void selectNameFilter(const QString &filter) = 0;
virtual QString selectedNameFilter() const = 0;
diff --git a/qtbase/src/gui/painting/qpaintengine_p.h b/qtbase/src/gui/painting/qpaintengine_p.h
index 312320c..5e82318 100644
index c58662e..468d671 100644
--- a/qtbase/src/gui/painting/qpaintengine_p.h
+++ b/qtbase/src/gui/painting/qpaintengine_p.h
@@ -79,8 +79,18 @@ public:
@@ -123,8 +137,8 @@ index 312320c..5e82318 100644
- else
- systemClip = systemTransform.map(systemClip);
+ else {
+ // Transform the system clip region back from device pixels to device-independent pixels before
+ // applying systemTransform, which already has transform from device-independent pixels to device pixels
+// Transform the system clip region back from device pixels to device-independent pixels before
+// applying systemTransform, which already has transform from device-independent pixels to device pixels
+#ifdef Q_OS_MAC
+ QTransform scaleTransform;
+ const qreal invDevicePixelRatio = 1. / pdev->devicePixelRatio();
@@ -138,32 +152,30 @@ index 312320c..5e82318 100644
// Make sure we're inside the viewport.
diff --git a/qtbase/src/gui/text/qtextlayout.cpp b/qtbase/src/gui/text/qtextlayout.cpp
index 1ac50d3..3c88caa 100644
index 7da3e84..0829250 100644
--- a/qtbase/src/gui/text/qtextlayout.cpp
+++ b/qtbase/src/gui/text/qtextlayout.cpp
@@ -643,7 +643,10 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
@@ -643,6 +643,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
while (oldPos < len && !attributes[oldPos].graphemeBoundary)
oldPos++;
} else {
- if (oldPos < len && d->atWordSeparator(oldPos)) {
+ while (oldPos < len && d->atSpace(oldPos))
+ while (oldPos < len && attributes[oldPos].whiteSpace)
+ oldPos++;
+
+ if (oldPos < len && d->atWordSeparator(oldPos)) {
if (oldPos < len && d->atWordSeparator(oldPos)) {
oldPos++;
while (oldPos < len && d->atWordSeparator(oldPos))
oldPos++;
@@ -651,8 +654,6 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
while (oldPos < len && !d->atSpace(oldPos) && !d->atWordSeparator(oldPos))
while (oldPos < len && !attributes[oldPos].whiteSpace && !d->atWordSeparator(oldPos))
oldPos++;
}
- while (oldPos < len && d->atSpace(oldPos))
- while (oldPos < len && attributes[oldPos].whiteSpace)
- oldPos++;
}
return oldPos;
diff --git a/qtbase/src/gui/text/qtextlayout.h b/qtbase/src/gui/text/qtextlayout.h
index 1e0ab9b..47972d3 100644
index 47dcd38..64c3810 100644
--- a/qtbase/src/gui/text/qtextlayout.h
+++ b/qtbase/src/gui/text/qtextlayout.h
@@ -186,6 +186,8 @@ private:
@@ -176,27 +188,29 @@ index 1e0ab9b..47972d3 100644
diff --git a/qtbase/src/network/socket/qnativesocketengine_win.cpp b/qtbase/src/network/socket/qnativesocketengine_win.cpp
index f5943d6..f7787c3 100644
index 72f85c8..a1c2e08 100644
--- a/qtbase/src/network/socket/qnativesocketengine_win.cpp
+++ b/qtbase/src/network/socket/qnativesocketengine_win.cpp
@@ -703,6 +703,12 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
@@ -685,7 +685,13 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
errorDetected = true;
break;
}
- if (value == WSAEADDRNOTAVAIL) {
+ if (value == WSAENETUNREACH) {
+ setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ errorDetected = true;
+ break;
+ }
if (value == WSAEADDRNOTAVAIL) {
+ if (value == WSAEADDRNOTAVAIL) {
setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
socketState = QAbstractSocket::UnconnectedState;
errorDetected = true;
diff --git a/qtbase/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/qtbase/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
index 43903ac..efa7014 100644
index 65cdabd..190683e 100644
--- a/qtbase/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
+++ b/qtbase/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
@@ -213,6 +213,78 @@ void QBasicFontDatabase::releaseHandle(void *handle)
@@ -198,6 +198,78 @@ void QBasicFontDatabase::releaseHandle(void *handle)
extern FT_Library qt_getFreetype();
@@ -275,12 +289,12 @@ index 43903ac..efa7014 100644
QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file, QSupportedWritingSystems *supportedWritingSystems)
{
FT_Library library = qt_getFreetype();
@@ -224,9 +296,9 @@ QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByt
@@ -209,9 +281,9 @@ QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByt
FT_Face face;
FT_Error error;
if (!fontData.isEmpty()) {
- error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face);
+ error = __ft_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face);
+ error = __ft_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face);
} else {
- error = FT_New_Face(library, file.constData(), index, &face);
+ error = __ft_New_Face(library, file.constData(), index, &face);
@@ -288,10 +302,10 @@ index 43903ac..efa7014 100644
if (error != FT_Err_Ok) {
qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error;
diff --git a/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
index 5dec1d0..f4d6fcd 100644
index 112bb8e..9f1df70 100644
--- a/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
+++ b/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
@@ -341,6 +341,15 @@ static void populateFromPattern(FcPattern *pattern)
@@ -373,6 +373,15 @@ static void populateFromPattern(FcPattern *pattern)
return;
familyName = QString::fromUtf8((const char *)value);
@@ -307,7 +321,7 @@ index 5dec1d0..f4d6fcd 100644
slant_value = FC_SLANT_ROMAN;
weight_value = FC_WEIGHT_REGULAR;
@@ -742,6 +751,15 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData,
@@ -781,6 +790,15 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData,
FcChar8 *fam = 0;
if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) {
QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
@@ -324,10 +338,10 @@ index 5dec1d0..f4d6fcd 100644
}
populateFromPattern(pattern);
diff --git a/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
index 9f2ff10..fe87ca1 100644
index be70092..1594dac 100644
--- a/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
+++ b/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
@@ -257,6 +257,10 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
@@ -263,6 +263,10 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
fd->foundryName = QStringLiteral("CoreText");
fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
@@ -339,10 +353,10 @@ index 9f2ff10..fe87ca1 100644
fd->weight = QFont::Normal;
fd->style = QFont::StyleNormal;
diff --git a/qtbase/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/qtbase/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 9f7609f..5df1514 100644
index f3a0216..643ebdd 100644
--- a/qtbase/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/qtbase/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -216,7 +216,7 @@ static void cleanupCocoaApplicationDelegate()
@@ -210,7 +210,7 @@ QT_END_NAMESPACE
if (reflectionDelegate) {
if ([reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)])
return [reflectionDelegate applicationShouldTerminate:sender];
@@ -352,25 +366,18 @@ index 9f7609f..5df1514 100644
if ([self canQuit]) {
diff --git a/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index e449fd3..7f7bd24 100644
index 713758c..9c695aa 100644
--- a/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -102,7 +102,7 @@ QT_USE_NAMESPACE
@@ -94,6 +94,7 @@ QT_USE_NAMESPACE
QCocoaSystemTrayIcon *systray;
NSStatusItem *item;
QCocoaMenu *menu;
- bool menuVisible;
+ bool menuVisible, iconSelected;
+ bool menuVisible, iconSelected;
QIcon icon;
QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
}
@@ -202,13 +202,11 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
m_sys->item->icon = icon;
- const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible;
-
// The reccomended maximum title bar icon height is 18 points
@@ -197,7 +198,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
// (device independent pixels). The menu height on past and
// current OS X versions is 22 points. Provide some future-proofing
// by deriving the icon height from the menu height.
@@ -379,32 +386,51 @@ index e449fd3..7f7bd24 100644
const int menuHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
const int maxImageHeight = menuHeight - padding;
@@ -218,7 +216,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
@@ -207,8 +208,9 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
// devicePixelRatio for the "best" screen on the system.
qreal devicePixelRatio = qApp->devicePixelRatio();
const int maxPixmapHeight = maxImageHeight * devicePixelRatio;
- const QIcon::Mode mode = menuVisible ? QIcon::Selected : QIcon::Normal;
+ const QIcon::Mode mode = m_sys->item->iconSelected ? QIcon::Selected : QIcon::Normal;
+ const QIcon::Mode mode = m_sys->item->iconSelected ? QIcon::Selected : QIcon::Normal;
QSize selectedSize;
Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes(mode))) {
- Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes())) {
+ Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes(mode))) {
// Select a pixmap based on the height. We want the largest pixmap
@@ -381,6 +379,7 @@ QT_END_NAMESPACE
// with a height smaller or equal to maxPixmapHeight. The pixmap
// may rectangular; assume it has a reasonable size. If there is
@@ -224,9 +226,9 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
// Handle SVG icons, which do not return anything for availableSizes().
if (!selectedSize.isValid())
- selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight));
+ selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight), mode);
- QPixmap pixmap = icon.pixmap(selectedSize);
+ QPixmap pixmap = icon.pixmap(selectedSize, mode);
// Draw a low-resolution icon if there is not enough pixels for a retina
// icon. This prevents showing a small icon on retina displays.
@@ -373,6 +375,10 @@ QT_END_NAMESPACE
Q_UNUSED(notification);
down = NO;
+ parent->iconSelected = false;
parent->systray->updateIcon(parent->icon);
parent->menuVisible = false;
+ parent->systray->updateIcon(parent->icon);
+ parent->menuVisible = false;
+
[self setNeedsDisplay:YES];
}
@@ -393,6 +392,7 @@ QT_END_NAMESPACE
@@ -381,6 +387,9 @@ QT_END_NAMESPACE
down = YES;
int clickCount = [mouseEvent clickCount];
[self setNeedsDisplay:YES];
+ parent->iconSelected = (clickCount != 2) && parent->menu;
parent->systray->updateIcon(parent->icon);
+
+ parent->iconSelected = (clickCount != 2) && parent->menu;
+ parent->systray->updateIcon(parent->icon);
if (clickCount == 2) {
@@ -411,6 +411,10 @@ QT_END_NAMESPACE
[self menuTrackingDone:nil];
@@ -398,6 +407,10 @@ QT_END_NAMESPACE
-(void)mouseUp:(NSEvent *)mouseEvent
{
Q_UNUSED(mouseEvent);
@@ -415,7 +441,7 @@ index e449fd3..7f7bd24 100644
[self menuTrackingDone:nil];
}
@@ -422,6 +426,10 @@ QT_END_NAMESPACE
@@ -409,6 +422,10 @@ QT_END_NAMESPACE
-(void)rightMouseUp:(NSEvent *)mouseEvent
{
Q_UNUSED(mouseEvent);
@@ -426,20 +452,36 @@ index e449fd3..7f7bd24 100644
[self menuTrackingDone:nil];
}
@@ -437,7 +445,7 @@ QT_END_NAMESPACE
@@ -424,7 +441,7 @@ QT_END_NAMESPACE
}
-(void)drawRect:(NSRect)rect {
- [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down];
+ [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:parent->menu ? down : NO];
+ [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:parent->menu ? down : NO];
[super drawRect:rect];
}
@end
@@ -437,6 +454,7 @@ QT_END_NAMESPACE
if (self) {
item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
menu = 0;
+ menuVisible = false;
systray = sys;
imageCell = [[QNSImageView alloc] initWithParent:self];
[item setView: imageCell];
@@ -481,6 +499,7 @@ QT_END_NAMESPACE
selector:@selector(menuTrackingDone:)
name:NSMenuDidEndTrackingNotification
object:m];
+ menuVisible = true;
[item popUpStatusItemMenu: m];
}
}
diff --git a/qtbase/src/plugins/platforms/cocoa/qcocoawindow.mm b/qtbase/src/plugins/platforms/cocoa/qcocoawindow.mm
index 6656212..486fda0 100644
index 92fc66a..d18884a 100644
--- a/qtbase/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/qtbase/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -175,7 +175,7 @@ static void selectNextKeyWindow(NSWindow *currentKeyWindow)
@@ -142,7 +142,7 @@ static bool isMouseEvent(NSEvent *ev)
if (!self.window.delegate)
return; // Already detached, pending NSAppKitDefined event
@@ -448,7 +490,7 @@ index 6656212..486fda0 100644
NSPoint loc = [theEvent locationInWindow];
NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]];
NSRect contentFrame = [[self.window contentView] frame];
@@ -918,6 +918,14 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath)
@@ -924,6 +924,14 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath)
[m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""];
}
@@ -463,7 +505,7 @@ index 6656212..486fda0 100644
void QCocoaWindow::setWindowIcon(const QIcon &icon)
{
QCocoaAutoReleasePool pool;
@@ -933,7 +941,8 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
@@ -939,7 +947,8 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
if (icon.isNull()) {
[iconButton setImage:nil];
} else {
@@ -474,33 +516,34 @@ index 6656212..486fda0 100644
[iconButton setImage:image];
[image release];
diff --git a/qtbase/src/plugins/platforms/cocoa/qnsview.mm b/qtbase/src/plugins/platforms/cocoa/qnsview.mm
index 6993407..0357bf4 100644
index d44cdb3..cfc8705 100644
--- a/qtbase/src/plugins/platforms/cocoa/qnsview.mm
+++ b/qtbase/src/plugins/platforms/cocoa/qnsview.mm
@@ -1321,7 +1321,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
@@ -1348,7 +1348,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
// On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin.
- if (phase == NSEventPhaseMayBegin)
+ if (phase == NSEventPhaseMayBegin || phase == NSEventPhaseBegan)
- if (phase == NSEventPhaseMayBegin) {
+ if (phase == NSEventPhaseMayBegin || phase == NSEventPhaseBegan) {
m_scrolling = true;
ph = Qt::ScrollBegin;
} else
#endif
@@ -1451,6 +1451,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
}
@@ -1489,6 +1489,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
&& qtKey == Qt::Key_Period) {
[self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
return YES;
+ } else if ([nsevent modifierFlags] & NSControlKeyMask && (qtKey == Qt::Key_Tab || qtKey == Qt::Key_Backtab)) {
+ } else if ([nsevent modifierFlags] & NSControlKeyMask
+ && (qtKey == Qt::Key_Tab || qtKey == Qt::Key_Backtab)) {
+ [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
+ return YES;
}
}
return [super performKeyEquivalent:nsevent];
diff --git a/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index f1f472b..97819dd 100644
index da0ba27..1d42b79 100644
--- a/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -710,6 +710,8 @@ public:
@@ -713,6 +713,8 @@ public:
QList<QUrl> selectedFiles() const;
void setSelectedFiles(const QList<QUrl> &);
QString selectedFile() const;
@@ -509,7 +552,7 @@ index f1f472b..97819dd 100644
private:
class Data : public QSharedData {
@@ -717,6 +719,7 @@ private:
@@ -720,6 +722,7 @@ private:
QUrl directory;
QString selectedNameFilter;
QList<QUrl> selectedFiles;
@@ -517,7 +560,7 @@ index f1f472b..97819dd 100644
QMutex mutex;
};
QExplicitlySharedDataPointer<Data> m_data;
@@ -770,6 +773,20 @@ inline void QWindowsFileDialogSharedData::setSelectedFiles(const QList<QUrl> &ur
@@ -773,6 +776,20 @@ inline void QWindowsFileDialogSharedData::setSelectedFiles(const QList<QUrl> &ur
m_data->selectedFiles = urls;
}
@@ -538,7 +581,7 @@ index f1f472b..97819dd 100644
inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFileDialogOptions> &o)
{
QMutexLocker (&m_data->mutex);
@@ -893,6 +910,7 @@ public:
@@ -896,6 +913,7 @@ public:
// Return the result for tracking in OnFileOk(). Differs from selection for
// example by appended default suffixes, etc.
virtual QList<QUrl> dialogResult() const = 0;
@@ -546,21 +589,25 @@ index f1f472b..97819dd 100644
inline void onFolderChange(IShellItem *);
inline void onSelectionChange();
@@ -1286,7 +1304,12 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel
void QWindowsNativeFileDialogBase::selectFile(const QString &fileName) const
@@ -1332,8 +1350,15 @@ void QWindowsNativeFileDialogBase::selectFile(const QString &fileName) const
{
- m_fileDialog->SetFileName((wchar_t*)fileName.utf16());
+ QString file = QDir::toNativeSeparators(fileName);
+ int lastBackSlash = file.lastIndexOf(QChar::fromLatin1('\\'));
+ if (lastBackSlash >= 0) {
+ file = file.mid(lastBackSlash + 1);
// Hack to prevent CLSIDs from being set as file name due to
// QFileDialogPrivate::initialSelection() being QString-based.
- if (!isClsid(fileName))
- m_fileDialog->SetFileName((wchar_t*)fileName.utf16());
+ if (!isClsid(fileName))
+ {
+ QString file = QDir::toNativeSeparators(fileName);
+ int lastBackSlash = file.lastIndexOf(QChar::fromLatin1('\\'));
+ if (lastBackSlash >= 0) {
+ file = file.mid(lastBackSlash + 1);
+ }
+ m_fileDialog->SetFileName((wchar_t*)file.utf16());;
+ }
+ m_fileDialog->SetFileName((wchar_t*)file.utf16());;
}
// Return the index of the selected filter, accounting for QFileDialog
@@ -1356,6 +1379,7 @@ bool QWindowsNativeFileDialogBase::onFileOk()
@@ -1403,6 +1428,7 @@ bool QWindowsNativeFileDialogBase::onFileOk()
{
// Store selected files as GetResults() returns invalid data after the dialog closes.
m_data.setSelectedFiles(dialogResult());
@@ -568,7 +615,7 @@ index f1f472b..97819dd 100644
return true;
}
@@ -1484,6 +1508,7 @@ public:
@@ -1531,6 +1557,7 @@ public:
QWindowsNativeFileDialogBase(data) {}
virtual QList<QUrl> selectedFiles() const;
virtual QList<QUrl> dialogResult() const;
@@ -576,7 +623,7 @@ index f1f472b..97819dd 100644
private:
inline IFileOpenDialog *openFileDialog() const
@@ -1499,6 +1524,54 @@ QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const
@@ -1546,6 +1573,54 @@ QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const
return result;
}
@@ -631,7 +678,7 @@ index f1f472b..97819dd 100644
QList<QUrl> QWindowsNativeOpenFileDialog::selectedFiles() const
{
QList<QUrl> result;
@@ -1562,6 +1635,7 @@ public:
@@ -1609,6 +1684,7 @@ public:
virtual QUrl directory() const Q_DECL_OVERRIDE;
virtual void selectFile(const QUrl &filename) Q_DECL_OVERRIDE;
virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE;
@@ -639,7 +686,7 @@ index f1f472b..97819dd 100644
virtual void setFilter() Q_DECL_OVERRIDE;
virtual void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE;
virtual QString selectedNameFilter() const Q_DECL_OVERRIDE;
@@ -1655,6 +1729,11 @@ QList<QUrl> QWindowsFileDialogHelper::selectedFiles() const
@@ -1702,6 +1778,11 @@ QList<QUrl> QWindowsFileDialogHelper::selectedFiles() const
return m_data.selectedFiles();
}
@@ -651,7 +698,7 @@ index f1f472b..97819dd 100644
void QWindowsFileDialogHelper::setFilter()
{
qCDebug(lcQpaDialogs) << __FUNCTION__;
@@ -1945,6 +2024,7 @@ public:
@@ -1992,6 +2073,7 @@ public:
virtual QUrl directory() const Q_DECL_OVERRIDE;
virtual void selectFile(const QUrl &url) Q_DECL_OVERRIDE;
virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE;
@@ -659,7 +706,7 @@ index f1f472b..97819dd 100644
virtual void setFilter() Q_DECL_OVERRIDE {}
virtual void selectNameFilter(const QString &) Q_DECL_OVERRIDE;
virtual QString selectedNameFilter() const Q_DECL_OVERRIDE;
@@ -1988,6 +2068,11 @@ QList<QUrl> QWindowsXpFileDialogHelper::selectedFiles() const
@@ -2035,6 +2117,11 @@ QList<QUrl> QWindowsXpFileDialogHelper::selectedFiles() const
return m_data.selectedFiles();
}
@@ -671,55 +718,11 @@ index f1f472b..97819dd 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/qwindowskeymapper.cpp b/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp
index ff9ad18..3fd0848 100644
--- a/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -537,17 +537,16 @@ static inline int toKeyOrUnicode(int vk, int scancode, unsigned char *kbdBuffer,
Q_ASSERT(vk > 0 && vk < 256);
int code = 0;
QChar unicodeBuffer[5];
- // While key combinations containing alt and ctrl might trigger the third assignment of a key
- // (for example "alt+ctrl+q" causes '@' on a German layout), ToUnicode often does not return the
- // wanted character if only the ctrl modifier is used. Thus we unset this modifier temporarily
- // if it is not used together with alt.
- const unsigned char controlState = kbdBuffer[VK_MENU] ? 0 : kbdBuffer[VK_CONTROL];
- if (controlState)
- kbdBuffer[VK_CONTROL] = 0;
- int res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0);
- if (controlState)
- kbdBuffer[VK_CONTROL] = controlState;
- if (res)
+ int res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0);
+ // When Ctrl modifier is used ToUnicode does not return correct values. In order to assign the
+ // right key the control modifier is removed for just that function if the previous call failed.
+ if (res == 0 && kbdBuffer[VK_CONTROL]) {
+ const unsigned char controlState = kbdBuffer[VK_CONTROL];
+ kbdBuffer[VK_CONTROL] = 0;
+ res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0);
+ kbdBuffer[VK_CONTROL] = controlState;
+ }
+ if (res)
code = unicodeBuffer[0].toUpper().unicode();
// Qt::Key_*'s are not encoded below 0x20, so try again, and DEL keys (0x7f) is encoded with a
@@ -833,7 +832,10 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con
const int qtKey = CmdTbl[cmd];
sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0);
- return true;
+ // QTBUG-43343: Make sure to return false if Qt does not handle the key, otherwise,
+ // the keys are not passed to the active media player.
+ const QKeySequence sequence(Qt::Modifier(state) + qtKey);
+ return QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(sequence);
#else
Q_UNREACHABLE();
return false;
diff --git a/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp b/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp
index 8a80729..16fda26 100644
index 543c081..d80429b 100644
--- a/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -943,7 +943,7 @@ void QWindowsWindow::destroyWindow()
@@ -973,7 +973,7 @@ void QWindowsWindow::destroyWindow()
// Clear any transient child relationships as Windows will otherwise destroy them (QTBUG-35499, QTBUG-36666)
if (QWindow *transientChild = findTransientChild(window()))
if (QWindowsWindow *tw = QWindowsWindow::baseWindowOf(transientChild))
@@ -728,7 +731,7 @@ index 8a80729..16fda26 100644
QWindowsContext *context = QWindowsContext::instance();
if (context->windowUnderMouse() == window())
context->clearWindowUnderMouse();
@@ -1144,11 +1144,24 @@ void QWindowsWindow::updateTransientParent() const
@@ -1178,11 +1178,24 @@ void QWindowsWindow::updateTransientParent() const
if (const QWindowsWindow *tw = QWindowsWindow::baseWindowOf(tp))
if (!tw->testFlag(WithinDestroy)) // Prevent destruction by parent window (QTBUG-35499, QTBUG-36666)
newTransientParent = tw->handle();
@@ -755,10 +758,10 @@ index 8a80729..16fda26 100644
{
// QWidget-attribute Qt::WA_ShowWithoutActivating .
diff --git a/qtbase/src/plugins/platforms/windows/qwindowswindow.h b/qtbase/src/plugins/platforms/windows/qwindowswindow.h
index 71debf2..4fa2e5d 100644
index fff90b4..71d060b 100644
--- a/qtbase/src/plugins/platforms/windows/qwindowswindow.h
+++ b/qtbase/src/plugins/platforms/windows/qwindowswindow.h
@@ -268,6 +268,7 @@ private:
@@ -273,6 +273,7 @@ private:
inline void setWindowState_sys(Qt::WindowState newState);
inline void setParent_sys(const QPlatformWindow *parent);
inline void updateTransientParent() const;
@@ -767,10 +770,10 @@ index 71debf2..4fa2e5d 100644
inline bool isDropSiteEnabled() const { return m_dropTarget != 0; }
void setDropSiteEnabled(bool enabled);
diff --git a/qtbase/src/widgets/dialogs/qfiledialog.cpp b/qtbase/src/widgets/dialogs/qfiledialog.cpp
index 6065ad0..03fad7a 100644
index a9d5574..ea8aa43 100644
--- a/qtbase/src/widgets/dialogs/qfiledialog.cpp
+++ b/qtbase/src/widgets/dialogs/qfiledialog.cpp
@@ -1219,6 +1219,14 @@ QList<QUrl> QFileDialogPrivate::userSelectedFiles() const
@@ -1199,6 +1199,14 @@ QList<QUrl> QFileDialogPrivate::userSelectedFiles() const
return files;
}
@@ -782,10 +785,10 @@ index 6065ad0..03fad7a 100644
+ return QByteArray();
+}
+
QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList filesToFix) const
QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList &filesToFix) const
{
QStringList files;
@@ -1282,6 +1290,13 @@ QStringList QFileDialog::selectedFiles() const
@@ -1262,6 +1270,13 @@ QStringList QFileDialog::selectedFiles() const
return files;
}
@@ -800,10 +803,10 @@ index 6065ad0..03fad7a 100644
Returns a list of urls containing the selected files in the dialog.
If no files are selected, or the mode is not ExistingFiles or
diff --git a/qtbase/src/widgets/dialogs/qfiledialog.h b/qtbase/src/widgets/dialogs/qfiledialog.h
index 70e498a..b13e8b2 100644
index 95209bc..0dca0ef 100644
--- a/qtbase/src/widgets/dialogs/qfiledialog.h
+++ b/qtbase/src/widgets/dialogs/qfiledialog.h
@@ -103,6 +103,7 @@ public:
@@ -106,6 +106,7 @@ public:
void selectFile(const QString &filename);
QStringList selectedFiles() const;
@@ -812,7 +815,7 @@ index 70e498a..b13e8b2 100644
void selectUrl(const QUrl &url);
QList<QUrl> selectedUrls() const;
diff --git a/qtbase/src/widgets/dialogs/qfiledialog_p.h b/qtbase/src/widgets/dialogs/qfiledialog_p.h
index cc2f481..cf70355 100644
index f610e46..16fa44e 100644
--- a/qtbase/src/widgets/dialogs/qfiledialog_p.h
+++ b/qtbase/src/widgets/dialogs/qfiledialog_p.h
@@ -123,6 +123,7 @@ public:
@@ -820,10 +823,10 @@ index cc2f481..cf70355 100644
QStringList typedFiles() const;
QList<QUrl> userSelectedFiles() const;
+ QByteArray userSelectedRemoteContent() const;
QStringList addDefaultSuffixToFiles(const QStringList filesToFix) const;
QStringList addDefaultSuffixToFiles(const QStringList &filesToFix) const;
QList<QUrl> addDefaultSuffixToUrls(const QList<QUrl> &urlsToFix) const;
bool removeDirectory(const QString &path);
@@ -250,6 +251,7 @@ public:
@@ -256,6 +257,7 @@ public:
QUrl directory_sys() const;
void selectFile_sys(const QUrl &filename);
QList<QUrl> selectedFiles_sys() const;
@@ -831,7 +834,7 @@ index cc2f481..cf70355 100644
void setFilter_sys();
void selectNameFilter_sys(const QString &filter);
QString selectedNameFilter_sys() const;
@@ -387,6 +389,13 @@ inline QList<QUrl> QFileDialogPrivate::selectedFiles_sys() const
@@ -393,6 +395,13 @@ inline QList<QUrl> QFileDialogPrivate::selectedFiles_sys() const
return QList<QUrl>();
}
@@ -846,95 +849,54 @@ index cc2f481..cf70355 100644
{
if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
diff --git a/qtbase/src/widgets/kernel/qwidget.cpp b/qtbase/src/widgets/kernel/qwidget.cpp
index 315d615..e99b1c3 100644
index e701eb0..1bdaff5 100644
--- a/qtbase/src/widgets/kernel/qwidget.cpp
+++ b/qtbase/src/widgets/kernel/qwidget.cpp
@@ -8674,7 +8674,7 @@ bool QWidget::event(QEvent *event)
@@ -8683,7 +8683,7 @@ bool QWidget::event(QEvent *event)
case QEvent::KeyPress: {
QKeyEvent *k = (QKeyEvent *)event;
bool res = false;
- if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
+ if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { //### Add MetaModifier?
+ if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { //### Add MetaModifier?
if (k->key() == Qt::Key_Backtab
|| (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
res = focusNextPrevChild(false);
diff --git a/qtbase/src/widgets/util/qsystemtrayicon.cpp b/qtbase/src/widgets/util/qsystemtrayicon.cpp
index 7d04cab..53c2856 100644
index dc2737c..aa9bc91 100644
--- a/qtbase/src/widgets/util/qsystemtrayicon.cpp
+++ b/qtbase/src/widgets/util/qsystemtrayicon.cpp
@@ -710,7 +710,9 @@ void QSystemTrayIconPrivate::updateMenu_sys_qpa()
menu->setPlatformMenu(platformMenu);
}
@@ -711,6 +711,8 @@ void QSystemTrayIconPrivate::updateMenu_sys_qpa()
if (menu) {
addPlatformMenu(menu);
qpa_sys->updateMenu(menu->platformMenu());
- }
+ } else {
+ qpa_sys->updateMenu(0);
+ }
}
}
void QSystemTrayIconPrivate::updateToolTip_sys_qpa()
diff --git a/qtbase/src/widgets/widgets/qwidgetlinecontrol.cpp b/qtbase/src/widgets/widgets/qwidgetlinecontrol.cpp
index e6385ba..8e1543e 100644
index 759e41a..fbd3064 100644
--- a/qtbase/src/widgets/widgets/qwidgetlinecontrol.cpp
+++ b/qtbase/src/widgets/widgets/qwidgetlinecontrol.cpp
@@ -1870,7 +1870,7 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
if (unknown && !isReadOnly()) {
@@ -1884,7 +1884,7 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
&& event->modifiers() != Qt::ControlModifier
&& event->modifiers() != (Qt::ControlModifier | Qt::ShiftModifier)) {
QString t = event->text();
- if (!t.isEmpty() && t.at(0).isPrint()) {
+ if (!t.isEmpty() && (t.at(0).isPrint() || t.at(0).unicode() == 0x200C || t.at(0).unicode() == 0x200D)) {
+ if (!t.isEmpty() && (t.at(0).isPrint() || t.at(0).unicode() == 0x200C || t.at(0).unicode() == 0x200D)) {
insert(t);
#ifndef QT_NO_COMPLETER
complete(event->key());
diff --git a/qtbase/src/widgets/widgets/qwidgettextcontrol.cpp b/qtbase/src/widgets/widgets/qwidgettextcontrol.cpp
index dfec6a1..a1be4a1 100644
index faa63cb..f3de539 100644
--- a/qtbase/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/qtbase/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -1340,7 +1340,7 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
process:
{
@@ -1348,7 +1348,7 @@ process:
return;
}
QString text = e->text();
- if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
+ if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t') || text.at(0).unicode() == 0x200C || text.at(0).unicode() == 0x200D)) {
+ if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t') || text.at(0).unicode() == 0x200C || text.at(0).unicode() == 0x200D)) {
if (overwriteMode
// no need to call deleteChar() if we have a selection, insertText
// does it already
diff --git a/qtimageformats/src/3rdparty/libwebp/src/dec/vp8l.c b/qtimageformats/src/3rdparty/libwebp/src/dec/vp8l.c
index ea0254d..93d9dc4 100644
--- a/qtimageformats/src/3rdparty/libwebp/src/dec/vp8l.c
+++ b/qtimageformats/src/3rdparty/libwebp/src/dec/vp8l.c
@@ -12,7 +12,6 @@
// Authors: Vikas Arora (vikaas.arora@gmail.com)
// Jyrki Alakuijala (jyrki@google.com)
-#include <stdio.h>
#include <stdlib.h>
#include "./alphai.h"
#include "./vp8li.h"
@@ -740,6 +739,7 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
const int mask = hdr->huffman_mask_;
assert(htree_group != NULL);
+ assert(pos < end);
assert(last_row <= height);
assert(Is8bOptimizable(hdr));
@@ -830,6 +830,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
(hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
const int mask = hdr->huffman_mask_;
assert(htree_group != NULL);
+ assert(src < src_end);
assert(src_last <= src_end);
while (!br->eos_ && src < src_last) {
@@ -1294,6 +1295,10 @@ int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
assert(dec->action_ == READ_DATA);
assert(last_row <= dec->height_);
+ if (dec->last_pixel_ == dec->width_ * dec->height_) {
+ return 1; // Done
+ }
+
// Decode (with special row processing).
return alph_dec->use_8b_decode ?
DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,

View File

@@ -1,60 +1,59 @@
#
# qmake configuration for win32-msvc2013
#
# Written for Microsoft Visual C++ 2013
# qmake configuration for Microsoft Visual Studio C/C++ Compiler
# This mkspec is used for all win32-msvcXXXX specs
#
MAKEFILE_GENERATOR = MSBUILD
isEmpty(MSC_VER)|isEmpty(MSVC_VER): error("Source mkspec must set both MSC_VER and MSVC_VER.")
#
# Baseline: Visual Studio 2005 (8.0), VC++ 14.0
#
MAKEFILE_GENERATOR = MSVC.NET
QMAKE_PLATFORM = win32
QMAKE_COMPILER = msvc
CONFIG += incremental flat precompile_header autogen_precompile_source debug_and_release debug_and_release_target embed_manifest_dll embed_manifest_exe
DEFINES += UNICODE WIN32
MSVC_VER = 12.0
QMAKE_COMPILER_DEFINES += _MSC_VER=1800 _WIN32
QMAKE_COMPILER_DEFINES += _MSC_VER=$$MSC_VER _WIN32
contains(QMAKE_TARGET.arch, x86_64) {
DEFINES += WIN64
QMAKE_COMPILER_DEFINES += _WIN64
}
QMAKE_COMPILER = msvc
QMAKE_CC = cl
QMAKE_LEX = flex
QMAKE_LEXFLAGS =
QMAKE_YACC = byacc
QMAKE_YACCFLAGS = -d
QMAKE_CFLAGS = -nologo -Zm200 -Zc:wchar_t -FS
QMAKE_CFLAGS = -nologo -Zc:wchar_t
QMAKE_CFLAGS_WARN_ON = -W3
QMAKE_CFLAGS_WARN_OFF = -W0
QMAKE_CFLAGS_RELEASE = -O2 -MT -Zc:strictStrings
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MT -Zi -Zc:strictStrings
QMAKE_CFLAGS_RELEASE = -O2 -MT
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MT -Zi
QMAKE_CFLAGS_DEBUG = -Zi -MTd
QMAKE_CFLAGS_YACC =
QMAKE_CFLAGS_LTCG = -GL
QMAKE_CFLAGS_MP = -MP
QMAKE_CFLAGS_SSE2 = -arch:SSE2
QMAKE_CFLAGS_SSE3 = -arch:SSE2
QMAKE_CFLAGS_SSSE3 = -arch:SSE2
QMAKE_CFLAGS_SSE4_1 = -arch:SSE2
QMAKE_CFLAGS_SSE4_2 = -arch:SSE2
QMAKE_CFLAGS_AVX = -arch:AVX
QMAKE_CFLAGS_AVX2 = -arch:AVX
QMAKE_CXX = $$QMAKE_CC
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS
QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON -w34100 -w34189
QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON -w34100 -w34189 -w44996
QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF
QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE
QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG
QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC
QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG
QMAKE_CXXFLAGS_MP = $$QMAKE_CFLAGS_MP
QMAKE_CXXFLAGS_STL_ON = -EHsc
QMAKE_CXXFLAGS_STL_OFF =
QMAKE_CXXFLAGS_RTTI_ON = -GR
QMAKE_CXXFLAGS_RTTI_OFF =
QMAKE_CXXFLAGS_EXCEPTIONS_ON = -EHsc
QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -D_HAS_EXCEPTIONS=0
QMAKE_CXXFLAGS_EXCEPTIONS_OFF =
QMAKE_INCDIR =
@@ -70,8 +69,8 @@ QMAKE_LFLAGS = /NOLOGO /DYNAMICBASE /NXCOMPAT
QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO
QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO = /DEBUG /OPT:REF /INCREMENTAL:NO
QMAKE_LFLAGS_DEBUG = /DEBUG
QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE@QMAKE_SUBSYSTEM_SUFFIX@
QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS@QMAKE_SUBSYSTEM_SUFFIX@
QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE
QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS
QMAKE_LFLAGS_EXE = \"/MANIFESTDEPENDENCY:type=\'win32\' name=\'Microsoft.Windows.Common-Controls\' version=\'6.0.0.0\' publicKeyToken=\'6595b64144ccf1df\' language=\'*\' processorArchitecture=\'*\'\"
QMAKE_LFLAGS_DLL = /DLL
QMAKE_LFLAGS_LTCG = /LTCG
@@ -91,9 +90,58 @@ QMAKE_IDL = midl
QMAKE_LIB = lib /NOLOGO
QMAKE_RC = rc
include(../common/shell-win32.conf)
VCPROJ_EXTENSION = .vcxproj
VCPROJ_EXTENSION = .vcproj
VCSOLUTION_EXTENSION = .sln
VCPROJ_KEYWORD = Qt4VSv1.0
load(qt_config)
#
# Version-specific changes
#
greaterThan(MSC_VER, 1499) {
# Visual Studio 2008 (9.0) / Visual C++ 15.0 and up
QMAKE_CFLAGS_MP = -MP
QMAKE_CXXFLAGS_MP = $$QMAKE_CFLAGS_MP
}
greaterThan(MSC_VER, 1599) {
# Visual Studio 2010 (10.0) / Visual C++ 16.0 and up
MAKEFILE_GENERATOR = MSBUILD
QMAKE_CFLAGS_AVX = -arch:AVX
QMAKE_CFLAGS_AVX2 = -arch:AVX
VCPROJ_EXTENSION = .vcxproj
}
greaterThan(MSC_VER, 1699) {
# Visual Studio 2012 (11.0) / Visual C++ 17.0 and up
QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -D_HAS_EXCEPTIONS=0
QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE@QMAKE_SUBSYSTEM_SUFFIX@
QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS@QMAKE_SUBSYSTEM_SUFFIX@
QT_CONFIG += c++11
CONFIG += c++11
}
greaterThan(MSC_VER, 1799) {
# Visual Studio 2013 (12.0) / Visual C++ 18.0 and up
QMAKE_CFLAGS += -FS
QMAKE_CXXFLAGS += -FS
equals(MSC_VER, 1800) {
QMAKE_CFLAGS_RELEASE += -Zc:strictStrings
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -Zc:strictStrings
QMAKE_CXXFLAGS_RELEASE += -Zc:strictStrings
QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += -Zc:strictStrings
}
}
greaterThan(MSC_VER, 1899) {
# Visual Studio 2015 (14.0) / Visual C++ 19.0 and up
QMAKE_CFLAGS += -Zc:strictStrings
QMAKE_CFLAGS_WARN_ON += -w44456 -w44457 -w44458
QMAKE_CFLAGS_AVX2 = -arch:AVX2
QMAKE_CXXFLAGS += -Zc:strictStrings
QMAKE_CXXFLAGS_WARN_ON += -w44456 -w44457 -w44458
}
unset(MSC_VER)

View File

@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the qmake application of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
** 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
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** 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$
@@ -105,7 +105,7 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
{
if(project->isActiveConfig("generate_pbxbuild_makefile")) {
QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
qmake_getpwd());
FileFixifyToIndir);
QFile mkwrapf(mkwrap);
if(mkwrapf.open(QIODevice::WriteOnly | QIODevice::Text)) {
debug_msg(1, "pbuilder: Creating file: %s", mkwrap.toLatin1().constData());
@@ -151,7 +151,7 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
subdir += Option::dir_sep;
tmp = subdir + tmp;
}
QFileInfo fi(fileInfo(Option::fixPathToLocalOS(tmp, true)));
QFileInfo fi(fileInfo(Option::normalizePath(tmp)));
if(fi.exists()) {
if(fi.isDir()) {
QString profile = tmp;
@@ -184,13 +184,13 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
bool in_root = true;
QString name = qmake_getpwd();
if(project->isActiveConfig("flat")) {
QString flat_file = fileFixify(name, oldpwd, oldoutpwd, FileFixifyRelative);
QString flat_file = fileFixify(name, FileFixifyBackwards | FileFixifyRelative);
if(flat_file.indexOf(Option::dir_sep) != -1) {
QStringList dirs = flat_file.split(Option::dir_sep);
name = dirs.back();
}
} else {
QString flat_file = fileFixify(name, oldpwd, oldoutpwd, FileFixifyRelative);
QString flat_file = fileFixify(name, FileFixifyBackwards | FileFixifyRelative);
if(QDir::isRelativePath(flat_file) && flat_file.indexOf(Option::dir_sep) != -1) {
QString last_grp("QMAKE_SUBDIR_PBX_HEIR_GROUP");
QStringList dirs = flat_file.split(Option::dir_sep);
@@ -215,7 +215,7 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
t << "\t\t" << project_key << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("lastKnownFileType", "wrapper.pb-project") << ";\n"
<< "\t\t\t" << writeSettings("name", escapeFilePath(tmp_proj.first("TARGET") + projectSuffix())) << ";\n"
<< "\t\t\t" << writeSettings("name", tmp_proj.first("TARGET") + projectSuffix()) << ";\n"
<< "\t\t\t" << writeSettings("path", pbxproj) << ";\n"
<< "\t\t\t" << writeSettings("sourceTree", "<absolute>") << ";\n"
<< "\t\t};\n";
@@ -283,7 +283,7 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
t << "\t\t" << keyFor(grp_it.key()) << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";\n"
<< "\t\t\t" << writeSettings("name", grp_it.key().section(Option::dir_sep, -1)) << ";\n"
<< "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";\n"
<< "\t\t};\n";
}
@@ -307,7 +307,7 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
ProString name = l.at(i);
const ProKey buildKey(name + ".build");
if (!project->isEmpty(buildKey)) {
const QString build = project->values(buildKey).first().toQString();
const QString build = project->first(buildKey).toQString();
if (build.toLower() != configName.toLower())
continue;
}
@@ -344,7 +344,7 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_AGGREGATE_TARGET") << " = {\n"
<< "\t\t\t" << writeSettings("buildPhases", ProStringList(), SettingsAsList, 4) << ";\n"
<< "\t\t\tbuildSettings = {\n"
<< "\t\t\t\t" << writeSettings("PRODUCT_NAME", project->values("TARGET").first()) << ";\n"
<< "\t\t\t\t" << writeSettings("PRODUCT_NAME", project->first("TARGET")) << ";\n"
<< "\t\t\t};\n";
{
ProStringList dependencies;
@@ -354,8 +354,8 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
t << "\t\t\t" << writeSettings("dependencies", dependencies, SettingsAsList, 4) << ";\n"
}
t << "\t\t\t" << writeSettings("isa", "PBXAggregateTarget", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", project->values("TARGET").first()) << ";\n"
<< "\t\t\t" << writeSettings("productName", project->values("TARGET").first()) << ";\n"
<< "\t\t\t" << writeSettings("name", project->first("TARGET")) << ";\n"
<< "\t\t\t" << writeSettings("productName", project->first("TARGET")) << ";\n"
<< "\t\t};\n";
#endif
@@ -455,8 +455,8 @@ ProjectBuilderSources::files(QMakeProject *project) const
{
QStringList ret = project->values(ProKey(key)).toQStringList();
if(key == "QMAKE_INTERNAL_INCLUDED_FILES") {
QString qtPrefix(QLibraryInfo::rawLocation(QLibraryInfo::PrefixPath, QLibraryInfo::EffectivePaths) + '/');
QString qtSrcPrefix(QLibraryInfo::rawLocation(QLibraryInfo::PrefixPath, QLibraryInfo::EffectiveSourcePaths) + '/');
QString qtPrefix(project->propertyValue(ProKey("QT_INSTALL_PREFIX/get")).toQString() + '/');
QString qtSrcPrefix(project->propertyValue(ProKey("QT_INSTALL_PREFIX/src")).toQString() + '/');
QStringList newret;
for(int i = 0; i < ret.size(); ++i) {
@@ -507,14 +507,6 @@ static QString xcodeFiletypeForFilename(const QString &filename)
bool
ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
{
// The code in this function assumes that the current directory matches
// the output directory, which is not actually the case when we are called
// from the generic generator code. Instead of changing every single
// assumption and fileFixify we cheat by moving into the output directory
// for the duration of this function.
QString input_dir = qmake_getpwd();
qmake_setpwd(Option::output_dir);
ProStringList tmp;
bool did_preprocess = false;
@@ -536,7 +528,6 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QFile mkf(mkfile);
if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
writingUnixMakefileGenerator = true;
qmake_setpwd(input_dir); // Makefile generation assumes input_dir as pwd
debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
QTextStream mkt(&mkf);
writeHeader(mkt);
@@ -545,10 +536,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
mkt.flush();
mkf.close();
writingUnixMakefileGenerator = false;
qmake_setpwd(Option::output_dir);
}
QString phase_key = keyFor("QMAKE_PBX_MAKEQMAKE_BUILDPHASE");
mkfile = fileFixify(mkfile, qmake_getpwd());
mkfile = fileFixify(mkfile);
project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
t << "\t\t" << phase_key << " = {\n"
<< "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";\n"
@@ -557,16 +547,20 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
<< "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", "Qt Qmake") << ";\n"
<< "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";\n"
<< "\t\t\t" << writeSettings("shellScript", "make -C " + IoUtils::shellQuoteUnix(qmake_getpwd()) + " -f " + IoUtils::shellQuoteUnix(mkfile)) << ";\n"
<< "\t\t\t" << writeSettings("shellScript", "make -C " + IoUtils::shellQuoteUnix(Option::output_dir)
+ " -f " + IoUtils::shellQuoteUnix(mkfile)) << ";\n"
<< "\t\t\t" << writeSettings("showEnvVarsInLog", "0") << ";\n"
<< "\t\t};\n";
}
// FIXME: Move all file resolving logic out of ProjectBuilderSources::files(), as it
// doesn't have access to any of the information it needs to resolve relative paths.
project->values("QMAKE_INTERNAL_INCLUDED_FILES").prepend(fileFixify(project->projectFile(), qmake_getpwd(), input_dir));
project->values("QMAKE_INTERNAL_INCLUDED_FILES").prepend(project->projectFile());
// Since we can't fileFixify inside ProjectBuilderSources::files(), we resolve the absolute paths here
project->values("QMAKE_INTERNAL_INCLUDED_FILES") = ProStringList(fileFixify(project->values("QMAKE_INTERNAL_INCLUDED_FILES").toQStringList(), FileFixifyAbsolute));
project->values("QMAKE_INTERNAL_INCLUDED_FILES") = ProStringList(
fileFixify(project->values("QMAKE_INTERNAL_INCLUDED_FILES").toQStringList(),
FileFixifyFromOutdir | FileFixifyAbsolute));
//DUMP SOURCES
QMap<QString, ProStringList> groups;
@@ -623,11 +617,10 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
ProStringList &src_list = project->values(ProKey("QMAKE_PBX_" + sources.at(source).keyName()));
ProStringList &root_group_list = project->values("QMAKE_PBX_GROUPS");
const QStringList &files = fileFixify(sources.at(source).files(project));
const QStringList &files = fileFixify(sources.at(source).files(project),
FileFixifyFromOutdir | FileFixifyAbsolute);
for(int f = 0; f < files.count(); ++f) {
QString file = files[f];
if(file.length() >= 2 && (file[0] == '"' || file[0] == '\'') && file[(int) file.length()-1] == file[0])
file = file.mid(1, file.length()-2);
if(!sources.at(source).compilerName().isNull() &&
!verifyExtraCompiler(sources.at(source).compilerName(), file))
continue;
@@ -637,12 +630,11 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
bool in_root = true;
QString src_key = keyFor(file);
file = fileFixify(file, qmake_getpwd(), Option::output_dir, FileFixifyAbsolute);
QString name = file.split(Option::dir_sep).back();
if (!project->isActiveConfig("flat")) {
// Build group hierarchy for file references that match the source our build dir
QString relativePath = fileFixify(file, input_dir, qmake_getpwd(), FileFixifyRelative);
QString relativePath = fileFixify(file, FileFixifyToIndir | FileFixifyRelative);
if (QDir::isRelativePath(relativePath) && relativePath.startsWith(QLatin1String("../")))
relativePath = fileFixify(file, FileFixifyRelative); // Try build dir
@@ -678,9 +670,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
//source reference
t << "\t\t" << src_key << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("path", escapeFilePath(file)) << ";\n";
<< "\t\t\t" << writeSettings("path", file) << ";\n";
if (name != file)
t << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";\n";
t << "\t\t\t" << writeSettings("name", name) << ";\n";
t << "\t\t\t" << writeSettings("sourceTree", "<absolute>") << ";\n";
QString filetype = xcodeFiletypeForFilename(file);
if (!filetype.isNull())
@@ -715,7 +707,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
t << "\t\t" << keyFor(grp_it.key()) << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";\n"
<< "\t\t\t" << writeSettings("name", grp_it.key().section(Option::dir_sep, -1)) << ";\n"
<< "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";\n"
<< "\t\t};\n";
}
@@ -730,8 +722,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
QTextStream mkt(&mkf);
writeHeader(mkt);
mkt << "MOC = " << Option::fixPathToTargetOS(var("QMAKE_MOC")) << endl;
mkt << "UIC = " << Option::fixPathToTargetOS(var("QMAKE_UIC")) << endl;
mkt << "MOC = " << var("QMAKE_MOC") << endl;
mkt << "UIC = " << var("QMAKE_UIC") << endl;
mkt << "LEX = " << var("QMAKE_LEX") << endl;
mkt << "LEXFLAGS = " << var("QMAKE_LEXFLAGS") << endl;
mkt << "YACC = " << var("QMAKE_YACC") << endl;
@@ -739,13 +731,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
mkt << "DEFINES = "
<< varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
<< varGlue("DEFINES","-D"," -D","") << endl;
mkt << "INCPATH = -I" << specdir();
if(!project->isActiveConfig("no_include_pwd")) {
QString pwd = escapeFilePath(fileFixify(qmake_getpwd()));
if(pwd.isEmpty())
pwd = ".";
mkt << " -I" << pwd;
}
mkt << "INCPATH =";
{
const ProStringList &incs = project->values("INCLUDEPATH");
for (ProStringList::ConstIterator incit = incs.begin(); incit != incs.end(); ++incit)
@@ -756,30 +742,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
mkt << endl;
mkt << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
mkt << "MOVE = " << var("QMAKE_MOVE") << endl << endl;
mkt << "IMAGES = " << varList("QMAKE_IMAGE_COLLECTION") << endl;
mkt << "PARSERS =";
if(!project->isEmpty("YACCSOURCES")) {
const ProStringList &yaccs = project->values("YACCSOURCES");
for (ProStringList::ConstIterator yit = yaccs.begin(); yit != yaccs.end(); ++yit) {
QFileInfo fi(fileInfo((*yit).toQString()));
mkt << " " << fi.path() << Option::dir_sep << fi.baseName()
<< Option::yacc_mod << Option::cpp_ext.first();
}
}
if(!project->isEmpty("LEXSOURCES")) {
const ProStringList &lexs = project->values("LEXSOURCES");
for (ProStringList::ConstIterator lit = lexs.begin(); lit != lexs.end(); ++lit) {
QFileInfo fi(fileInfo((*lit).toQString()));
mkt << " " << fi.path() << Option::dir_sep << fi.baseName()
<< Option::lex_mod << Option::cpp_ext.first();
}
}
mkt << "\n";
mkt << "preprocess: $(PARSERS) compilers\n";
mkt << "clean preprocess_clean: parser_clean compiler_clean\n\n";
mkt << "parser_clean:\n";
if(!project->isEmpty("YACCSOURCES") || !project->isEmpty("LEXSOURCES"))
mkt << "\t-rm -f $(PARSERS)\n";
mkt << "preprocess: compilers\n";
mkt << "clean preprocess_clean: compiler_clean\n\n";
writeExtraTargets(mkt);
if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
mkt << "compilers:";
@@ -800,8 +764,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
if(added && !(added % 3))
mkt << "\\\n\t";
++added;
const QString file_name = fileFixify(fn, Option::output_dir, Option::output_dir);
mkt << " " << replaceExtraCompilerVariables(Option::fixPathToTargetOS(tmp_out.first().toQString(), false), file_name, QString());
const QString file_name = fileFixify(fn, FileFixifyFromOutdir);
mkt << ' ' << escapeDependencyPath(Option::fixPathToTargetOS(
replaceExtraCompilerVariables(tmp_out.first().toQString(), file_name, QString(), NoShell)));
}
}
}
@@ -812,7 +777,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
mkt.flush();
mkf.close();
}
mkfile = fileFixify(mkfile, qmake_getpwd());
mkfile = fileFixify(mkfile);
QString phase_key = keyFor("QMAKE_PBX_PREPROCESS_TARGET");
// project->values("QMAKE_PBX_BUILDPHASES").append(phase_key);
project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
@@ -823,7 +788,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
<< "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", "Qt Preprocessors") << ";\n"
<< "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";\n"
<< "\t\t\t" << writeSettings("shellScript", "make -C " + IoUtils::shellQuoteUnix(qmake_getpwd()) + " -f " + IoUtils::shellQuoteUnix(mkfile)) << ";\n"
<< "\t\t\t" << writeSettings("shellScript", "make -C " + IoUtils::shellQuoteUnix(Option::output_dir)
+ " -f " + IoUtils::shellQuoteUnix(mkfile)) << ";\n"
<< "\t\t\t" << writeSettings("showEnvVarsInLog", "0") << ";\n"
<< "\t\t};\n";
}
@@ -843,22 +810,17 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES
ProStringList &libdirs = project->values("QMAKE_PBX_LIBPATHS"),
&frameworkdirs = project->values("QMAKE_FRAMEWORKPATH");
static const char * const libs[] = { "QMAKE_LFLAGS", "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", 0 };
static const char * const libs[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", 0 };
for (int i = 0; libs[i]; i++) {
tmp = project->values(libs[i]);
for(int x = 0; x < tmp.count();) {
bool remove = false;
QString library, name;
ProString opt = tmp[x].trimmed();
if (opt.length() >= 2 && (opt.at(0) == '"' || opt.at(0) == '\'') && opt.endsWith(opt.at(0)))
opt = opt.mid(1, opt.length()-2);
if(opt.startsWith("-L")) {
QString r = opt.mid(2).toQString();
fixForOutput(r);
libdirs.append(r);
} else if(opt == "-prebind") {
project->values("QMAKE_DO_PREBINDING").append("TRUE");
remove = true;
} else if(opt.startsWith("-l")) {
name = opt.mid(2).toQString();
QString lib("lib" + name);
@@ -887,10 +849,10 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QString librarySuffix = project->first("QMAKE_XCODE_LIBRARY_SUFFIX").toQString();
suffixSetting = "$(" + suffixSetting + ")";
if (!librarySuffix.isEmpty()) {
library = library.replace(librarySuffix, suffixSetting);
name = name.remove(librarySuffix);
library.replace(librarySuffix, suffixSetting);
name.remove(librarySuffix);
} else {
library = library.replace(name, name + suffixSetting);
library.replace(name, name + suffixSetting);
}
}
}
@@ -956,15 +918,14 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
if(!path.isEmpty() && !libdirs.contains(path))
libdirs += path;
}
library = fileFixify(library);
QString filetype = xcodeFiletypeForFilename(library);
library = fileFixify(library, FileFixifyFromOutdir | FileFixifyAbsolute);
QString key = keyFor(library);
if (!project->values("QMAKE_PBX_LIBRARIES").contains(key)) {
bool is_frmwrk = (library.endsWith(".framework"));
t << "\t\t" << key << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";\n"
<< "\t\t\t" << writeSettings("path", escapeFilePath(library)) << ";\n"
<< "\t\t\t" << writeSettings("name", name) << ";\n"
<< "\t\t\t" << writeSettings("path", library) << ";\n"
<< "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(library)), SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("sourceTree", "<absolute>") << ";\n";
if (is_frmwrk)
@@ -999,21 +960,22 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QTextStream mkt(&mkf);
writeHeader(mkt);
mkt << "SUBLIBS= ";
// ### This is missing the parametrization found in unixmake2.cpp
tmp = project->values("SUBLIBS");
for(int i = 0; i < tmp.count(); i++)
t << "tmp/lib" << tmp[i] << ".a ";
t << escapeFilePath("tmp/lib" + tmp[i] + ".a") << ' ';
t << endl << endl;
mkt << "sublibs: $(SUBLIBS)\n\n";
tmp = project->values("SUBLIBS");
for(int i = 0; i < tmp.count(); i++)
t << "tmp/lib" << tmp[i] << ".a:\n\t"
t << escapeFilePath("tmp/lib" + tmp[i] + ".a") + ":\n\t"
<< var(ProKey("MAKELIB" + tmp[i])) << endl << endl;
mkt.flush();
mkf.close();
writingUnixMakefileGenerator = false;
}
QString phase_key = keyFor("QMAKE_PBX_SUBLIBS_BUILDPHASE");
mkfile = fileFixify(mkfile, qmake_getpwd());
mkfile = fileFixify(mkfile);
project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
t << "\t\t" << phase_key << " = {\n"
<< "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";\n"
@@ -1022,7 +984,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
<< "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", "Qt Sublibs") << ";\n"
<< "\t\t\t" << writeSettings("shellPath", "/bin/sh") << "\n"
<< "\t\t\t" << writeSettings("shellScript", "make -C " + IoUtils::shellQuoteUnix(qmake_getpwd()) + " -f " + IoUtils::shellQuoteUnix(mkfile)) << ";\n"
<< "\t\t\t" << writeSettings("shellScript", "make -C " + IoUtils::shellQuoteUnix(Option::output_dir)
+ " -f " + IoUtils::shellQuoteUnix(mkfile)) << ";\n"
<< "\t\t\t" << writeSettings("showEnvVarsInLog", "0") << ";\n"
<< "\t\t};\n";
}
@@ -1058,6 +1022,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
<< "\t\t\t" << writeSettings("name", "Qt Prelink") << ";\n"
<< "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";\n"
<< "\t\t\t" << writeSettings("shellScript", project->values("QMAKE_PRE_LINK")) << ";\n"
<< "\t\t\t" << writeSettings("showEnvVarsInLog", "0") << ";\n"
<< "\t\t};\n";
}
@@ -1070,7 +1035,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
t << "\t\t" << key << " = {\n"
<< "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_LIBRARIES"), SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";\n"
<< "\t\t\t" << writeSettings("name", grp) << ";\n"
<< "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";\n"
<< "\t\t};\n";
}
@@ -1083,7 +1048,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
<< "\t\t\t" << writeSettings("files", project->values("QMAKE_PBX_BUILD_LIBRARIES"), SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("isa", "PBXFrameworksBuildPhase", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";\n"
<< "\t\t\t" << writeSettings("name", grp) << ";\n"
<< "\t\t};\n";
}
@@ -1101,14 +1066,14 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
<< "\t\t\t" << writeSettings("name", "Qt Postlink") << ";\n"
<< "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";\n"
<< "\t\t\t" << writeSettings("shellScript", project->values("QMAKE_POST_LINK")) << ";\n"
<< "\t\t\t" << writeSettings("showEnvVarsInLog", "0") << ";\n"
<< "\t\t};\n";
}
if (!project->isEmpty("DESTDIR")) {
QString phase_key = keyFor("QMAKE_PBX_TARGET_COPY_PHASE");
QString destDir = project->first("DESTDIR").toQString();
destDir = fixForOutput(destDir);
destDir = fileInfo(Option::fixPathToLocalOS(destDir)).absoluteFilePath();
QString destDir = fileFixify(project->first("DESTDIR").toQString(),
FileFixifyFromOutdir | FileFixifyAbsolute);
project->values("QMAKE_PBX_BUILDPHASES").append(phase_key);
t << "\t\t" << phase_key << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";\n"
@@ -1119,7 +1084,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
<< "\t\t\t" << writeSettings("outputPaths", ProStringList(), SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";\n"
<< "\t\t\t" << writeSettings("shellScript", fixForOutput("cp -r $BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME " + escapeFilePath(destDir))) << ";\n"
<< "\t\t\t" << writeSettings("shellScript", fixForOutput("cp -r $BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME " + IoUtils::shellQuoteUnix(destDir))) << ";\n"
<< "\t\t\t" << writeSettings("showEnvVarsInLog", "0") << ";\n"
<< "\t\t};\n";
}
bool copyBundleResources = project->isActiveConfig("app_bundle") && project->first("TEMPLATE") == "app";
@@ -1137,13 +1103,13 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
//all files
const ProStringList &files = project->values(ProKey(bundle_data[i] + ".files"));
for(int file = 0; file < files.count(); file++) {
QString fn = fileFixify(files[file].toQString(), Option::output_dir, input_dir, FileFixifyAbsolute);
QString fn = fileFixify(files[file].toQString(), FileFixifyAbsolute);
QString name = fn.split(Option::dir_sep).back();
QString file_ref_key = keyFor("QMAKE_PBX_BUNDLE_DATA_FILE_REF." + bundle_data[i] + "-" + fn);
bundle_file_refs += file_ref_key;
t << "\t\t" << file_ref_key << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("path", escapeFilePath(fn)) << ";\n"
<< "\t\t\t" << writeSettings("path", fn) << ";\n"
<< "\t\t\t" << writeSettings("name", name) << ";\n"
<< "\t\t\t" << writeSettings("sourceTree", "<absolute>") << ";\n"
<< "\t\t};\n";
@@ -1169,7 +1135,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
t << "\t\t" << phase_key << " = {\n"
<< "\t\t\t" << writeSettings("name", "Copy '" + bundle_data[i] + "' Files to Bundle") << ";\n"
<< "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("dstPath", escapeFilePath(path)) << ";\n"
<< "\t\t\t" << writeSettings("dstPath", path) << ";\n"
<< "\t\t\t" << writeSettings("dstSubfolderSpec", "1", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("files", bundle_files, SettingsAsList, 4) << ";\n"
@@ -1193,8 +1159,6 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
if (copyBundleResources) {
if (!project->isEmpty("ICON")) {
ProString icon = project->first("ICON");
if (icon.length() >= 2 && (icon.at(0) == '"' || icon.at(0) == '\'') && icon.endsWith(icon.at(0)))
icon = icon.mid(1, icon.length() - 2);
bundle_resources_files += keyFor(icon + ".BUILDABLE");
}
@@ -1207,7 +1171,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
<< "\t\t\t" << writeSettings("files", bundle_resources_files, SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("isa", "PBXResourcesBuildPhase", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";\n"
<< "\t\t\t" << writeSettings("name", grp) << ";\n"
<< "\t\t};\n";
}
@@ -1232,9 +1196,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
} else {
t << "\t\t\t" << writeSettings("explicitFileType", "compiled.mach-o.executable") << ";\n";
}
QString app = (!project->isEmpty("DESTDIR") ? project->first("DESTDIR") + project->first("QMAKE_ORIG_TARGET") :
qmake_getpwd()) + Option::dir_sep + targ;
t << "\t\t\t" << writeSettings("path", escapeFilePath(targ)) << ";\n";
t << "\t\t\t" << writeSettings("path", targ) << ";\n";
} else {
ProString lib = project->first("QMAKE_ORIG_TARGET");
if(project->isActiveConfig("staticlib")) {
@@ -1262,7 +1224,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
} else {
t << "\t\t\t" << writeSettings("explicitFileType", "compiled.mach-o.dylib") << ";\n";
}
t << "\t\t\t" << writeSettings("path", escapeFilePath(lib)) << ";\n";
t << "\t\t\t" << writeSettings("path", lib) << ";\n";
}
t << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";\n"
<< "\t\t};\n";
@@ -1282,7 +1244,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
t << "\t\t" << keyFor("QMAKE_PBX_ROOT_GROUP") << " = {\n"
<< "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_GROUPS"), SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";\n"
<< "\t\t\t" << writeSettings("name", project->first("QMAKE_ORIG_TARGET")) << ";\n"
<< "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";\n"
<< "\t\t};\n";
@@ -1328,14 +1290,14 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
else
t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.tool") << ";\n";
}
t << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";\n"
<< "\t\t\t" << writeSettings("productName", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";\n";
t << "\t\t\t" << writeSettings("name", project->first("QMAKE_ORIG_TARGET")) << ";\n"
<< "\t\t\t" << writeSettings("productName", project->first("QMAKE_ORIG_TARGET")) << ";\n";
} else {
ProString lib = project->first("QMAKE_ORIG_TARGET");
if(!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib"))
lib.prepend("lib");
t << "\t\t\t" << writeSettings("name", escapeFilePath(lib)) << ";\n"
<< "\t\t\t" << writeSettings("productName", escapeFilePath(lib)) << ";\n";
t << "\t\t\t" << writeSettings("name", lib) << ";\n"
<< "\t\t\t" << writeSettings("productName", lib) << ";\n";
if (!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";\n";
else if (project->isActiveConfig("staticlib"))
@@ -1346,8 +1308,98 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.library.dynamic") << ";\n";
}
if(!project->isEmpty("DESTDIR"))
t << "\t\t\t" << writeSettings("productInstallPath", escapeFilePath(project->first("DESTDIR"))) << ";\n";
t << "\t\t\t" << writeSettings("productInstallPath", project->first("DESTDIR")) << ";\n";
t << "\t\t};\n";
// Test target for running Qt unit tests under XCTest
if (project->isActiveConfig("testcase") && project->isActiveConfig("app_bundle")) {
QString devNullFileReferenceKey = keyFor(pbx_dir + "QMAKE_PBX_DEV_NULL_FILE_REFERENCE");
t << "\t\t" << devNullFileReferenceKey << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("name", "/dev/null") << ";\n"
<< "\t\t\t" << writeSettings("path", "/dev/null") << ";\n"
<< "\t\t\t" << writeSettings("lastKnownFileType", "sourcecode.c.c") << ";\n"
<< "\t\t\t" << writeSettings("sourceTree", "<absolute>") << ";\n"
<< "\t\t};\n";
QString devNullBuildFileKey = keyFor(pbx_dir + "QMAKE_PBX_DEV_NULL_BUILD_FILE");
t << "\t\t" << devNullBuildFileKey << " = {\n"
<< "\t\t\t" << writeSettings("fileRef", devNullFileReferenceKey) << ";\n"
<< "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";\n"
<< "\t\t};\n";
QString dummySourceBuildPhaseKey = keyFor(pbx_dir + "QMAKE_PBX_DUMMY_SOURCE_BUILD_PHASE");
t << "\t\t" << dummySourceBuildPhaseKey << " = {\n"
<< "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("files", devNullBuildFileKey, SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("isa", "PBXSourcesBuildPhase", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n"
<< "\t\t};\n";
ProStringList testBundleBuildConfigs;
ProString targetName = project->first("QMAKE_ORIG_TARGET");
ProString testHost = "$(BUILT_PRODUCTS_DIR)/" + targetName + ".app/";
if (!project->isActiveConfig("ios"))
testHost.append("Contents/MacOS/");
testHost.append(targetName);
static const char * const configs[] = { "Debug", "Release", 0 };
for (int i = 0; configs[i]; i++) {
QString testBundleBuildConfig = keyFor(pbx_dir + "QMAKE_PBX_TEST_BUNDLE_BUILDCONFIG_" + configs[i]);
t << "\t\t" << testBundleBuildConfig << " = {\n"
<< "\t\t\t" << writeSettings("isa", "XCBuildConfiguration", SettingsNoQuote) << ";\n"
<< "\t\t\tbuildSettings = {\n"
<< "\t\t\t\t" << writeSettings("INFOPLIST_FILE", project->first("QMAKE_XCODE_SPECDIR") + "/QtTest.plist") << ";\n"
<< "\t\t\t\t" << writeSettings("OTHER_LDFLAGS", "") << ";\n"
<< "\t\t\t\t" << writeSettings("TEST_HOST", testHost) << ";\n"
<< "\t\t\t\t" << writeSettings("DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym") << ";\n"
<< "\t\t\t};\n"
<< "\t\t\t" << writeSettings("name", configs[i], SettingsNoQuote) << ";\n"
<< "\t\t};\n";
testBundleBuildConfigs.append(testBundleBuildConfig);
}
QString testBundleBuildConfigurationListKey = keyFor(pbx_dir + "QMAKE_PBX_TEST_BUNDLE_BUILDCONFIG_LIST");
t << "\t\t" << testBundleBuildConfigurationListKey << " = {\n"
<< "\t\t\t" << writeSettings("isa", "XCConfigurationList", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("buildConfigurations", testBundleBuildConfigs, SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("defaultConfigurationIsVisible", "0", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("defaultConfigurationName", "Debug", SettingsNoQuote) << ";\n"
<< "\t\t};\n";
QString primaryTargetDependencyKey = keyFor(pbx_dir + "QMAKE_PBX_PRIMARY_TARGET_DEP");
t << "\t\t" << primaryTargetDependencyKey << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXTargetDependency", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("target", keyFor(pbx_dir + "QMAKE_PBX_TARGET")) << ";\n"
<< "\t\t};\n";
QString testBundleReferenceKey = keyFor("QMAKE_TEST_BUNDLE_REFERENCE");
t << "\t\t" << testBundleReferenceKey << " = {\n"
<< "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("explicitFileType", "wrapper.cfbundle") << ";\n"
<< "\t\t\t" << writeSettings("includeInIndex", "0", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";\n"
<< "\t\t};\n";
QString testTargetKey = keyFor(pbx_dir + "QMAKE_PBX_TEST_TARGET");
project->values("QMAKE_PBX_TARGETS").append(testTargetKey);
t << "\t\t" << testTargetKey << " = {\n"
<< "\t\t\t" << writeSettings("buildPhases", dummySourceBuildPhaseKey, SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("dependencies", primaryTargetDependencyKey, SettingsAsList, 4) << ";\n"
<< "\t\t\t" << writeSettings("buildConfigurationList", testBundleBuildConfigurationListKey) << ";\n"
<< "\t\t\t" << writeSettings("productType", "com.apple.product-type.bundle.unit-test") << ";\n"
<< "\t\t\t" << writeSettings("isa", "PBXNativeTarget", SettingsNoQuote) << ";\n"
<< "\t\t\t" << writeSettings("productReference", testBundleReferenceKey) << ";\n"
<< "\t\t\t" << writeSettings("name", "Qt Test") << ";\n"
<< "\t\t};\n";
QLatin1Literal testTargetID("TestTargetID");
project->values(ProKey("QMAKE_PBX_TARGET_ATTRIBUTES_" + testTargetKey + "_" + testTargetID)).append(keyFor(pbx_dir + "QMAKE_PBX_TARGET"));
project->values(ProKey("QMAKE_PBX_TARGET_ATTRIBUTES_" + testTargetKey)).append(ProKey(testTargetID));
}
//DEBUG/RELEASE
QString defaultConfig;
for(int as_release = 0; as_release < 2; as_release++)
@@ -1356,6 +1408,10 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QMap<QString, QString> settings;
settings.insert("COPY_PHASE_STRIP", (as_release ? "YES" : "NO"));
// Bitcode is only supported with a deployment target >= iOS 6.0.
// Disable it for now, and consider switching it on when later
// bumping the deployment target.
settings.insert("ENABLE_BITCODE", "NO");
settings.insert("GCC_GENERATE_DEBUGGING_SYMBOLS", as_release ? "NO" : "YES");
if(!as_release)
settings.insert("GCC_OPTIMIZATION_LEVEL", "0");
@@ -1367,14 +1423,14 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
ProString name = l.at(i);
const ProKey buildKey(name + ".build");
if (!project->isEmpty(buildKey)) {
const QString build = project->values(buildKey).first().toQString();
const QString build = project->first(buildKey).toQString();
if (build.toLower() != configName.toLower())
continue;
}
const QString value = project->values(ProKey(name + ".value")).join(QString(Option::field_sep));
const ProKey nkey(name + ".name");
if (!project->isEmpty(nkey))
name = project->values(nkey).first();
name = project->first(nkey);
settings.insert(name.toQString(), value);
}
}
@@ -1384,7 +1440,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
ProString lib = project->first("QMAKE_ORIG_TARGET");
if (!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib"))
lib.prepend("lib");
settings.insert("PRODUCT_NAME", escapeFilePath(lib.toQString()));
settings.insert("PRODUCT_NAME", lib.toQString());
}
if (project->isActiveConfig("debug") != (bool)as_release)
@@ -1415,10 +1471,10 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
if ((project->first("TEMPLATE") == "app" && project->isActiveConfig("app_bundle")) ||
(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
project->isActiveConfig("lib_bundle"))) {
QString plist = fileFixify(project->first("QMAKE_INFO_PLIST").toQString(), Option::output_dir, input_dir);
QString plist = fileFixify(project->first("QMAKE_INFO_PLIST").toQString(), FileFixifyToIndir);
if (!plist.isEmpty()) {
if (exists(plist))
t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", plist) << ";\n";
t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", fileFixify(plist)) << ";\n";
else
warn_msg(WarnLogic, "Could not resolve Info.plist: '%s'. Check if QMAKE_INFO_PLIST points to a valid file.", plist.toLatin1().constData());
} else {
@@ -1427,30 +1483,29 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
if (plist_in_file.open(QIODevice::ReadOnly)) {
QTextStream plist_in(&plist_in_file);
QString plist_in_text = plist_in.readAll();
plist_in_text = plist_in_text.replace("@ICON@",
plist_in_text.replace("@ICON@",
(project->isEmpty("ICON") ? QString("") : project->first("ICON").toQString().section(Option::dir_sep, -1)));
if (project->first("TEMPLATE") == "app") {
plist_in_text = plist_in_text.replace("@EXECUTABLE@", project->first("QMAKE_ORIG_TARGET").toQString());
plist_in_text.replace("@EXECUTABLE@", project->first("QMAKE_ORIG_TARGET").toQString());
} else {
plist_in_text = plist_in_text.replace("@LIBRARY@", project->first("QMAKE_ORIG_TARGET").toQString());
plist_in_text.replace("@LIBRARY@", project->first("QMAKE_ORIG_TARGET").toQString());
}
QString bundlePrefix = project->first("QMAKE_TARGET_BUNDLE_PREFIX").toQString();
if (bundlePrefix.isEmpty())
bundlePrefix = "com.yourcompany";
plist_in_text = plist_in_text.replace("@BUNDLEIDENTIFIER@", bundlePrefix + "." + QLatin1String("${PRODUCT_NAME:rfc1034identifier}"));
plist_in_text.replace("@BUNDLEIDENTIFIER@", bundlePrefix + '.' + QLatin1String("${PRODUCT_NAME:rfc1034identifier}"));
if (!project->values("VERSION").isEmpty()) {
plist_in_text = plist_in_text.replace("@SHORT_VERSION@", project->first("VER_MAJ") + "." +
project->first("VER_MIN"));
plist_in_text.replace("@SHORT_VERSION@", project->first("VER_MAJ") + "." + project->first("VER_MIN"));
}
plist_in_text = plist_in_text.replace("@TYPEINFO@",
plist_in_text.replace("@TYPEINFO@",
(project->isEmpty("QMAKE_PKGINFO_TYPEINFO")
? QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4).toQString()));
QString plist_dir;
if (!project->isEmpty("PLIST_DIR"))
plist_dir = project->first("PLIST_DIR").toQString();
QString plist_in_filename = QFileInfo(plist_in_file).fileName();
QFile plist_out_file(plist_dir + plist_in_filename);
if (plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QFile plist_out_file(Option::output_dir + "/" + plist_dir + plist_in_filename);
if (plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream plist_out(&plist_out_file);
plist_out << plist_in_text;
t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", fixForOutput(plist_dir + plist_in_filename)) << ";\n";
@@ -1459,12 +1514,12 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
}
}
t << "\t\t\t\t" << writeSettings("SYMROOT", escapeFilePath(qmake_getpwd())) << ";\n";
t << "\t\t\t\t" << writeSettings("SYMROOT", Option::output_dir) << ";\n";
if (!project->isEmpty("DESTDIR")) {
ProString dir = project->first("DESTDIR");
if (QDir::isRelativePath(dir.toQString()))
dir.prepend(qmake_getpwd() + Option::dir_sep);
dir.prepend(Option::output_dir + Option::dir_sep);
t << "\t\t\t\t" << writeSettings("INSTALL_DIR", dir) << ";\n";
}
@@ -1495,13 +1550,13 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QString var = tmp[i].toQString(), val = QString::fromLocal8Bit(qgetenv(var.toLatin1().constData()));
if (val.isEmpty() && var == "TB")
val = "/usr/bin/";
t << "\t\t\t\t" << writeSettings(var, escapeFilePath(val)) << ";\n";
t << "\t\t\t\t" << writeSettings(var, val) << ";\n";
}
if (!project->isEmpty("PRECOMPILED_HEADER")) {
t << "\t\t\t\t" << writeSettings("GCC_PRECOMPILE_PREFIX_HEADER", "YES") << ";\n"
<< "\t\t\t\t" << writeSettings("GCC_PREFIX_HEADER", escapeFilePath(project->first("PRECOMPILED_HEADER"))) << ";\n";
<< "\t\t\t\t" << writeSettings("GCC_PREFIX_HEADER", project->first("PRECOMPILED_HEADER")) << ";\n";
}
t << "\t\t\t\t" << writeSettings("HEADER_SEARCH_PATHS", fixListForOutput("INCLUDEPATH") + ProStringList(fixForOutput(specdir())), SettingsAsList, 5) << ";\n"
t << "\t\t\t\t" << writeSettings("HEADER_SEARCH_PATHS", fixListForOutput("INCLUDEPATH"), SettingsAsList, 5) << ";\n"
<< "\t\t\t\t" << writeSettings("LIBRARY_SEARCH_PATHS", fixListForOutput("QMAKE_PBX_LIBPATHS"), SettingsAsList, 5) << ";\n"
<< "\t\t\t\t" << writeSettings("FRAMEWORK_SEARCH_PATHS", fixListForOutput("QMAKE_FRAMEWORKPATH"),
!project->values("QMAKE_FRAMEWORKPATH").isEmpty() ? SettingsAsList : 0, 5) << ";\n";
@@ -1530,8 +1585,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
t << "\t\t\t\t" << writeSettings("OTHER_LDFLAGS",
fixListForOutput("SUBLIBS")
+ fixListForOutput("QMAKE_LFLAGS")
+ fixListForOutput("QMAKE_LIBS")
+ fixListForOutput("QMAKE_LIBS_PRIVATE"),
+ fixListForOutput(fixLibFlags("QMAKE_LIBS"))
+ fixListForOutput(fixLibFlags("QMAKE_LIBS_PRIVATE")),
SettingsAsList, 6) << ";\n";
}
const ProStringList &archs = !project->values("QMAKE_XCODE_ARCHS").isEmpty() ?
@@ -1539,7 +1594,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
if (!archs.isEmpty())
t << "\t\t\t\t" << writeSettings("ARCHS", archs) << ";\n";
if (!project->isEmpty("OBJECTS_DIR"))
t << "\t\t\t\t" << writeSettings("OBJROOT", escapeFilePath(project->first("OBJECTS_DIR").toQString())) << ";\n";
t << "\t\t\t\t" << writeSettings("OBJROOT", project->first("OBJECTS_DIR")) << ";\n";
} else {
if (project->first("TEMPLATE") == "app") {
t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", fixForOutput(project->first("QMAKE_ORIG_TARGET").toQString())) << ";\n";
@@ -1551,7 +1606,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
ProString lib = project->first("QMAKE_ORIG_TARGET");
if (!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib"))
lib.prepend("lib");
t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", escapeFilePath(lib)) << ";\n";
t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", lib) << ";\n";
}
}
t << "\t\t\t};\n"
@@ -1578,6 +1633,19 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
t << "\t\t\t" << writeSettings("projectDirPath", ProStringList()) << ";\n"
<< "\t\t\t" << writeSettings("projectRoot", "") << ";\n"
<< "\t\t\t" << writeSettings("targets", project->values("QMAKE_PBX_TARGETS"), SettingsAsList, 4) << ";\n"
<< "\t\t\t" << "attributes = {\n"
<< "\t\t\t\tTargetAttributes = {\n";
foreach (const ProString &target, project->values("QMAKE_PBX_TARGETS")) {
const ProStringList &attributes = project->values(ProKey("QMAKE_PBX_TARGET_ATTRIBUTES_" + target));
if (attributes.isEmpty())
continue;
t << "\t\t\t\t\t" << target << " = {\n";
foreach (const ProString &attribute, attributes)
t << "\t\t\t\t\t\t" << writeSettings(attribute.toQString(), project->first(ProKey("QMAKE_PBX_TARGET_ATTRIBUTES_" + target + "_" + attribute))) << ";\n";
t << "\t\t\t\t\t};\n";
}
t << "\t\t\t\t};\n"
<< "\t\t\t};\n"
<< "\t\t};\n";
// FIXME: Deal with developmentRegion and knownRegions for QMAKE_PBX_ROOT
@@ -1588,8 +1656,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
<< "}\n";
if(project->isActiveConfig("generate_pbxbuild_makefile")) {
QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
qmake_getpwd());
QString mkwrap = Option::output_dir + project->first("/MAKEFILE");
QFile mkwrapf(mkwrap);
if(mkwrapf.open(QIODevice::WriteOnly | QIODevice::Text)) {
writingUnixMakefileGenerator = true;
@@ -1597,13 +1664,14 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QTextStream mkwrapt(&mkwrapf);
writeHeader(mkwrapt);
const char cleans[] = "preprocess_clean ";
const QString cmd = escapeFilePath(project->first("QMAKE_ORIG_TARGET") + projectSuffix() + "/") + " && " + pbxbuild();
mkwrapt << "#This is a makefile wrapper for PROJECT BUILDER\n"
<< "all:\n\t"
<< "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << "\n"
<< "cd " << cmd << "\n"
<< "install: all\n\t"
<< "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " install\n"
<< "cd " << cmd << " install\n"
<< "distclean clean: preprocess_clean\n\t"
<< "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " clean\n"
<< "cd " << cmd << " clean\n"
<< (!did_preprocess ? cleans : "") << ":\n";
if(did_preprocess)
mkwrapt << cleans << ":\n\t"
@@ -1613,7 +1681,52 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
}
}
qmake_setpwd(input_dir);
// Scheme
{
QString xcodeSpecDir = project->first("QMAKE_XCODE_SPECDIR").toQString();
bool wroteCustomScheme = false;
QString projectSharedSchemesPath = pbx_dir + "/xcshareddata/xcschemes";
if (mkdir(projectSharedSchemesPath)) {
QString target = project->first("QMAKE_ORIG_TARGET").toQString();
QFile defaultSchemeFile(xcodeSpecDir + "/default.xcscheme");
QFile outputSchemeFile(projectSharedSchemesPath + Option::dir_sep + target + ".xcscheme");
if (defaultSchemeFile.open(QIODevice::ReadOnly)
&& outputSchemeFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream defaultSchemeStream(&defaultSchemeFile);
QString schemeData = defaultSchemeStream.readAll();
schemeData.replace("@QMAKE_ORIG_TARGET@", target);
schemeData.replace("@TARGET_PBX_KEY@", keyFor(pbx_dir + "QMAKE_PBX_TARGET"));
schemeData.replace("@TEST_BUNDLE_PBX_KEY@", keyFor("QMAKE_TEST_BUNDLE_REFERENCE"));
QTextStream outputSchemeStream(&outputSchemeFile);
outputSchemeStream << schemeData;
wroteCustomScheme = true;
}
}
if (wroteCustomScheme) {
// Prevent Xcode from auto-generating schemes
QString workspaceSettingsFilename("WorkspaceSettings.xcsettings");
QString workspaceSharedDataPath = pbx_dir + "/project.xcworkspace/xcshareddata";
if (mkdir(workspaceSharedDataPath)) {
QFile::copy(xcodeSpecDir + Option::dir_sep + workspaceSettingsFilename,
workspaceSharedDataPath + Option::dir_sep + workspaceSettingsFilename);
} else {
wroteCustomScheme = false;
}
}
if (!wroteCustomScheme)
warn_msg(WarnLogic, "Failed to generate schemes in '%s', " \
"falling back to Xcode auto-generated schemes", qPrintable(projectSharedSchemesPath));
}
return true;
}
@@ -1703,13 +1816,15 @@ ProjectBuilderMakefileGenerator::openOutput(QFile &file, const QString &build) c
output += QDir::separator();
}
output += QString("project.pbxproj");
output = unescapeFilePath(output);
file.setFileName(output);
bool ret = UnixMakefileGenerator::openOutput(file, build);
((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1);
Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2);
return ret;
}
bool ret = UnixMakefileGenerator::openOutput(file, build);
((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1);
Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2);
return ret;
((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir;
return UnixMakefileGenerator::openOutput(file, build);
}
/* This function is such a hack it is almost pointless, but it
@@ -1760,8 +1875,6 @@ ProjectBuilderMakefileGenerator::pbuilderVersion() const
else
version_plist = "/Developer/Applications/Project Builder.app/Contents/version.plist";
#endif
} else {
version_plist = version_plist.replace(QRegExp("\""), "");
}
if (ret.isEmpty()) {
QFile version_file(version_plist);
@@ -1822,7 +1935,7 @@ int
ProjectBuilderMakefileGenerator::reftypeForFile(const QString &where)
{
int ret = 0; //absolute is the default..
if(QDir::isRelativePath(unescapeFilePath(where)))
if (QDir::isRelativePath(where))
ret = 4; //relative
return ret;
}
@@ -1848,26 +1961,6 @@ ProjectBuilderMakefileGenerator::pbxbuild()
return (pbuilderVersion() >= 38 ? "xcodebuild" : "pbxbuild");
}
QString
ProjectBuilderMakefileGenerator::escapeFilePath(const QString &path) const
{
#if 1
//in the middle of generating a Makefile!
if(writingUnixMakefileGenerator)
return UnixMakefileGenerator::escapeFilePath(path);
//generating stuff for the xml file!
QString ret = path;
if(!ret.isEmpty()) {
ret = unescapeFilePath(ret);
debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
}
return ret;
#else
return UnixMakefileGenerator::escapeFilePath(path);
#endif
}
static QString quotedStringLiteral(const QString &value)
{
QString result;

Some files were not shown because too many files have changed in this diff Show More